diff options
Diffstat (limited to 'test')
-rw-r--r-- | test/CMakeLists.txt | 7 | ||||
-rw-r--r-- | test/test_common.cpp | 18 | ||||
-rw-r--r-- | test/test_common.hpp | 43 | ||||
-rw-r--r-- | test/test_deserialize_number.cpp | 503 | ||||
-rw-r--r-- | test/test_result.cpp | 2 | ||||
-rw-r--r-- | test/test_string.cpp | 296 |
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 |