summaryrefslogtreecommitdiff
path: root/test
diff options
context:
space:
mode:
Diffstat (limited to 'test')
-rw-r--r--test/CMakeLists.txt7
-rw-r--r--test/test_common.cpp18
-rw-r--r--test/test_common.hpp43
-rw-r--r--test/test_deserialize_number.cpp503
-rw-r--r--test/test_result.cpp2
-rw-r--r--test/test_string.cpp296
6 files changed, 866 insertions, 3 deletions
diff --git a/test/CMakeLists.txt b/test/CMakeLists.txt
index 9bd9e87..dc48e1f 100644
--- a/test/CMakeLists.txt
+++ b/test/CMakeLists.txt
@@ -33,9 +33,9 @@ function(fud_add_test test_name)
add_executable(${test_name} test_common.cpp ${FUD_ADD_TEST_SOURCES})
- target_include_directories(${test_name} PUBLIC $<TARGET_PROPERTY:libfud>)
+ target_include_directories(${test_name} PUBLIC $<TARGET_PROPERTY:fud>)
- target_link_libraries(${test_name} PUBLIC GTest::gtest_main libfud)
+ target_link_libraries(${test_name} PUBLIC GTest::gtest_main fud)
target_compile_options(${test_name} PRIVATE ${CVG_FLAGS})
target_link_options(${test_name} PRIVATE ${CVG_FLAGS})
@@ -52,6 +52,8 @@ function(fud_add_test test_name)
endfunction()
fud_add_test(test_result SOURCES test_result.cpp)
+fud_add_test(test_string SOURCES test_string.cpp)
+# fud_add_test(test_deserialize_number SOURCES test_deserialize_number.cpp)
# fud_add_test(test_ext_algorithm SOURCES test_algorithm.cpp)
# fud_add_test(test_ext_array SOURCES
# test_ext_array.cpp
@@ -64,3 +66,4 @@ fud_add_test(test_result SOURCES test_result.cpp)
# fud_add_test(test_ext_string_format SOURCES
# test_ext_string_format.cpp)
+# fud_add_test(test_c_file SOURCES test_c_file.cpp)
diff --git a/test/test_common.cpp b/test/test_common.cpp
index a03c8db..fc37566 100644
--- a/test/test_common.cpp
+++ b/test/test_common.cpp
@@ -1,3 +1,21 @@
+/*
+ * libfud
+ * Copyright 2024 Dominick Allen
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "test_common.hpp"
#include "fud_memory.hpp"
#include <cstdlib>
diff --git a/test/test_common.hpp b/test/test_common.hpp
new file mode 100644
index 0000000..fa6cf09
--- /dev/null
+++ b/test/test_common.hpp
@@ -0,0 +1,43 @@
+/*
+ * libfud
+ * Copyright 2024 Dominick Allen
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef EXT_TEST_COMMON_HPP
+#define EXT_TEST_COMMON_HPP
+
+#include <cstddef>
+#include <cstdlib>
+
+namespace ext_lib {
+
+// NOLINTBEGIN(cppcoreguidelines-macro-usage)
+#define MULTI_BYTE_LITERAL "test今日素敵はですねƩ®😀z"
+static_assert(sizeof(MULTI_BYTE_LITERAL) == 38); // NOLINT(readability-magic-numbers)
+#define TWO_BYTE "Ʃ"
+static_assert(sizeof(TWO_BYTE) == 2 + 1);
+#define THREE_BYTE "今"
+static_assert(sizeof(THREE_BYTE) == 3 + 1);
+#define FOUR_BYTE "😀"
+static_assert(sizeof(FOUR_BYTE) == 4 + 1);
+
+#define CHQUOTE "why waste time learning, when ignorance is instantaneous?"
+#define CHARACTER_SET "abcdefghijklmnopqrstuvwxyz ABCDEFGHIJKLMNOPQRSTUVWXYZ"
+// NOLINTEND(cppcoreguidelines-macro-usage)
+constexpr size_t charSetSize = sizeof(CHARACTER_SET) - 1;
+
+} // namespace ext_lib
+
+#endif
diff --git a/test/test_deserialize_number.cpp b/test/test_deserialize_number.cpp
new file mode 100644
index 0000000..6b3f85c
--- /dev/null
+++ b/test/test_deserialize_number.cpp
@@ -0,0 +1,503 @@
+/*
+ * libfud
+ * Copyright 2024 Dominick Allen
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "fud_array.hpp"
+#include "fud_string.hpp"
+
+#include "gtest/gtest.h"
+
+namespace fud {
+
+template <typename T, typename Func>
+auto testStringToIntegerInvalid(Func&& func)
+{
+ Array<uint8_t, sizeof("7 13 42 0 08 010 0x08")> backing{"7 13 42 0 08 010 0x08"};
+ FudString extString{FudString::withBacking(backing)};
+ StringView view{extString};
+ StringView invalidView{extString};
+ T number = 0;
+ ASSERT_EQ(std::forward<Func>(func)(view, nullptr, 0, nullptr), ExtNullPointer);
+
+ invalidView.data = nullptr;
+ ASSERT_EQ(std::forward<Func>(func)(invalidView, &number, 1, nullptr), ExtNullPointer);
+ invalidView.data = view.data;
+
+ invalidView.length = 0;
+ ASSERT_EQ(std::forward<Func>(func)(invalidView, &number, 0, nullptr), ExtInvalidInput);
+ ASSERT_EQ(std::forward<Func>(func)(view, &number, 1, nullptr), ExtInvalidInput);
+ ASSERT_EQ(std::forward<Func>(func)(view, &number, UINT8_MAX, nullptr), ExtInvalidInput);
+}
+
+template <typename T, size_t BackingSize, size_t WordCount, typename Func>
+auto testStringToNumber(
+ Array<uint8_t, BackingSize>& backing,
+ const Array<size_t, WordCount>& wordSizes,
+ const Array<ExtStatus, WordCount>& statuses,
+ const Array<T, WordCount>& expectedValues,
+ Func&& func,
+ uint8_t radix)
+{
+ FudString extString{FudString::withBacking(backing)};
+ StringView view{extString};
+ T number = 0;
+
+ ASSERT_EQ(std::forward<Func>(func)(view, &number, radix, nullptr), statuses[0]);
+ ASSERT_EQ(number, expectedValues[0]);
+
+ size_t index = 0;
+ for (size_t idx = 0; idx < WordCount; ++idx) {
+
+ T tempNumber{};
+ if (std::forward<Func>(func)(view, &tempNumber, radix, &index) != statuses[idx]) {
+ printf(
+ "どうして? \"%s\" %ld %zu %ld\n",
+ view.data,
+ static_cast<int64_t>(expectedValues[idx]),
+ idx,
+ static_cast<int64_t>(tempNumber));
+ if (idx > 0) {
+ printf("Test: \"%s\"\n", view.data - index);
+ }
+ }
+ EXPECT_EQ(std::forward<Func>(func)(view, &number, radix, &index), statuses[idx]);
+ if (statuses[idx] == ExtSuccess) {
+ ASSERT_EQ(number, expectedValues[idx]);
+ ASSERT_EQ(index, wordSizes[idx]);
+ }
+
+ view.data += wordSizes[idx];
+ view.length -= wordSizes[idx];
+ }
+}
+
+TEST(FudString, StringToUint8Invalid)
+{
+ testStringToIntegerInvalid<uint8_t>(ext_string_to_uint8);
+}
+
+TEST(FudString, StringToUint8RadixUnspec)
+{
+ Array<uint8_t, sizeof("7 13 42 0 018 010 0xFF 0xFF0 256")> backing{"7 13 42 0 018 010 0xFF 0xFF0 256"};
+ constexpr Array<size_t, 10> wordSizes{
+ sizeof("7") - 1,
+ sizeof(" 13") - 1,
+ sizeof(" 42") - 1,
+ sizeof(" 0") - 1,
+ sizeof(" 01") - 1,
+ sizeof("8") - 1,
+ sizeof(" 010") - 1,
+ sizeof(" 0xFF") - 1,
+ sizeof(" 0xFF0") - 1,
+ sizeof(" 256") - 1};
+ constexpr Array<uint8_t, 10> expectedValues{7, 13, 42, 0, 1, 8, 8, 0xFF, 0, 0};
+ constexpr Array<ExtStatus, 10> statuses{
+ ExtSuccess,
+ ExtSuccess,
+ ExtSuccess,
+ ExtSuccess,
+ ExtSuccess,
+ ExtSuccess,
+ ExtSuccess,
+ ExtSuccess,
+ ExtInvalidInput,
+ ExtInvalidInput};
+ testStringToNumber(backing, wordSizes, statuses, expectedValues, ext_string_to_uint8, 0);
+}
+
+TEST(FudString, StringToUint8Octal)
+{
+ Array<uint8_t, sizeof("7 13 42 0 018 010 377 0xFF0")> backing{"7 13 42 0 018 010 377 0xFF0"};
+ constexpr Array<uint8_t, 10> expectedValues{7, 8 + 3, 8 * 4 + 2, 0, 1, 0, 8, 255, 0, 0};
+ constexpr Array<size_t, 10> wordSizes{
+ sizeof("7") - 1,
+ sizeof(" 13") - 1,
+ sizeof(" 42") - 1,
+ sizeof(" 0") - 1,
+ sizeof(" 01") - 1,
+ sizeof("8") - 1,
+ sizeof(" 010") - 1,
+ sizeof(" 377") - 1,
+ sizeof(" 0") - 1,
+ sizeof("xFF0") - 1};
+ constexpr Array<ExtStatus, 10> statuses{
+ ExtSuccess,
+ ExtSuccess,
+ ExtSuccess,
+ ExtSuccess,
+ ExtSuccess,
+ ExtInvalidInput,
+ ExtSuccess,
+ ExtSuccess,
+ ExtSuccess,
+ ExtInvalidInput};
+ testStringToNumber(backing, wordSizes, statuses, expectedValues, ext_string_to_uint8, ExtRadixOctal);
+}
+
+TEST(FudString, StringToUint8Hex)
+{
+ Array<uint8_t, sizeof("7 13 0x42 0 018 010 FF 0xFF0")> backing{"7 13 0x42 0 018 010 FF 0xFF0"};
+ constexpr Array<uint8_t, 8> expectedValues{7, 16 + 3, 16 * 4 + 2, 0, 16 + 8, 16, 255, 0};
+ constexpr Array<size_t, 8> wordSizes{
+ sizeof("7") - 1,
+ sizeof(" 13") - 1,
+ sizeof(" 0x42") - 1,
+ sizeof(" 0") - 1,
+ sizeof(" 018") - 1,
+ sizeof(" 010") - 1,
+ sizeof(" FF") - 1,
+ sizeof(" 0xFF0") - 1};
+ constexpr Array<ExtStatus, 8>
+ statuses{ExtSuccess, ExtSuccess, ExtSuccess, ExtSuccess, ExtSuccess, ExtSuccess, ExtSuccess, ExtInvalidInput};
+ testStringToNumber(backing, wordSizes, statuses, expectedValues, ext_string_to_uint8, ExtRadixHexadecimal);
+}
+
+TEST(FudString, StringToUint16Invalid)
+{
+ testStringToIntegerInvalid<uint16_t>(ext_string_to_uint16);
+}
+
+TEST(FudString, StringToUint16RadixUnspec)
+{
+ Array<uint8_t, sizeof("7 65535 0x42 0 010 0xFFFF 0xFFFF0")> backing{
+ "7 65535 0x42 0 010 0xFFFF 0xFFFF0"};
+ constexpr Array<uint16_t, 7> expectedValues{7, 0xFFFF, 0x42, 0, 8, 0xFFFF, 0};
+ constexpr Array<size_t, 7> wordSizes{
+ sizeof("7") - 1,
+ sizeof(" 65535") - 1,
+ sizeof(" 0x42") - 1,
+ sizeof(" 0") - 1,
+ sizeof(" 010") - 1,
+ sizeof(" 0xFFFF") - 1,
+ sizeof(" 0xFFFF0") - 1};
+ constexpr Array<ExtStatus, 7> statuses{
+ ExtSuccess,
+ ExtSuccess,
+ ExtSuccess,
+ ExtSuccess,
+ ExtSuccess,
+ ExtSuccess,
+ ExtInvalidInput};
+ testStringToNumber(backing, wordSizes, statuses, expectedValues, ext_string_to_uint16, 0);
+}
+
+TEST(FudString, StringToUint16Octal)
+{
+ Array<uint8_t, sizeof("7 13 42 0 010 177777 200000")> backing{"7 13 42 0 010 177777 200000"};
+ constexpr Array<uint16_t, 7> expectedValues{7, 8 + 3, 8 * 4 + 2, 0, 8, 0xFFFF, 0};
+ constexpr Array<size_t, 7> wordSizes{
+ sizeof("7") - 1,
+ sizeof(" 13") - 1,
+ sizeof(" 42") - 1,
+ sizeof(" 0") - 1,
+ sizeof(" 010") - 1,
+ sizeof(" 177777") - 1,
+ sizeof(" 200000") - 1};
+ constexpr Array<ExtStatus, 7> statuses{
+ ExtSuccess,
+ ExtSuccess,
+ ExtSuccess,
+ ExtSuccess,
+ ExtSuccess,
+ ExtSuccess,
+ ExtInvalidInput};
+ testStringToNumber(backing, wordSizes, statuses, expectedValues, ext_string_to_uint16, ExtRadixOctal);
+}
+
+TEST(FudString, StringToUint16Hex)
+{
+ Array<uint8_t, sizeof("7 13 0x42 0 018 010 FFFF 0x10000")> backing{"7 13 0x42 0 018 010 FFFF 0x10000"};
+ constexpr Array<uint16_t, 8> expectedValues{7, 16 + 3, 16 * 4 + 2, 0, 16 + 8, 16, 0xFFFF, 0};
+ constexpr Array<size_t, 8> wordSizes{
+ sizeof("7") - 1,
+ sizeof(" 13") - 1,
+ sizeof(" 0x42") - 1,
+ sizeof(" 0") - 1,
+ sizeof(" 018") - 1,
+ sizeof(" 010") - 1,
+ sizeof(" FFFF") - 1,
+ sizeof(" 200000") - 1};
+ constexpr Array<ExtStatus, 8>
+ statuses{ExtSuccess, ExtSuccess, ExtSuccess, ExtSuccess, ExtSuccess, ExtSuccess, ExtSuccess, ExtInvalidInput};
+ testStringToNumber(backing, wordSizes, statuses, expectedValues, ext_string_to_uint16, ExtRadixHexadecimal);
+}
+
+TEST(FudString, StringToUint64Hex)
+{
+ Array<uint8_t, sizeof("7 13 0x7FFFFFFFFFFFFFFF 0 018 010 -8000000000000000 0xFFFFFFFFFFFFFFFF -8000000000000001")>
+ backing{"7 13 0x7FFFFFFFFFFFFFFF 0 018 010 -8000000000000000 0xFFFFFFFFFFFFFFFF -8000000000000001"};
+ constexpr Array<uint64_t, 9> expectedValues{
+ 7,
+ 16 + 3,
+ std::numeric_limits<int64_t>::max(),
+ 0,
+ 16 + 8,
+ 16,
+ 0,
+ std::numeric_limits<uint64_t>::max(),
+ 0};
+ constexpr Array<size_t, 9> wordSizes{
+ sizeof("7") - 1,
+ sizeof(" 13") - 1,
+ sizeof(" 0x7FFFFFFFFFFFFFFF") - 1,
+ sizeof(" 0") - 1,
+ sizeof(" 018") - 1,
+ sizeof(" 010") - 1,
+ sizeof(" -8000000000000000") - 1,
+ sizeof(" 0xFFFFFFFFFFFFFFFF") - 1,
+ sizeof(" -8000000000000001") - 1};
+ constexpr Array<ExtStatus, 9> statuses{
+ ExtSuccess,
+ ExtSuccess,
+ ExtSuccess,
+ ExtSuccess,
+ ExtSuccess,
+ ExtSuccess,
+ ExtInvalidInput,
+ ExtSuccess,
+ ExtInvalidInput};
+ testStringToNumber(backing, wordSizes, statuses, expectedValues, ext_string_to_uint64, ExtRadixHexadecimal);
+}
+
+TEST(FudString, StringToInt8Invalid)
+{
+ testStringToIntegerInvalid<int8_t>(ext_string_to_int8);
+}
+
+TEST(FudString, StringToInt8RadixUnspec)
+{
+ Array<uint8_t, sizeof("7 13 127 0 018 010 -0x80 0x80")> backing{"7 13 127 0 018 010 -0x80 0x80"};
+ constexpr Array<int8_t, 8> expectedValues{7, 13, 127, 0, 0, 8, -0x80, 0};
+ constexpr Array<size_t, 8> wordSizes{
+ sizeof("7") - 1,
+ sizeof(" 13") - 1,
+ sizeof(" 127") - 1,
+ sizeof(" 0") - 1,
+ sizeof(" 018") - 1,
+ sizeof(" 010") - 1,
+ sizeof(" -0x80") - 1,
+ sizeof(" 0x80") - 1};
+ constexpr Array<ExtStatus, 8> statuses{
+ ExtSuccess,
+ ExtSuccess,
+ ExtSuccess,
+ ExtSuccess,
+ ExtInvalidInput,
+ ExtSuccess,
+ ExtSuccess,
+ ExtInvalidInput};
+ testStringToNumber(backing, wordSizes, statuses, expectedValues, ext_string_to_int8, 0);
+}
+
+TEST(FudString, StringToInt8Octal)
+{
+ Array<uint8_t, sizeof("7 13 177 0 018 010 -200 0xFF0 -201")> backing{"7 13 177 0 018 010 -200 0xFF0 -201"};
+ constexpr Array<int8_t, 9> expectedValues{7, 8 + 3, 127, 0, 0, 8, -128, 0};
+ constexpr Array<size_t, 9> wordSizes{
+ sizeof("7") - 1,
+ sizeof(" 13") - 1,
+ sizeof(" 177") - 1,
+ sizeof(" 0") - 1,
+ sizeof(" 018") - 1,
+ sizeof(" 010") - 1,
+ sizeof(" -200") - 1,
+ sizeof(" 0xFF0") - 1,
+ sizeof(" -201") - 1};
+ constexpr Array<ExtStatus, 9> statuses{
+ ExtSuccess,
+ ExtSuccess,
+ ExtSuccess,
+ ExtSuccess,
+ ExtInvalidInput,
+ ExtSuccess,
+ ExtSuccess,
+ ExtInvalidInput,
+ ExtInvalidInput};
+ testStringToNumber(backing, wordSizes, statuses, expectedValues, ext_string_to_int8, ExtRadixOctal);
+}
+
+TEST(FudString, StringToInt8Hex)
+{
+ Array<uint8_t, sizeof("7 13 0x7F 0 018 010 -80 0xFF0")> backing{"7 13 0x7F 0 018 010 -80 0xFF0"};
+ constexpr Array<int8_t, 8> expectedValues{7, 16 + 3, 127, 0, 16 + 8, 16, -128, 0};
+ constexpr Array<size_t, 8> wordSizes{
+ sizeof("7") - 1,
+ sizeof(" 13") - 1,
+ sizeof(" 0x7F") - 1,
+ sizeof(" 0") - 1,
+ sizeof(" 018") - 1,
+ sizeof(" 010") - 1,
+ sizeof(" -80") - 1,
+ sizeof(" 0xFF0") - 1};
+ constexpr Array<ExtStatus, 8>
+ statuses{ExtSuccess, ExtSuccess, ExtSuccess, ExtSuccess, ExtSuccess, ExtSuccess, ExtSuccess, ExtInvalidInput};
+ testStringToNumber(backing, wordSizes, statuses, expectedValues, ext_string_to_int8, ExtRadixHexadecimal);
+}
+
+TEST(FudString, StringToInt32Decimal)
+{
+ Array<uint8_t, sizeof("01 13 0x7F 0 018 010 -80 0xFF0")> backing{"01 13 0x7F 0 018 010 -80 0xFF0"};
+ constexpr Array<int8_t, 8> expectedValues{1, 13, 0, 0, 18, 10, -80, 0};
+ constexpr Array<size_t, 8> wordSizes{
+ sizeof("01") - 1,
+ sizeof(" 13") - 1,
+ sizeof(" 0x7F") - 1,
+ sizeof(" 0") - 1,
+ sizeof(" 018") - 1,
+ sizeof(" 010") - 1,
+ sizeof(" -80") - 1,
+ sizeof(" 0xFF0") - 1};
+ constexpr Array<ExtStatus, 8>
+ statuses{ExtSuccess, ExtSuccess, ExtInvalidInput, ExtSuccess, ExtSuccess, ExtSuccess, ExtSuccess, ExtInvalidInput};
+ testStringToNumber(backing, wordSizes, statuses, expectedValues, ext_string_to_int8, ExtRadixDecimal);
+}
+
+TEST(FudString, StringToInt64Hex)
+{
+ Array<uint8_t, sizeof("+7 13 0x7FFFFFFFFFFFFFFF 0 018 010 -8000000000000000 0x8000000000000000 -8000000000000001")>
+ backing{"+7 13 0x7FFFFFFFFFFFFFFF 0 018 010 -8000000000000000 0x8000000000000000 -8000000000000001"};
+ constexpr Array<int64_t, 9> expectedValues{
+ 7,
+ 16 + 3,
+ std::numeric_limits<int64_t>::max(),
+ 0,
+ 16 + 8,
+ 16,
+ std::numeric_limits<int64_t>::min(),
+ 0,
+ 0};
+ constexpr Array<size_t, 9> wordSizes{
+ sizeof("+7") - 1,
+ sizeof(" 13") - 1,
+ sizeof(" 0x7FFFFFFFFFFFFFFF") - 1,
+ sizeof(" 0") - 1,
+ sizeof(" 018") - 1,
+ sizeof(" 010") - 1,
+ sizeof(" -8000000000000000") - 1,
+ sizeof(" 0x8000000000000000") - 1,
+ sizeof(" -8000000000000001") - 1};
+ constexpr Array<ExtStatus, 9> statuses{
+ ExtSuccess,
+ ExtSuccess,
+ ExtSuccess,
+ ExtSuccess,
+ ExtSuccess,
+ ExtSuccess,
+ ExtSuccess,
+ ExtInvalidInput,
+ ExtInvalidInput};
+ testStringToNumber(backing, wordSizes, statuses, expectedValues, ext_string_to_int64, ExtRadixHexadecimal);
+}
+
+template <typename T>
+struct TestStringToFloatParams {
+ T value{0.0};
+ size_t wordSize{0};
+ ExtStatus status{ExtInvalidInput};
+ bool isNaN{false};
+};
+
+template <typename T, size_t BackingSize, size_t WordCount, typename Func>
+auto testStringToFloat(
+ Array<uint8_t, BackingSize>& backing,
+ const Array<TestStringToFloatParams<T>, WordCount>& testParams,
+ Func&& func)
+{
+ FudString extString{FudString::withBacking(backing)};
+ StringView view{extString};
+ T number = 0;
+
+ ASSERT_EQ(std::forward<Func>(func)(view, &number, nullptr), testParams[0].status);
+ ASSERT_EQ(number, testParams[0].value);
+
+ size_t index = 0;
+ for (size_t idx = 0; idx < WordCount; ++idx) {
+ ASSERT_EQ(std::forward<Func>(func)(view, &number, &index), testParams[idx].status);
+ if (testParams[idx].status == ExtSuccess) {
+ if (!testParams[idx].isNaN) {
+ ASSERT_EQ(number, testParams[idx].value);
+ } else {
+ ASSERT_NE(number, number);
+ }
+ ASSERT_EQ(index, testParams[idx].wordSize);
+ }
+
+ view.data += testParams[idx].wordSize;
+ view.length -= testParams[idx].wordSize;
+ }
+}
+
+TEST(FudString, StringToFloat)
+{
+ Array<uint8_t, sizeof("123 -7 123.5 .25 0.25 -.125 -2.0625 NaN -inf inF")> backing{
+ "123 -7 123.5 .25 0.25 -.125 -2.0625 NaN -inf inF"};
+ /* N.B. In the following expressions, sizeof includes null, but excludes one leading space. */
+ constexpr Array<TestStringToFloatParams<float>, 10> testParams{
+ {{123.0, sizeof("123") - 1, ExtSuccess},
+ {-7.0, sizeof("-7"), ExtSuccess},
+ {123.5, sizeof("123.5"), ExtSuccess},
+ {.25, sizeof(".25"), ExtSuccess},
+ {.25, sizeof("0.25"), ExtSuccess},
+ {-.125, sizeof("-.125"), ExtSuccess},
+ {-2.0625, sizeof("-2.0625"), ExtSuccess},
+ {std::numeric_limits<float>::quiet_NaN(), sizeof("NaN"), ExtSuccess, true},
+ {-1.0F * std::numeric_limits<float>::infinity(), sizeof("-inf"), ExtSuccess},
+ {std::numeric_limits<float>::infinity(), sizeof("inF"), ExtSuccess}}};
+
+ testStringToFloat(backing, testParams, ext_string_to_float);
+}
+
+TEST(FudString, StringToDouble)
+{
+ Array<uint8_t, sizeof("123 -7 123.5 .25 0.25 -.125 -2.0625 NaN -inf inF")> backing{
+ "123 -7 123.5 .25 0.25 -.125 -2.0625 NaN -inf inF"};
+ /* N.B. In the following expressions, sizeof includes null, but excludes one leading space. */
+ constexpr Array<TestStringToFloatParams<double>, 10> testParams{
+ {{123.0, sizeof("123") - 1, ExtSuccess},
+ {-7.0, sizeof("-7"), ExtSuccess},
+ {123.5, sizeof("123.5"), ExtSuccess},
+ {.25, sizeof(".25"), ExtSuccess},
+ {.25, sizeof("0.25"), ExtSuccess},
+ {-.125, sizeof("-.125"), ExtSuccess},
+ {-2.0625, sizeof("-2.0625"), ExtSuccess},
+ {std::numeric_limits<double>::quiet_NaN(), sizeof("NaN"), ExtSuccess, true},
+ {-1.0 * std::numeric_limits<double>::infinity(), sizeof("-inf"), ExtSuccess},
+ {std::numeric_limits<double>::infinity(), sizeof("inF"), ExtSuccess}}};
+
+ testStringToFloat(backing, testParams, ext_string_to_double);
+}
+
+TEST(FudString, StringToDoubleExpt)
+{
+ Array<uint8_t, sizeof("1.25e01 1.25e+01 0.125e2 12.5e0 125.e-1 125e-1 1250.e-02 1250.0e-02")> backing{
+ "1.25e01 1.25e+01 0.125e2 12.5e0 125.e-1 125e-1 1250.e-02 1250.0e-02"};
+ /* N.B. In the following expressions, sizeof includes null, but excludes one leading space. */
+ constexpr Array<TestStringToFloatParams<double>, 8> testParams{
+ {{12.5, sizeof("1.25e01") - 1, ExtSuccess},
+ {12.5, sizeof("1.25e+01"), ExtSuccess},
+ {12.5, sizeof("0.125e2"), ExtSuccess},
+ {12.5, sizeof("12.5e0"), ExtSuccess},
+ {12.5, sizeof("125.e-1"), ExtSuccess},
+ {12.5, sizeof("125e-1"), ExtSuccess},
+ {12.5, sizeof("1250.e-02"), ExtSuccess},
+ {12.5, sizeof("1250.0e-02"), ExtSuccess}
+ }};
+
+ testStringToFloat(backing, testParams, ext_string_to_double);
+}
+
+
+} // namespace fud
diff --git a/test/test_result.cpp b/test/test_result.cpp
index d86a170..172323d 100644
--- a/test/test_result.cpp
+++ b/test/test_result.cpp
@@ -1,5 +1,5 @@
/*
- * ExtLib
+ * libfud
* Copyright 2024 Dominick Allen
*
* Licensed under the Apache License, Version 2.0 (the "License");
diff --git a/test/test_string.cpp b/test/test_string.cpp
new file mode 100644
index 0000000..3b8c3aa
--- /dev/null
+++ b/test/test_string.cpp
@@ -0,0 +1,296 @@
+/*
+ * libfud
+ * Copyright 2024 Dominick Allen
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "fud_array.hpp"
+#include "fud_string.hpp"
+#include "test_common.hpp"
+
+#include "gtest/gtest.h"
+
+namespace fud {
+
+TEST(FudString, CStringLength)
+{
+ ASSERT_EQ(cStringLength(nullptr), -1);
+ ASSERT_EQ(cStringLength(""), 0);
+ ASSERT_EQ(cStringLength("a"), 1);
+ ASSERT_EQ(cStringLength(MULTI_BYTE_LITERAL), sizeof(MULTI_BYTE_LITERAL) - 1);
+ ASSERT_EQ(cStringLength(MULTI_BYTE_LITERAL), sizeof(MULTI_BYTE_LITERAL) - 1);
+}
+
+TEST(FudString, BasicStringOps)
+{
+ const Array<utf8, 2> invalid{0xFF, 0x00};
+ ASSERT_FALSE(Ascii::valid(invalid[0]));
+ const Array<utf8, 2> invalid2{0xFF, 0x00};
+ String fudString{invalid2.data()};
+ ASSERT_EQ(fudString.length(), 1);
+ ASSERT_EQ(fudString.data()[0], invalid[0]);
+ ASSERT_FALSE(Ascii::valid(fudString.data()[0]));
+ ASSERT_FALSE(fudString.utf8Valid());
+
+ fudString = String{"TEST"};
+ ASSERT_TRUE(fudString.utf8Valid());
+
+ StringView view1{};
+ ASSERT_FALSE(view1.utf8Valid());
+ StringView view2{fudString};
+ ASSERT_TRUE(view2.utf8Valid());
+ ASSERT_TRUE(view2.nullTerminated());
+}
+
+#if 0
+TEST(FudString, FindSubstringCxx)
+{
+ Array<uint8_t, sizeof(CHQUOTE)> basis{};
+ ASSERT_EQ(ExtCopyMem(basis.data(), basis.size(), CHQUOTE, sizeof(CHQUOTE)), ExtSuccess);
+ String fudString{basis.size() - 1, basis.size(), basis.data()};
+
+ StringView haystack{extString};
+ ASSERT_NE(haystack.length, 0);
+ ASSERT_NE(haystack.data, nullptr);
+
+ Array<uint8_t, sizeof("learning")> subBasis{};
+ ASSERT_EQ(ExtCopyMem(subBasis.data(), subBasis.size(), "learning", sizeof("learning")), ExtSuccess);
+ FudStringView needle{subBasis.size() - 1, subBasis.data()};
+
+ FudStringView stringView{};
+ auto findStatus = ext_string_find_substring(haystack, needle, &stringView);
+ ASSERT_EQ(findStatus, ExtSuccess);
+ // NOLINTBEGIN(cppcoreguidelines-pro-type-reinterpret-cast)
+ ASSERT_EQ(
+ ext_string_get_c_string(&extString) + sizeof("why waste time"),
+ reinterpret_cast<const char*>(stringView.data));
+ // NOLINTEND(cppcoreguidelines-pro-type-reinterpret-cast)
+}
+
+TEST(TestFudString, StringBuffer)
+{
+ Result<FixedStringBuffer<1>, ExtStatus> bufferResult{FixedStringBuffer<1>::fromLiteral(nullptr)};
+ ASSERT_TRUE(bufferResult.isError());
+ ASSERT_EQ(bufferResult.getError(), ExtNullPointer);
+
+ Array<uint8_t, 1> data1{};
+ bufferResult = FixedStringBuffer<1>::fromArray(data1);
+ ASSERT_TRUE(bufferResult.isOkay());
+ FixedStringBuffer<1> buffer1{std::move(bufferResult.getOkay())};
+ ASSERT_EQ(buffer1.m_string.m_data[0], '\0');
+ ASSERT_EQ(buffer1.m_string.m_length, 0);
+ ASSERT_EQ(buffer1.m_string.m_size, 1);
+
+ bufferResult = FixedStringBuffer<1>::fromLiteral("a");
+ ASSERT_TRUE(bufferResult.isError());
+ ASSERT_EQ(bufferResult.getError(), ExtInvalidInput);
+
+ data1[0] = 'a';
+ bufferResult = FixedStringBuffer<1>::fromArray(data1);
+ ASSERT_TRUE(bufferResult.isError());
+ ASSERT_EQ(bufferResult.getError(), ExtInvalidInput);
+
+ bufferResult = FixedStringBuffer<1>::fromLiteral("");
+ ASSERT_TRUE(bufferResult.isOkay());
+ buffer1 = {bufferResult.getOkay()};
+ ASSERT_EQ(buffer1.m_string.m_data[0], '\0');
+ ASSERT_EQ(buffer1.m_string.m_length, 0);
+ ASSERT_EQ(buffer1.m_string.m_size, 1);
+
+ StringView view1{buffer1};
+ ASSERT_EQ(buffer1.append(view1), ExtInvalidInput);
+
+ ASSERT_EQ(buffer1, buffer1);
+ const auto buffer2{buffer1};
+ ASSERT_EQ(buffer1, buffer2);
+ const auto buffer3{buffer2}; // NOLINT(performance-unnecessary-copy-initialization)
+ ASSERT_EQ(buffer1, buffer3);
+ auto buffer4 = buffer3; // NOLINT(performance-unnecessary-copy-initialization)
+ ASSERT_EQ(buffer1, buffer4);
+
+ Array<uint8_t, sizeof("test")> data2{"test"};
+ auto bufferResult2{FixedStringBuffer<data2.size()>::fromArray(data2)};
+ ASSERT_TRUE(bufferResult2.isOkay());
+ FixedStringBuffer<data2.size()> bufferTest{std::move(bufferResult2.getOkay())};
+ ASSERT_EQ(bufferTest.m_string.m_data[0], 't');
+ ASSERT_EQ(bufferTest.m_string.m_data[4], '\0');
+ ASSERT_EQ(bufferTest.m_string.m_length, data2.size() - 1);
+ ASSERT_EQ(bufferTest.m_string.m_size, data2.size());
+
+ const StringView view2{bufferTest};
+ FixedStringBuffer<data2.size()> bufferTest2{};
+ ASSERT_EQ(bufferTest2.append(view2), ExtSuccess);
+ ASSERT_EQ(bufferTest2.append(view2), ExtFull);
+ ASSERT_EQ(bufferTest2.remainingLength(), 0);
+ bufferTest2.m_string.m_length++;
+ ASSERT_EQ(bufferTest2.remainingLength(), 0);
+ bufferTest2.clear();
+ ASSERT_EQ(bufferTest2.remainingLength(), data2.size() - 1);
+
+ bufferTest2.m_string.m_length = 0;
+ bufferTest2.m_memory.clear();
+ buffer1.m_string.m_data[0] = 'a';
+ view1.length = 1;
+ ASSERT_EQ(bufferTest2.append(view1), FudStringInvalid);
+ ASSERT_TRUE(bufferTest2.m_memory.pushBack('\0'));
+ ASSERT_EQ(bufferTest2.append(view1), ExtSuccess);
+
+ ASSERT_NE(bufferTest2, bufferTest);
+ bufferTest2.clear();
+ ASSERT_EQ(bufferTest2.append(view2), ExtSuccess);
+ ASSERT_EQ(bufferTest, bufferTest2);
+ bufferTest.data()[3] = 'a';
+ ASSERT_NE(bufferTest, bufferTest2);
+}
+
+TEST(FudString, SpanCxx)
+{
+ Array<uint8_t, sizeof(CHQUOTE)> basis{};
+ ASSERT_EQ(ExtCopyMem(basis.data(), basis.size(), CHQUOTE, sizeof(CHQUOTE)), ExtSuccess);
+ String fudString{basis.size(), basis.size() - 1, basis.data()};
+
+ StringView inputView{extString};
+ ASSERT_NE(inputView.length, 0);
+ ASSERT_EQ(inputView.length, sizeof(CHQUOTE) - 1);
+ ASSERT_NE(inputView.data, nullptr);
+
+ constexpr Array<uint8_t, charSetSize + 1> charArray{CHARACTER_SET};
+ Array<Utf8, charSetSize> utf8Array{};
+ for (auto idx = 0; idx < utf8Array.size(); ++idx) {
+ utf8Array[idx] = Utf8{Ascii{charArray[idx]}};
+ }
+
+ static_assert(!ext_lib::hasDuplicates(charArray));
+ auto temp = utf8Array[0];
+ utf8Array[0] = utf8Array[1];
+ auto characterSetResult{Utf8Set<charSetSize>::make(utf8Array)};
+ ASSERT_TRUE(characterSetResult.isError());
+ utf8Array[0] = temp;
+ characterSetResult = Utf8Set<charSetSize>::make(utf8Array);
+ ASSERT_TRUE(characterSetResult.isOkay());
+ auto characterSet = characterSetResult.getOkay();
+
+ FudStringView result{};
+ EXPECT_EQ(ext_string_span_set(inputView, nullptr, nullptr), ExtNullPointer);
+ ASSERT_EQ(ext_string_span_set(inputView, &characterSet, &result), ExtSuccess);
+
+ ASSERT_EQ(result.length, sizeof(", when ignorance is instantaneous?") - 1);
+ std::vector<char> resString(result.length + 1);
+ ASSERT_EQ(ExtCopyMem(resString.data(), resString.size(), result.data, result.length), ExtSuccess);
+ ASSERT_EQ(std::string(resString.data()), std::string(", when ignorance is instantaneous?"));
+
+ Array<uint8_t, 2> ex2{'l'};
+ StringView setView2{};
+ setView2.length = sizeof(ex2) - 1;
+ setView2.data = ex2.data();
+ StringView setView3{setView2};
+ int difference = -1;
+ ASSERT_EQ(ExtCompareMem(&setView2, sizeof(setView2), &setView3, sizeof(setView3), &difference), ExtSuccess);
+ ASSERT_EQ(difference, 0);
+
+ Array<ExtUtf8Impl, 1> setArray{{Utf8{Ascii{'l'}}}};
+ Utf8Set<1> charSet{setArray};
+ ASSERT_FALSE(charSet.isEmptySet());
+ ASSERT_TRUE(static_cast<ExtUtf8Set*>(&charSet)->contains(Utf8{Ascii{'l'}}));
+ ASSERT_TRUE(static_cast<ExtUtf8Set*>(&charSet)->contains(setArray[0]));
+
+ EXPECT_EQ(ext_string_c_span_set(inputView, nullptr, nullptr), ExtNullPointer);
+ ASSERT_EQ(ext_string_c_span_set(inputView, &charSet, &result), ExtSuccess);
+
+ ASSERT_EQ(result.length, sizeof("learning, when ignorance is instantaneous?") - 1);
+ StringView resultView{result};
+ ASSERT_TRUE(resultView.nullTerminated());
+ resString.resize(result.length + 1);
+ ASSERT_EQ(ExtCopyMem(resString.data(), resString.size(), result.data, result.length), ExtSuccess);
+ ASSERT_EQ(std::string(resString.data()), std::string("learning, when ignorance is instantaneous?"));
+}
+
+TEST(FudString, SpanSetInvalid)
+{
+ constexpr Array<uint8_t, charSetSize + 1> charArray{CHARACTER_SET};
+ Array<Utf8, charSetSize> utf8Array{};
+ for (auto idx = 0; idx < utf8Array.size(); ++idx) {
+ utf8Array[idx] = Utf8{Ascii{charArray[idx]}};
+ }
+ utf8Array[0] = Utf8{Ascii{0xFF}}; // NOLINT(readability-magic-numbers)
+
+ static_assert(!ext_lib::hasDuplicates(charArray));
+ auto characterSetResult{Utf8Set<charSetSize>::make(utf8Array)};
+ ASSERT_TRUE(characterSetResult.isOkay());
+ auto characterSet{characterSetResult.getOkay()};
+
+ Array<uint8_t, sizeof(CHQUOTE)> backing{CHQUOTE};
+ auto fudString{FudString::withBacking(backing)};
+
+ StringView inputView{extString};
+
+ Array<uint8_t, sizeof(CHARACTER_SET)> setBacking{CHARACTER_SET};
+ setBacking[0] = ExtUtf8::invalidAsciiCode.character();
+
+ FudStringView result{};
+ ASSERT_EQ(ext_string_span_set(inputView, &characterSet, &result), ExtUtf8Invalid);
+ ASSERT_EQ(ext_string_c_span_set(inputView, &characterSet, &result), ExtUtf8Invalid);
+}
+
+TEST(FudString, SpanSetInputInvalid)
+{
+ constexpr Array<uint8_t, charSetSize + 1> charArray{CHARACTER_SET};
+ Array<Utf8, charSetSize> utf8Array{};
+ for (auto idx = 0; idx < utf8Array.size(); ++idx) {
+ utf8Array[idx] = Utf8{Ascii{charArray[idx]}};
+ }
+
+ static_assert(!ext_lib::hasDuplicates(charArray));
+ auto characterSetResult{Utf8Set<charSetSize>::make(utf8Array)};
+ ASSERT_TRUE(characterSetResult.isOkay());
+ auto characterSet{characterSetResult.getOkay()};
+
+ Array<uint8_t, sizeof(CHQUOTE)> backing{CHQUOTE};
+ backing[0] = ExtUtf8::invalidAsciiCode.character();
+ auto fudString{FudString::withBacking(backing)};
+
+ StringView inputView{extString};
+
+ Array<uint8_t, sizeof(CHARACTER_SET)> setBacking{CHARACTER_SET};
+
+ FudStringView result{};
+ ASSERT_EQ(ext_string_span_set(inputView, &characterSet, &result), ExtUtf8Invalid);
+ ASSERT_EQ(ext_string_c_span_set(inputView, &characterSet, &result), ExtUtf8Invalid);
+}
+
+TEST(FudString, SpanSetNotFound)
+{
+ constexpr Array<uint8_t, sizeof("QZ")> setBacking{"QZ"};
+ Array<Utf8, sizeof(setBacking) - 1> utf8Array{};
+ for (auto idx = 0; idx < utf8Array.size(); ++idx) {
+ utf8Array[idx] = Utf8{Ascii{setBacking[idx]}};
+ }
+
+ static_assert(!ext_lib::hasDuplicates(setBacking));
+ auto characterSetResult{Utf8Set<utf8Array.size()>::make(utf8Array)};
+ ASSERT_TRUE(characterSetResult.isOkay());
+ auto characterSet{characterSetResult.getOkay()};
+
+ Array<uint8_t, sizeof(CHQUOTE)> backing{CHQUOTE};
+ auto fudString{FudString::withBacking(backing)};
+
+ StringView inputView{extString};
+
+ FudStringView result{};
+ ASSERT_EQ(ext_string_span_set(inputView, &characterSet, &result), ExtNotFound);
+ ASSERT_EQ(ext_string_c_span_set(inputView, &characterSet, &result), ExtNotFound);
+}
+
+#endif
+} // namespace fud