From 0b860bb5dd6d2007db605291d239a6a9d41f57d1 Mon Sep 17 00:00:00 2001 From: Dominick Allen Date: Mon, 23 Sep 2024 07:36:16 -0500 Subject: Installable library. --- test/CMakeLists.txt | 7 +- test/test_common.cpp | 18 ++ test/test_common.hpp | 43 ++++ test/test_deserialize_number.cpp | 503 +++++++++++++++++++++++++++++++++++++++ test/test_result.cpp | 2 +- test/test_string.cpp | 296 +++++++++++++++++++++++ 6 files changed, 866 insertions(+), 3 deletions(-) create mode 100644 test/test_common.hpp create mode 100644 test/test_deserialize_number.cpp create mode 100644 test/test_string.cpp (limited to 'test') 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_include_directories(${test_name} PUBLIC $) - 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 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 +#include + +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 +auto testStringToIntegerInvalid(Func&& func) +{ + Array 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)(view, nullptr, 0, nullptr), ExtNullPointer); + + invalidView.data = nullptr; + ASSERT_EQ(std::forward(func)(invalidView, &number, 1, nullptr), ExtNullPointer); + invalidView.data = view.data; + + invalidView.length = 0; + ASSERT_EQ(std::forward(func)(invalidView, &number, 0, nullptr), ExtInvalidInput); + ASSERT_EQ(std::forward(func)(view, &number, 1, nullptr), ExtInvalidInput); + ASSERT_EQ(std::forward(func)(view, &number, UINT8_MAX, nullptr), ExtInvalidInput); +} + +template +auto testStringToNumber( + Array& backing, + const Array& wordSizes, + const Array& statuses, + const Array& expectedValues, + Func&& func, + uint8_t radix) +{ + FudString extString{FudString::withBacking(backing)}; + StringView view{extString}; + T number = 0; + + ASSERT_EQ(std::forward(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)(view, &tempNumber, radix, &index) != statuses[idx]) { + printf( + "どうして? \"%s\" %ld %zu %ld\n", + view.data, + static_cast(expectedValues[idx]), + idx, + static_cast(tempNumber)); + if (idx > 0) { + printf("Test: \"%s\"\n", view.data - index); + } + } + EXPECT_EQ(std::forward(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(ext_string_to_uint8); +} + +TEST(FudString, StringToUint8RadixUnspec) +{ + Array backing{"7 13 42 0 018 010 0xFF 0xFF0 256"}; + constexpr Array 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 expectedValues{7, 13, 42, 0, 1, 8, 8, 0xFF, 0, 0}; + constexpr Array 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 backing{"7 13 42 0 018 010 377 0xFF0"}; + constexpr Array expectedValues{7, 8 + 3, 8 * 4 + 2, 0, 1, 0, 8, 255, 0, 0}; + constexpr Array 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 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 backing{"7 13 0x42 0 018 010 FF 0xFF0"}; + constexpr Array expectedValues{7, 16 + 3, 16 * 4 + 2, 0, 16 + 8, 16, 255, 0}; + constexpr Array 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 + statuses{ExtSuccess, ExtSuccess, ExtSuccess, ExtSuccess, ExtSuccess, ExtSuccess, ExtSuccess, ExtInvalidInput}; + testStringToNumber(backing, wordSizes, statuses, expectedValues, ext_string_to_uint8, ExtRadixHexadecimal); +} + +TEST(FudString, StringToUint16Invalid) +{ + testStringToIntegerInvalid(ext_string_to_uint16); +} + +TEST(FudString, StringToUint16RadixUnspec) +{ + Array backing{ + "7 65535 0x42 0 010 0xFFFF 0xFFFF0"}; + constexpr Array expectedValues{7, 0xFFFF, 0x42, 0, 8, 0xFFFF, 0}; + constexpr Array wordSizes{ + sizeof("7") - 1, + sizeof(" 65535") - 1, + sizeof(" 0x42") - 1, + sizeof(" 0") - 1, + sizeof(" 010") - 1, + sizeof(" 0xFFFF") - 1, + sizeof(" 0xFFFF0") - 1}; + constexpr Array statuses{ + ExtSuccess, + ExtSuccess, + ExtSuccess, + ExtSuccess, + ExtSuccess, + ExtSuccess, + ExtInvalidInput}; + testStringToNumber(backing, wordSizes, statuses, expectedValues, ext_string_to_uint16, 0); +} + +TEST(FudString, StringToUint16Octal) +{ + Array backing{"7 13 42 0 010 177777 200000"}; + constexpr Array expectedValues{7, 8 + 3, 8 * 4 + 2, 0, 8, 0xFFFF, 0}; + constexpr Array wordSizes{ + sizeof("7") - 1, + sizeof(" 13") - 1, + sizeof(" 42") - 1, + sizeof(" 0") - 1, + sizeof(" 010") - 1, + sizeof(" 177777") - 1, + sizeof(" 200000") - 1}; + constexpr Array statuses{ + ExtSuccess, + ExtSuccess, + ExtSuccess, + ExtSuccess, + ExtSuccess, + ExtSuccess, + ExtInvalidInput}; + testStringToNumber(backing, wordSizes, statuses, expectedValues, ext_string_to_uint16, ExtRadixOctal); +} + +TEST(FudString, StringToUint16Hex) +{ + Array backing{"7 13 0x42 0 018 010 FFFF 0x10000"}; + constexpr Array expectedValues{7, 16 + 3, 16 * 4 + 2, 0, 16 + 8, 16, 0xFFFF, 0}; + constexpr Array 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 + statuses{ExtSuccess, ExtSuccess, ExtSuccess, ExtSuccess, ExtSuccess, ExtSuccess, ExtSuccess, ExtInvalidInput}; + testStringToNumber(backing, wordSizes, statuses, expectedValues, ext_string_to_uint16, ExtRadixHexadecimal); +} + +TEST(FudString, StringToUint64Hex) +{ + Array + backing{"7 13 0x7FFFFFFFFFFFFFFF 0 018 010 -8000000000000000 0xFFFFFFFFFFFFFFFF -8000000000000001"}; + constexpr Array expectedValues{ + 7, + 16 + 3, + std::numeric_limits::max(), + 0, + 16 + 8, + 16, + 0, + std::numeric_limits::max(), + 0}; + constexpr Array 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 statuses{ + ExtSuccess, + ExtSuccess, + ExtSuccess, + ExtSuccess, + ExtSuccess, + ExtSuccess, + ExtInvalidInput, + ExtSuccess, + ExtInvalidInput}; + testStringToNumber(backing, wordSizes, statuses, expectedValues, ext_string_to_uint64, ExtRadixHexadecimal); +} + +TEST(FudString, StringToInt8Invalid) +{ + testStringToIntegerInvalid(ext_string_to_int8); +} + +TEST(FudString, StringToInt8RadixUnspec) +{ + Array backing{"7 13 127 0 018 010 -0x80 0x80"}; + constexpr Array expectedValues{7, 13, 127, 0, 0, 8, -0x80, 0}; + constexpr Array 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 statuses{ + ExtSuccess, + ExtSuccess, + ExtSuccess, + ExtSuccess, + ExtInvalidInput, + ExtSuccess, + ExtSuccess, + ExtInvalidInput}; + testStringToNumber(backing, wordSizes, statuses, expectedValues, ext_string_to_int8, 0); +} + +TEST(FudString, StringToInt8Octal) +{ + Array backing{"7 13 177 0 018 010 -200 0xFF0 -201"}; + constexpr Array expectedValues{7, 8 + 3, 127, 0, 0, 8, -128, 0}; + constexpr Array 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 statuses{ + ExtSuccess, + ExtSuccess, + ExtSuccess, + ExtSuccess, + ExtInvalidInput, + ExtSuccess, + ExtSuccess, + ExtInvalidInput, + ExtInvalidInput}; + testStringToNumber(backing, wordSizes, statuses, expectedValues, ext_string_to_int8, ExtRadixOctal); +} + +TEST(FudString, StringToInt8Hex) +{ + Array backing{"7 13 0x7F 0 018 010 -80 0xFF0"}; + constexpr Array expectedValues{7, 16 + 3, 127, 0, 16 + 8, 16, -128, 0}; + constexpr Array 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 + statuses{ExtSuccess, ExtSuccess, ExtSuccess, ExtSuccess, ExtSuccess, ExtSuccess, ExtSuccess, ExtInvalidInput}; + testStringToNumber(backing, wordSizes, statuses, expectedValues, ext_string_to_int8, ExtRadixHexadecimal); +} + +TEST(FudString, StringToInt32Decimal) +{ + Array backing{"01 13 0x7F 0 018 010 -80 0xFF0"}; + constexpr Array expectedValues{1, 13, 0, 0, 18, 10, -80, 0}; + constexpr Array 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 + statuses{ExtSuccess, ExtSuccess, ExtInvalidInput, ExtSuccess, ExtSuccess, ExtSuccess, ExtSuccess, ExtInvalidInput}; + testStringToNumber(backing, wordSizes, statuses, expectedValues, ext_string_to_int8, ExtRadixDecimal); +} + +TEST(FudString, StringToInt64Hex) +{ + Array + backing{"+7 13 0x7FFFFFFFFFFFFFFF 0 018 010 -8000000000000000 0x8000000000000000 -8000000000000001"}; + constexpr Array expectedValues{ + 7, + 16 + 3, + std::numeric_limits::max(), + 0, + 16 + 8, + 16, + std::numeric_limits::min(), + 0, + 0}; + constexpr Array 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 statuses{ + ExtSuccess, + ExtSuccess, + ExtSuccess, + ExtSuccess, + ExtSuccess, + ExtSuccess, + ExtSuccess, + ExtInvalidInput, + ExtInvalidInput}; + testStringToNumber(backing, wordSizes, statuses, expectedValues, ext_string_to_int64, ExtRadixHexadecimal); +} + +template +struct TestStringToFloatParams { + T value{0.0}; + size_t wordSize{0}; + ExtStatus status{ExtInvalidInput}; + bool isNaN{false}; +}; + +template +auto testStringToFloat( + Array& backing, + const Array, WordCount>& testParams, + Func&& func) +{ + FudString extString{FudString::withBacking(backing)}; + StringView view{extString}; + T number = 0; + + ASSERT_EQ(std::forward(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)(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 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, 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::quiet_NaN(), sizeof("NaN"), ExtSuccess, true}, + {-1.0F * std::numeric_limits::infinity(), sizeof("-inf"), ExtSuccess}, + {std::numeric_limits::infinity(), sizeof("inF"), ExtSuccess}}}; + + testStringToFloat(backing, testParams, ext_string_to_float); +} + +TEST(FudString, StringToDouble) +{ + Array 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, 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::quiet_NaN(), sizeof("NaN"), ExtSuccess, true}, + {-1.0 * std::numeric_limits::infinity(), sizeof("-inf"), ExtSuccess}, + {std::numeric_limits::infinity(), sizeof("inF"), ExtSuccess}}}; + + testStringToFloat(backing, testParams, ext_string_to_double); +} + +TEST(FudString, StringToDoubleExpt) +{ + Array 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, 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 invalid{0xFF, 0x00}; + ASSERT_FALSE(Ascii::valid(invalid[0])); + const Array 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 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 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(stringView.data)); + // NOLINTEND(cppcoreguidelines-pro-type-reinterpret-cast) +} + +TEST(TestFudString, StringBuffer) +{ + Result, ExtStatus> bufferResult{FixedStringBuffer<1>::fromLiteral(nullptr)}; + ASSERT_TRUE(bufferResult.isError()); + ASSERT_EQ(bufferResult.getError(), ExtNullPointer); + + Array 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 data2{"test"}; + auto bufferResult2{FixedStringBuffer::fromArray(data2)}; + ASSERT_TRUE(bufferResult2.isOkay()); + FixedStringBuffer 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 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 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 charArray{CHARACTER_SET}; + Array 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::make(utf8Array)}; + ASSERT_TRUE(characterSetResult.isError()); + utf8Array[0] = temp; + characterSetResult = Utf8Set::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 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 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 setArray{{Utf8{Ascii{'l'}}}}; + Utf8Set<1> charSet{setArray}; + ASSERT_FALSE(charSet.isEmptySet()); + ASSERT_TRUE(static_cast(&charSet)->contains(Utf8{Ascii{'l'}})); + ASSERT_TRUE(static_cast(&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 charArray{CHARACTER_SET}; + Array 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::make(utf8Array)}; + ASSERT_TRUE(characterSetResult.isOkay()); + auto characterSet{characterSetResult.getOkay()}; + + Array backing{CHQUOTE}; + auto fudString{FudString::withBacking(backing)}; + + StringView inputView{extString}; + + Array 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 charArray{CHARACTER_SET}; + Array utf8Array{}; + for (auto idx = 0; idx < utf8Array.size(); ++idx) { + utf8Array[idx] = Utf8{Ascii{charArray[idx]}}; + } + + static_assert(!ext_lib::hasDuplicates(charArray)); + auto characterSetResult{Utf8Set::make(utf8Array)}; + ASSERT_TRUE(characterSetResult.isOkay()); + auto characterSet{characterSetResult.getOkay()}; + + Array backing{CHQUOTE}; + backing[0] = ExtUtf8::invalidAsciiCode.character(); + auto fudString{FudString::withBacking(backing)}; + + StringView inputView{extString}; + + Array 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 setBacking{"QZ"}; + Array utf8Array{}; + for (auto idx = 0; idx < utf8Array.size(); ++idx) { + utf8Array[idx] = Utf8{Ascii{setBacking[idx]}}; + } + + static_assert(!ext_lib::hasDuplicates(setBacking)); + auto characterSetResult{Utf8Set::make(utf8Array)}; + ASSERT_TRUE(characterSetResult.isOkay()); + auto characterSet{characterSetResult.getOkay()}; + + Array 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 -- cgit v1.2.3