diff options
Diffstat (limited to 'test/test_string.cpp')
-rw-r--r-- | test/test_string.cpp | 296 |
1 files changed, 296 insertions, 0 deletions
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 |