/* * 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}; auto stringResult = String::makeFromCString(reinterpret_cast(invalid2.data())); ASSERT_TRUE(stringResult.isOkay()); String fudString{stringResult.takeOkay()}; ASSERT_EQ(fudString.length(), 1); ASSERT_EQ(fudString.data()[0], invalid[0]); ASSERT_FALSE(Ascii::valid(fudString.data()[0])); ASSERT_FALSE(fudString.utf8Valid()); stringResult = String::makeFromCString("TEST"); ASSERT_TRUE(stringResult.isOkay()); fudString = stringResult.takeOkay(); ASSERT_TRUE(fudString.utf8Valid()); StringView view1{}; ASSERT_FALSE(view1.utf8Valid()); StringView view2{fudString}; ASSERT_TRUE(view2.utf8Valid()); ASSERT_TRUE(view2.nullTerminated()); } TEST(FudString, HeapAlloc) { constexpr const char filenameLiteral[] = "Amazing Saga Volume 01/000.jpg"; auto filenameResult{String::makeFromCString(filenameLiteral)}; ASSERT_TRUE(filenameResult.isOkay()); auto filename{filenameResult.takeOkay()}; ASSERT_EQ(filename.length(), sizeof(filenameLiteral) - 1); } TEST(FudString, Reserve) { String testString{}; ASSERT_TRUE(testString.valid()); ASSERT_EQ(testString.reserve(256), FudStatus::Success); ASSERT_TRUE(testString.valid()); } #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