/* * 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_algorithm.hpp" #include "fud_allocator.hpp" #include "fud_array.hpp" #include "fud_string.hpp" #include "fud_utf8.hpp" #include "fud_utf8_iterator.hpp" #include "fud_vector.hpp" #include "test_common.hpp" // #include "fud_format.hpp" // #include "fud_span.hpp" #include "gtest/gtest.h" namespace fud { constexpr size_t validAsciiSize = INT8_MAX + 1; constexpr size_t invalidAsciiSize = UINT8_MAX + 1 - validAsciiSize; constexpr size_t numControlChars = 33; constexpr char printableCharOffset = 0x20; constexpr auto invalidAscii = FudUtf8::invalidAsciiCode.character(); auto generateInvalidAsciiChars() { Iota iota{}; return generate([]() { return Array{}; }, [&]() { return iota().value(); }); } TEST(Utf8Test, Utf8Creation) { const Array threeByte = {THREE_BYTE}; FudUtf8 utf8Point{FudUtf8::make(threeByte)}; ASSERT_NE(utf8Point.data(), nullptr); ASSERT_EQ(utf8Point.size(), 3); ASSERT_NE(utf8Point.hash(), -1); const Array asciiLetter = {'A'}; utf8Point = FudUtf8::make(asciiLetter); ASSERT_NE(utf8Point.data(), nullptr); ASSERT_EQ(utf8Point.size(), 1); const Array twoByte = {TWO_BYTE}; utf8Point = FudUtf8::make(twoByte); ASSERT_NE(utf8Point.data(), nullptr); ASSERT_EQ(utf8Point.size(), 2); ASSERT_NE(utf8Point.hash(), -1); Array fourByte = { static_cast(FOUR_BYTE[0]), static_cast(FOUR_BYTE[1]), static_cast(FOUR_BYTE[2]), static_cast(FOUR_BYTE[3])}; utf8Point = FudUtf8::make(fourByte); ASSERT_NE(utf8Point.data(), nullptr); ASSERT_EQ(utf8Point.size(), 4); ASSERT_NE(utf8Point.hash(), -1); const Array invalidBytes = {0xFF, 0xFF, 0xFF, 0xFF}; utf8Point = FudUtf8::make(invalidBytes); ASSERT_EQ(utf8Point.data(), nullptr); ASSERT_EQ(utf8Point.size(), 0); ASSERT_EQ(utf8Point.hash(), -1); } TEST(Utf8Test, Utf8MultiByte) { Array data{MULTI_BYTE_LITERAL}; constexpr size_t bufSize = data.size(); EXPECT_EQ(data[bufSize - 1], '\0'); class FixedAllocator final : public Allocator { private: Array m_memory{}; size_t m_allocated{0}; public: virtual ~FixedAllocator() override final = default; virtual Result allocate(size_t bytes, size_t alignment) override final { static_cast(alignment); if (bytes > m_memory.size() - m_allocated) { return FudStatus::AllocFailure; } auto* data = m_memory.data() + m_allocated; m_allocated += bytes; return data; } virtual FudStatus deallocate(void* pointer, size_t bytes) override final { static_cast(pointer); static_cast(bytes); return FudStatus::Success; } virtual bool isEqual(const Allocator& rhs) const override final { return &rhs == this; } }; FixedAllocator fixedAllocator; auto stringBufferRes{String::makeFromCString(MULTI_BYTE_LITERAL, &fixedAllocator)}; ASSERT_TRUE(stringBufferRes.isOkay()); auto stringBuffer{stringBufferRes.takeOkay()}; EXPECT_EQ(stringBuffer.size(), bufSize); EXPECT_EQ(stringBuffer.size(), sizeof(data)); EXPECT_EQ(stringBuffer.length(), bufSize - 1); EXPECT_TRUE(stringBuffer.nullTerminated()); EXPECT_TRUE(stringBuffer.valid()); ASSERT_TRUE(stringBuffer.utf8Valid()); Utf8Iterator utf8Iter{stringBuffer}; auto characterOpt = utf8Iter.next(); ASSERT_TRUE(characterOpt.has_value()); // MULTI_BYTE_LITERAL "test今日素敵はですねƩ®😀z" const Array multiByteCharacters{ FudUtf8::make(Utf8Variant{Ascii{'t'}}), FudUtf8::make(Utf8Variant{Ascii{'e'}}), FudUtf8::make(Utf8Variant{Ascii{'s'}}), FudUtf8::make(Utf8Variant{Ascii{'t'}}), FudUtf8::from(StringView{sizeof("今"), "今"}, 0), FudUtf8::from(StringView{sizeof("日"), "日"}, 0), FudUtf8::from(StringView{sizeof("素"), "素"}, 0), FudUtf8::from(StringView{sizeof("敵"), "敵"}, 0), FudUtf8::from(StringView{sizeof("は"), "は"}, 0), FudUtf8::from(StringView{sizeof("で"), "で"}, 0), FudUtf8::from(StringView{sizeof("す"), "す"}, 0), FudUtf8::from(StringView{sizeof("ね"), "ね"}, 0), FudUtf8::from(StringView{sizeof("Ʃ"), "Ʃ"}, 0), FudUtf8::from(StringView{sizeof("®"), "®"}, 0), FudUtf8::from(StringView{sizeof("😀"), "😀"}, 0), FudUtf8::make(Utf8Variant{Ascii{'z'}}), }; size_t idx = 0; while (characterOpt.has_value()) { auto character = *characterOpt; if (character != FudUtf8{Utf8Variant{Ascii{'\0'}}}) { EXPECT_TRUE(character.size() >= 1); ASSERT_LT(idx, multiByteCharacters.size()); EXPECT_EQ(character.size(), multiByteCharacters[idx].size()); EXPECT_EQ(character, multiByteCharacters[idx]); EXPECT_TRUE(multiByteCharacters[idx].valid()); if (character != multiByteCharacters[idx]) { printf("idx = %zu, %.*s\n", idx, static_cast(character.size()), character.data()); } idx++; } characterOpt = utf8Iter.next(); } utf8Iter.reset(); ASSERT_TRUE(utf8Iter.next().has_value()); FudUtf8 invalid = FudUtf8::invalidAscii(); ASSERT_FALSE(invalid.valid()); ASSERT_EQ(invalid.size(), 0); ASSERT_EQ(invalid.data(), nullptr); ASSERT_EQ(invalid.hash(), -1); } TEST(Utf8Test, Utf8IsAscii) { ASSERT_FALSE(charIsAscii(invalidAscii)); Iota charIota{0, 1, validAsciiSize}; ASSERT_TRUE(allOf( [&]() -> std::optional { auto value = charIota(); return value ? std::optional(static_cast(*value)) : std::nullopt; }, charIsAscii)); Iota invalidCharIota{validAsciiSize, 1, invalidAsciiSize}; ASSERT_FALSE(anyOf( [&]() -> std::optional { auto value = invalidCharIota(); return value ? std::optional(static_cast(*value)) : std::nullopt; }, charIsAscii)); FudUtf8 unicode{FudUtf8::invalidAscii()}; ASSERT_FALSE(utf8IsAscii(unicode)); charIota.set(0); ASSERT_TRUE(allOf( [&]() -> std::optional { auto value = charIota(); return value ? std::optional(FudUtf8::make(static_cast(*value))) : std::nullopt; }, utf8IsAscii)); invalidCharIota.set(invalidAsciiSize); ASSERT_FALSE(anyOf( [&]() -> std::optional { auto value = invalidCharIota(); return value ? std::optional(FudUtf8::make(static_cast(*value))) : std::nullopt; }, utf8IsAscii)); } TEST(Utf8Test, Utf8IsAlphaNumeric) { constexpr size_t numAlphaNumericChars = 26 * 2 + 10; Array alphaNumericCharLiteral{ALPHA_NUMERIC_CHARS}; Array alphaNumericChars{}; copyMem(alphaNumericChars, alphaNumericCharLiteral); #if 0 ASSERT_TRUE(allOf(alphaNumericChars, charIsAlphanumeric)); auto alphaNumericSetResult{StaticSet::makeFromArray(alphaNumericChars)}; ASSERT_TRUE(alphaNumericSetResult.isOkay()); auto alphaNumericSet{std::move(alphaNumericSetResult.getOkay())}; constexpr size_t numNonAlphaNumericChars = validAsciiSize - numAlphaNumericChars; FixedVector nonAlphaNumericChars{}; for (char idx = 0; idx < INT8_MAX; ++idx) { if (!alphaNumericSet.isKey(idx)) { ASSERT_TRUE(nonAlphaNumericChars.pushBack(idx)); } } ASSERT_FALSE(anyOf(nonAlphaNumericChars, charIsAlphanumeric)); auto invalidAsciiChars = generateInvalidAsciiChars(); ASSERT_FALSE(anyOf(invalidAsciiChars, charIsAlphanumeric)); ASSERT_TRUE(allOf( map(alphaNumericChars, [](auto input) { return ExtUtf8Char4{static_cast(input)}; }), ext_lib_char4_is_alphanumeric)); ASSERT_FALSE(anyOf( map(nonAlphaNumericChars, [](auto input) { return ExtUtf8Char4{static_cast(input)}; }), ext_lib_char4_is_alphanumeric)); ASSERT_FALSE(anyOf( map(invalidAsciiChars, [](auto input) { return ExtUtf8Char4{static_cast(input)}; }), ext_lib_char4_is_alphanumeric)); ASSERT_TRUE(allOf( map(alphaNumericChars, [](auto input) { return ExtUtf8Char4{static_cast(input)}; }), ext_lib_char4_is_alphanumeric)); ASSERT_FALSE(anyOf( map(nonAlphaNumericChars, [](auto input) { return ExtUtf8Char4{static_cast(input)}; }), ext_lib_char4_is_alphanumeric)); ASSERT_FALSE(anyOf( map(invalidAsciiChars, [](auto input) { return ExtUtf8Char4{static_cast(input)}; }), ext_lib_char4_is_alphanumeric)); Utf8 utf8{invalidAscii}; bool isAscii = false; ASSERT_EQ(ext_lib_utf8_is_alphanumeric(nullptr, nullptr), ExtNullPointer); ASSERT_EQ(ext_lib_utf8_is_alphanumeric(&utf8, nullptr), ExtNullPointer); ASSERT_EQ(ext_lib_utf8_is_alphanumeric(nullptr, &isAscii), ExtNullPointer); ASSERT_EQ(ext_lib_utf8_is_alphanumeric(&utf8, &isAscii), ExtInvalidInput); ASSERT_FALSE(isAscii); ASSERT_TRUE(allOf( map(alphaNumericChars, [](char letter) { return FudUtf8::makeUtf8(ExtUtf8Char4{static_cast(letter)}); }), [](auto& utf8Letter) { bool predicate = false; auto isPredicateStatus = ext_lib_utf8_is_alphanumeric(&utf8Letter, &predicate); return isPredicateStatus == ExtSuccess && predicate; })); ASSERT_FALSE(anyOf( map(nonAlphaNumericChars, [](char letter) { return FudUtf8::makeUtf8(ExtUtf8Char4{static_cast(letter)}); }), [](auto& utf8Letter) { bool predicate = false; auto isPredicateStatus = ext_lib_utf8_is_alphanumeric(&utf8Letter, &predicate); return isPredicateStatus != ExtSuccess || predicate; })); ASSERT_FALSE(allOf( map(nonAlphaNumericChars, [](char letter) { return FudUtf8::makeUtf8(ExtUtf8Char4{static_cast(letter)}); }), [](auto& utf8Letter) { bool predicate = false; auto isPredicateStatus = ext_lib_utf8_is_alphanumeric(&utf8Letter, &predicate); return isPredicateStatus == ExtInvalidInput && !predicate; })); #endif } #if 0 TEST(Utf8Test, Utf8IsAlpha) { constexpr size_t numAlphaChars = sizeof(ALPHA_CHARS) - 1; Array alphaCharLiteral{ALPHA_CHARS}; Array alphaChars{}; copyMem(alphaChars, alphaCharLiteral); ASSERT_TRUE(allOf(alphaChars, ext_lib_char_is_alpha)); auto alphaSetResult{StaticSet::makeFromArray(alphaChars)}; ASSERT_TRUE(alphaSetResult.isOkay()); auto alphaSet{std::move(alphaSetResult.getOkay())}; constexpr size_t numNonAlphaChars = validAsciiSize - numAlphaChars; FixedVector nonAlphaChars{}; for (char idx = 0; idx < INT8_MAX; ++idx) { if (!alphaSet.isKey(idx)) { ASSERT_TRUE(nonAlphaChars.pushBack(idx)); } } ASSERT_FALSE(anyOf(nonAlphaChars, ext_lib_char_is_alpha)); auto invalidAsciiChars = generateInvalidAsciiChars(); ASSERT_FALSE(anyOf(invalidAsciiChars, ext_lib_char_is_alpha)); ASSERT_TRUE(allOf( map(alphaChars, [](auto input) { return ExtUtf8Char4{static_cast(input)}; }), ext_lib_char4_is_alpha)); ASSERT_FALSE(anyOf( map(nonAlphaChars, [](auto input) { return ExtUtf8Char4{static_cast(input)}; }), ext_lib_char4_is_alpha)); ASSERT_FALSE(anyOf( map(invalidAsciiChars, [](auto input) { return ExtUtf8Char4{static_cast(input)}; }), ext_lib_char4_is_alpha)); ASSERT_TRUE(allOf( map(alphaChars, [](auto input) { return ExtUtf8Char4{static_cast(input)}; }), ext_lib_char4_is_alpha)); ASSERT_FALSE(anyOf( map(nonAlphaChars, [](auto input) { return ExtUtf8Char4{static_cast(input)}; }), ext_lib_char4_is_alpha)); ASSERT_FALSE(anyOf( map(invalidAsciiChars, [](auto input) { return ExtUtf8Char4{static_cast(input)}; }), ext_lib_char4_is_alpha)); Utf8 utf8{invalidAscii}; bool isAscii = false; ASSERT_EQ(ext_lib_utf8_is_alpha(nullptr, nullptr), ExtNullPointer); ASSERT_EQ(ext_lib_utf8_is_alpha(&utf8, nullptr), ExtNullPointer); ASSERT_EQ(ext_lib_utf8_is_alpha(nullptr, &isAscii), ExtNullPointer); ASSERT_EQ(ext_lib_utf8_is_alpha(&utf8, &isAscii), ExtInvalidInput); ASSERT_FALSE(isAscii); ASSERT_TRUE(allOf( map(alphaChars, [](char letter) { return FudUtf8::makeUtf8(ExtUtf8Char4{static_cast(letter)}); }), [](auto& utf8Letter) { bool predicate = false; auto isPredicateStatus = ext_lib_utf8_is_alpha(&utf8Letter, &predicate); return isPredicateStatus == ExtSuccess && predicate; })); ASSERT_FALSE(anyOf( map(nonAlphaChars, [](char letter) { return FudUtf8::makeUtf8(ExtUtf8Char4{static_cast(letter)}); }), [](auto& utf8Letter) { bool predicate = false; auto isPredicateStatus = ext_lib_utf8_is_alpha(&utf8Letter, &predicate); return isPredicateStatus != ExtSuccess || predicate; })); ASSERT_FALSE(allOf( map(nonAlphaChars, [](char letter) { return FudUtf8::makeUtf8(ExtUtf8Char4{static_cast(letter)}); }), [](auto& utf8Letter) { bool predicate = false; auto isPredicateStatus = ext_lib_utf8_is_alpha(&utf8Letter, &predicate); return isPredicateStatus == ExtInvalidInput && !predicate; })); } TEST(Utf8Test, Utf8IsLower) { constexpr size_t numLowerChars = 26; Array lowerCharLiteral{LOWERCASE_CHARS}; Array lowerChars{}; copyMem(lowerChars, lowerCharLiteral); ASSERT_TRUE(allOf(lowerChars, ext_lib_char_is_lowercase)); auto lowerSetResult{StaticSet::makeFromArray(lowerChars)}; ASSERT_TRUE(lowerSetResult.isOkay()); auto lowerSet{std::move(lowerSetResult.getOkay())}; constexpr size_t numNonLowerChars = validAsciiSize - numLowerChars; FixedVector nonLowerChars{}; for (char idx = 0; idx < INT8_MAX; ++idx) { if (!lowerSet.isKey(idx)) { ASSERT_TRUE(nonLowerChars.pushBack(idx)); } } ASSERT_FALSE(anyOf(nonLowerChars, ext_lib_char_is_lowercase)); auto invalidAsciiChars = generateInvalidAsciiChars(); ASSERT_FALSE(anyOf(invalidAsciiChars, ext_lib_char_is_lowercase)); ASSERT_TRUE(allOf( map(lowerChars, [](auto input) { return ExtUtf8Char4{static_cast(input)}; }), ext_lib_char4_is_lowercase)); ASSERT_FALSE(anyOf( map(nonLowerChars, [](auto input) { return ExtUtf8Char4{static_cast(input)}; }), ext_lib_char4_is_lowercase)); ASSERT_FALSE(anyOf( map(invalidAsciiChars, [](auto input) { return ExtUtf8Char4{static_cast(input)}; }), ext_lib_char4_is_lowercase)); ASSERT_TRUE(allOf( map(lowerChars, [](auto input) { return ExtUtf8Char4{static_cast(input)}; }), ext_lib_char4_is_lowercase)); ASSERT_FALSE(anyOf( map(nonLowerChars, [](auto input) { return ExtUtf8Char4{static_cast(input)}; }), ext_lib_char4_is_lowercase)); ASSERT_FALSE(anyOf( map(invalidAsciiChars, [](auto input) { return ExtUtf8Char4{static_cast(input)}; }), ext_lib_char4_is_lowercase)); Utf8 utf8{invalidAscii}; bool isAscii = false; ASSERT_EQ(ext_lib_utf8_is_lowercase(nullptr, nullptr), ExtNullPointer); ASSERT_EQ(ext_lib_utf8_is_lowercase(&utf8, nullptr), ExtNullPointer); ASSERT_EQ(ext_lib_utf8_is_lowercase(nullptr, &isAscii), ExtNullPointer); ASSERT_EQ(ext_lib_utf8_is_lowercase(&utf8, &isAscii), ExtInvalidInput); ASSERT_FALSE(isAscii); ASSERT_TRUE(allOf( map(lowerChars, [](char letter) { return FudUtf8::makeUtf8(ExtUtf8Char4{static_cast(letter)}); }), [](auto& utf8Letter) { bool predicate = false; auto isPredicateStatus = ext_lib_utf8_is_lowercase(&utf8Letter, &predicate); return isPredicateStatus == ExtSuccess && predicate; })); ASSERT_FALSE(anyOf( map(nonLowerChars, [](char letter) { return FudUtf8::makeUtf8(ExtUtf8Char4{static_cast(letter)}); }), [](auto& utf8Letter) { bool predicate = false; auto isPredicateStatus = ext_lib_utf8_is_lowercase(&utf8Letter, &predicate); return isPredicateStatus != ExtSuccess || predicate; })); ASSERT_FALSE(allOf( map(nonLowerChars, [](char letter) { return FudUtf8::makeUtf8(ExtUtf8Char4{static_cast(letter)}); }), [](auto& utf8Letter) { bool predicate = false; auto isPredicateStatus = ext_lib_utf8_is_lowercase(&utf8Letter, &predicate); return isPredicateStatus == ExtInvalidInput && !predicate; })); } TEST(Utf8Test, Utf8IsUpper) { constexpr size_t numUpperChars = 26; Array upperCharLiteral{UPPERCASE_CHARS}; Array upperChars{}; copyMem(upperChars, upperCharLiteral); ASSERT_TRUE(allOf(upperChars, ext_lib_char_is_uppercase)); auto upperSetResult{StaticSet::makeFromArray(upperChars)}; ASSERT_TRUE(upperSetResult.isOkay()); auto upperSet{std::move(upperSetResult.getOkay())}; constexpr size_t numNonUpperChars = validAsciiSize - numUpperChars; FixedVector nonUpperChars{}; for (char idx = 0; idx < INT8_MAX; ++idx) { if (!upperSet.isKey(idx)) { ASSERT_TRUE(nonUpperChars.pushBack(idx)); } } ASSERT_FALSE(anyOf(nonUpperChars, ext_lib_char_is_uppercase)); auto invalidAsciiChars = generateInvalidAsciiChars(); ASSERT_FALSE(anyOf(invalidAsciiChars, ext_lib_char_is_uppercase)); ASSERT_TRUE(allOf( map(upperChars, [](auto input) { return ExtUtf8Char4{static_cast(input)}; }), ext_lib_char4_is_uppercase)); ASSERT_FALSE(anyOf( map(nonUpperChars, [](auto input) { return ExtUtf8Char4{static_cast(input)}; }), ext_lib_char4_is_uppercase)); ASSERT_FALSE(anyOf( map(invalidAsciiChars, [](auto input) { return ExtUtf8Char4{static_cast(input)}; }), ext_lib_char4_is_uppercase)); ASSERT_TRUE(allOf( map(upperChars, [](auto input) { return ExtUtf8Char4{static_cast(input)}; }), ext_lib_char4_is_uppercase)); ASSERT_FALSE(anyOf( map(nonUpperChars, [](auto input) { return ExtUtf8Char4{static_cast(input)}; }), ext_lib_char4_is_uppercase)); ASSERT_FALSE(anyOf( map(invalidAsciiChars, [](auto input) { return ExtUtf8Char4{static_cast(input)}; }), ext_lib_char4_is_uppercase)); Utf8 utf8{invalidAscii}; bool isAscii = false; ASSERT_EQ(ext_lib_utf8_is_uppercase(nullptr, nullptr), ExtNullPointer); ASSERT_EQ(ext_lib_utf8_is_uppercase(&utf8, nullptr), ExtNullPointer); ASSERT_EQ(ext_lib_utf8_is_uppercase(nullptr, &isAscii), ExtNullPointer); ASSERT_EQ(ext_lib_utf8_is_uppercase(&utf8, &isAscii), ExtInvalidInput); ASSERT_FALSE(isAscii); ASSERT_TRUE(allOf( map(upperChars, [](char letter) { return FudUtf8::makeUtf8(ExtUtf8Char4{static_cast(letter)}); }), [](auto& utf8Letter) { bool predicate = false; auto isPredicateStatus = ext_lib_utf8_is_uppercase(&utf8Letter, &predicate); return isPredicateStatus == ExtSuccess && predicate; })); ASSERT_FALSE(anyOf( map(nonUpperChars, [](char letter) { return FudUtf8::makeUtf8(ExtUtf8Char4{static_cast(letter)}); }), [](auto& utf8Letter) { bool predicate = false; auto isPredicateStatus = ext_lib_utf8_is_uppercase(&utf8Letter, &predicate); return isPredicateStatus != ExtSuccess || predicate; })); ASSERT_FALSE(allOf( map(nonUpperChars, [](char letter) { return FudUtf8::makeUtf8(ExtUtf8Char4{static_cast(letter)}); }), [](auto& utf8Letter) { bool predicate = false; auto isPredicateStatus = ext_lib_utf8_is_uppercase(&utf8Letter, &predicate); return isPredicateStatus == ExtInvalidInput && !predicate; })); } TEST(Utf8Test, Utf8IsDigit) { constexpr size_t numDigitChars = 10; Array digitCharLiteral{"0123456789"}; Array digitChars{}; copyMem(digitChars, digitCharLiteral); ASSERT_TRUE(allOf(digitChars, ext_lib_char_is_digit)); auto digitSetResult{StaticSet::makeFromArray(digitChars)}; ASSERT_TRUE(digitSetResult.isOkay()); auto digitSet{std::move(digitSetResult.getOkay())}; constexpr size_t numNonDigitChars = validAsciiSize - numDigitChars; FixedVector nonDigitChars{}; for (char idx = 0; idx < INT8_MAX; ++idx) { if (!digitSet.isKey(idx)) { ASSERT_TRUE(nonDigitChars.pushBack(idx)); } } ASSERT_FALSE(anyOf(nonDigitChars, ext_lib_char_is_digit)); auto invalidAsciiChars = generateInvalidAsciiChars(); ASSERT_FALSE(anyOf(invalidAsciiChars, ext_lib_char_is_digit)); ASSERT_TRUE(allOf( map(digitChars, [](auto input) { return ExtUtf8Char4{static_cast(input)}; }), ext_lib_char4_is_digit)); ASSERT_FALSE(anyOf( map(nonDigitChars, [](auto input) { return ExtUtf8Char4{static_cast(input)}; }), ext_lib_char4_is_digit)); ASSERT_FALSE(anyOf( map(invalidAsciiChars, [](auto input) { return ExtUtf8Char4{static_cast(input)}; }), ext_lib_char4_is_digit)); ASSERT_TRUE(allOf( map(digitChars, [](auto input) { return ExtUtf8Char4{static_cast(input)}; }), ext_lib_char4_is_digit)); ASSERT_FALSE(anyOf( map(nonDigitChars, [](auto input) { return ExtUtf8Char4{static_cast(input)}; }), ext_lib_char4_is_digit)); ASSERT_FALSE(anyOf( map(invalidAsciiChars, [](auto input) { return ExtUtf8Char4{static_cast(input)}; }), ext_lib_char4_is_digit)); Utf8 utf8{invalidAscii}; bool isAscii = false; ASSERT_EQ(ext_lib_utf8_is_digit(nullptr, nullptr), ExtNullPointer); ASSERT_EQ(ext_lib_utf8_is_digit(&utf8, nullptr), ExtNullPointer); ASSERT_EQ(ext_lib_utf8_is_digit(nullptr, &isAscii), ExtNullPointer); ASSERT_EQ(ext_lib_utf8_is_digit(&utf8, &isAscii), ExtInvalidInput); ASSERT_FALSE(isAscii); ASSERT_TRUE(allOf( map(digitChars, [](char letter) { return FudUtf8::makeUtf8(ExtUtf8Char4{static_cast(letter)}); }), [](auto& utf8Letter) { bool predicate = false; auto isPredicateStatus = ext_lib_utf8_is_digit(&utf8Letter, &predicate); return isPredicateStatus == ExtSuccess && predicate; })); ASSERT_FALSE(anyOf( map(nonDigitChars, [](char letter) { return FudUtf8::makeUtf8(ExtUtf8Char4{static_cast(letter)}); }), [](auto& utf8Letter) { bool predicate = false; auto isPredicateStatus = ext_lib_utf8_is_digit(&utf8Letter, &predicate); return isPredicateStatus != ExtSuccess || predicate; })); ASSERT_FALSE(allOf( map(nonDigitChars, [](char letter) { return FudUtf8::makeUtf8(ExtUtf8Char4{static_cast(letter)}); }), [](auto& utf8Letter) { bool predicate = false; auto isPredicateStatus = ext_lib_utf8_is_digit(&utf8Letter, &predicate); return isPredicateStatus == ExtInvalidInput && !predicate; })); } TEST(Utf8Test, Utf8IsHexDigit) { constexpr size_t numHexDigitChars = 6 * 2 + 10; Array hexDigitCharLiteral{"abcdefABCDEF0123456789"}; Array hexDigitChars{}; copyMem(hexDigitChars, hexDigitCharLiteral); ASSERT_TRUE(allOf(hexDigitChars, ext_lib_char_is_hex_digit)); auto hexDigitSetResult{StaticSet::makeFromArray(hexDigitChars)}; ASSERT_TRUE(hexDigitSetResult.isOkay()); auto hexDigitSet{std::move(hexDigitSetResult.getOkay())}; constexpr size_t numNonHexDigitChars = validAsciiSize - numHexDigitChars; FixedVector nonHexDigitChars{}; for (char idx = 0; idx < INT8_MAX; ++idx) { if (!hexDigitSet.isKey(idx)) { ASSERT_TRUE(nonHexDigitChars.pushBack(idx)); } } ASSERT_FALSE(anyOf(nonHexDigitChars, ext_lib_char_is_hex_digit)); auto invalidAsciiChars = generateInvalidAsciiChars(); ASSERT_FALSE(anyOf(invalidAsciiChars, ext_lib_char_is_hex_digit)); ASSERT_TRUE(allOf( map(hexDigitChars, [](auto input) { return ExtUtf8Char4{static_cast(input)}; }), ext_lib_char4_is_hex_digit)); ASSERT_FALSE(anyOf( map(nonHexDigitChars, [](auto input) { return ExtUtf8Char4{static_cast(input)}; }), ext_lib_char4_is_hex_digit)); ASSERT_FALSE(anyOf( map(invalidAsciiChars, [](auto input) { return ExtUtf8Char4{static_cast(input)}; }), ext_lib_char4_is_hex_digit)); ASSERT_TRUE(allOf( map(hexDigitChars, [](auto input) { return ExtUtf8Char4{static_cast(input)}; }), ext_lib_char4_is_hex_digit)); ASSERT_FALSE(anyOf( map(nonHexDigitChars, [](auto input) { return ExtUtf8Char4{static_cast(input)}; }), ext_lib_char4_is_hex_digit)); ASSERT_FALSE(anyOf( map(invalidAsciiChars, [](auto input) { return ExtUtf8Char4{static_cast(input)}; }), ext_lib_char4_is_hex_digit)); Utf8 utf8{invalidAscii}; bool isAscii = false; ASSERT_EQ(ext_lib_utf8_is_hex_digit(nullptr, nullptr), ExtNullPointer); ASSERT_EQ(ext_lib_utf8_is_hex_digit(&utf8, nullptr), ExtNullPointer); ASSERT_EQ(ext_lib_utf8_is_hex_digit(nullptr, &isAscii), ExtNullPointer); ASSERT_EQ(ext_lib_utf8_is_hex_digit(&utf8, &isAscii), ExtInvalidInput); ASSERT_FALSE(isAscii); ASSERT_TRUE(allOf( map(hexDigitChars, [](char letter) { return FudUtf8::makeUtf8(ExtUtf8Char4{static_cast(letter)}); }), [](auto& utf8Letter) { bool predicate = false; auto isPredicateStatus = ext_lib_utf8_is_hex_digit(&utf8Letter, &predicate); return isPredicateStatus == ExtSuccess && predicate; })); ASSERT_FALSE(anyOf( map(nonHexDigitChars, [](char letter) { return FudUtf8::makeUtf8(ExtUtf8Char4{static_cast(letter)}); }), [](auto& utf8Letter) { bool predicate = false; auto isPredicateStatus = ext_lib_utf8_is_hex_digit(&utf8Letter, &predicate); return isPredicateStatus != ExtSuccess || predicate; })); ASSERT_FALSE(allOf( map(nonHexDigitChars, [](char letter) { return FudUtf8::makeUtf8(ExtUtf8Char4{static_cast(letter)}); }), [](auto& utf8Letter) { bool predicate = false; auto isPredicateStatus = ext_lib_utf8_is_hex_digit(&utf8Letter, &predicate); return isPredicateStatus == ExtInvalidInput && !predicate; })); } TEST(Utf8Test, Utf8IsControl) { auto controlChars = generateIndexArray([](int idx) { return static_cast(idx); }); constexpr const char deleteChar = 0x7F; controlChars.back() = deleteChar; ASSERT_TRUE(allOf(controlChars, ext_lib_char_is_control)); constexpr size_t numNonControlChars = 256 - numControlChars; auto nonControlChars = generateIndexArray([](int idx) { return static_cast(idx + printableCharOffset); }); ASSERT_FALSE(anyOf(nonControlChars, ext_lib_char_is_control)); auto invalidAsciiChars = generateInvalidAsciiChars(); ASSERT_FALSE(anyOf(invalidAsciiChars, ext_lib_char_is_control)); ASSERT_TRUE(allOf( map(controlChars, [](auto input) { return ExtUtf8Char4{static_cast(input)}; }), ext_lib_char4_is_control)); ASSERT_FALSE(anyOf( map(nonControlChars, [](auto input) { return ExtUtf8Char4{static_cast(input)}; }), ext_lib_char4_is_control)); ASSERT_FALSE(anyOf( map(invalidAsciiChars, [](auto input) { return ExtUtf8Char4{static_cast(input)}; }), ext_lib_char4_is_control)); ASSERT_TRUE(allOf( map(controlChars, [](auto input) { return ExtUtf8Char4{static_cast(input)}; }), ext_lib_char4_is_control)); ASSERT_FALSE(anyOf( map(nonControlChars, [](auto input) { return ExtUtf8Char4{static_cast(input)}; }), ext_lib_char4_is_control)); ASSERT_FALSE(anyOf( map(invalidAsciiChars, [](auto input) { return ExtUtf8Char4{static_cast(input)}; }), ext_lib_char4_is_control)); Utf8 utf8{invalidAscii}; bool isAscii = false; ASSERT_EQ(ext_lib_utf8_is_control(nullptr, nullptr), ExtNullPointer); ASSERT_EQ(ext_lib_utf8_is_control(&utf8, nullptr), ExtNullPointer); ASSERT_EQ(ext_lib_utf8_is_control(nullptr, &isAscii), ExtNullPointer); ASSERT_EQ(ext_lib_utf8_is_control(&utf8, &isAscii), ExtInvalidInput); ASSERT_FALSE(isAscii); ASSERT_TRUE(allOf( map(controlChars, [](char letter) { return FudUtf8::makeUtf8(ExtUtf8Char4{static_cast(letter)}); }), [](auto& utf8Letter) { bool predicate = false; auto isPredicateStatus = ext_lib_utf8_is_control(&utf8Letter, &predicate); return isPredicateStatus == ExtSuccess && predicate; })); ASSERT_FALSE(anyOf( map(nonControlChars, [](char letter) { return FudUtf8::makeUtf8(ExtUtf8Char4{static_cast(letter)}); }), [](auto& utf8Letter) { bool predicate = false; auto isPredicateStatus = ext_lib_utf8_is_control(&utf8Letter, &predicate); return isPredicateStatus != ExtSuccess || predicate; })); ASSERT_FALSE(allOf( map(nonControlChars, [](char letter) { return FudUtf8::makeUtf8(ExtUtf8Char4{static_cast(letter)}); }), [](auto& utf8Letter) { bool predicate = false; auto isPredicateStatus = ext_lib_utf8_is_control(&utf8Letter, &predicate); return isPredicateStatus == ExtInvalidInput && !predicate; })); } TEST(Utf8Test, Utf8IsGraphical) { constexpr size_t numGraphicalChars = sizeof(GRAPHICAL_CHARS) - 1; Array graphicalCharLiteral{GRAPHICAL_CHARS}; Array graphicalChars{}; copyMem(graphicalChars, graphicalCharLiteral); ASSERT_TRUE(allOf(graphicalChars, ext_lib_char_is_graphical)); auto graphicalSetResult{StaticSet::makeFromArray(graphicalChars)}; ASSERT_TRUE(graphicalSetResult.isOkay()); auto graphicalSet{std::move(graphicalSetResult.getOkay())}; constexpr size_t numNonGraphicalChars = validAsciiSize - numGraphicalChars; FixedVector nonGraphicalChars{}; for (char idx = 0; idx < INT8_MAX; ++idx) { if (!graphicalSet.isKey(idx)) { ASSERT_TRUE(nonGraphicalChars.pushBack(idx)); } } ASSERT_FALSE(anyOf(nonGraphicalChars, ext_lib_char_is_graphical)); auto invalidAsciiChars = generateInvalidAsciiChars(); ASSERT_FALSE(anyOf(invalidAsciiChars, ext_lib_char_is_graphical)); ASSERT_TRUE(allOf( map(graphicalChars, [](auto input) { return ExtUtf8Char4{static_cast(input)}; }), ext_lib_char4_is_graphical)); ASSERT_FALSE(anyOf( map(nonGraphicalChars, [](auto input) { return ExtUtf8Char4{static_cast(input)}; }), ext_lib_char4_is_graphical)); ASSERT_FALSE(anyOf( map(invalidAsciiChars, [](auto input) { return ExtUtf8Char4{static_cast(input)}; }), ext_lib_char4_is_graphical)); ASSERT_TRUE(allOf( map(graphicalChars, [](auto input) { return ExtUtf8Char4{static_cast(input)}; }), ext_lib_char4_is_graphical)); ASSERT_FALSE(anyOf( map(nonGraphicalChars, [](auto input) { return ExtUtf8Char4{static_cast(input)}; }), ext_lib_char4_is_graphical)); ASSERT_FALSE(anyOf( map(invalidAsciiChars, [](auto input) { return ExtUtf8Char4{static_cast(input)}; }), ext_lib_char4_is_graphical)); Utf8 utf8{invalidAscii}; bool isAscii = false; ASSERT_EQ(ext_lib_utf8_is_graphical(nullptr, nullptr), ExtNullPointer); ASSERT_EQ(ext_lib_utf8_is_graphical(&utf8, nullptr), ExtNullPointer); ASSERT_EQ(ext_lib_utf8_is_graphical(nullptr, &isAscii), ExtNullPointer); ASSERT_EQ(ext_lib_utf8_is_graphical(&utf8, &isAscii), ExtInvalidInput); ASSERT_FALSE(isAscii); ASSERT_TRUE(allOf( map(graphicalChars, [](char letter) { return FudUtf8::makeUtf8(ExtUtf8Char4{static_cast(letter)}); }), [](auto& utf8Letter) { bool predicate = false; auto isPredicateStatus = ext_lib_utf8_is_graphical(&utf8Letter, &predicate); return isPredicateStatus == ExtSuccess && predicate; })); ASSERT_FALSE(anyOf( map(nonGraphicalChars, [](char letter) { return FudUtf8::makeUtf8(ExtUtf8Char4{static_cast(letter)}); }), [](auto& utf8Letter) { bool predicate = false; auto isPredicateStatus = ext_lib_utf8_is_graphical(&utf8Letter, &predicate); return isPredicateStatus != ExtSuccess || predicate; })); ASSERT_FALSE(allOf( map(nonGraphicalChars, [](char letter) { return FudUtf8::makeUtf8(ExtUtf8Char4{static_cast(letter)}); }), [](auto& utf8Letter) { bool predicate = false; auto isPredicateStatus = ext_lib_utf8_is_graphical(&utf8Letter, &predicate); return isPredicateStatus == ExtInvalidInput && !predicate; })); } TEST(Utf8Test, Utf8IsSpace) { constexpr size_t numSpaceChars = sizeof(" \t\v\r\n") - 1; Array spaceCharLiteral{" \t\v\r\n"}; Array spaceChars{}; copyMem(spaceChars, spaceCharLiteral); ASSERT_TRUE(allOf(spaceChars, ext_lib_char_is_space)); auto spaceSetResult{StaticSet::makeFromArray(spaceChars)}; ASSERT_TRUE(spaceSetResult.isOkay()); auto spaceSet{std::move(spaceSetResult.getOkay())}; constexpr size_t numNonSpaceChars = validAsciiSize - numSpaceChars; FixedVector nonSpaceChars{}; for (char idx = 0; idx < INT8_MAX; ++idx) { if (!spaceSet.isKey(idx)) { ASSERT_TRUE(nonSpaceChars.pushBack(idx)); } } ASSERT_FALSE(anyOf(nonSpaceChars, ext_lib_char_is_space)); auto invalidAsciiChars = generateInvalidAsciiChars(); ASSERT_FALSE(anyOf(invalidAsciiChars, ext_lib_char_is_space)); ASSERT_TRUE(allOf( map(spaceChars, [](auto input) { return ExtUtf8Char4{static_cast(input)}; }), ext_lib_char4_is_space)); ASSERT_FALSE(anyOf( map(nonSpaceChars, [](auto input) { return ExtUtf8Char4{static_cast(input)}; }), ext_lib_char4_is_space)); ASSERT_FALSE(anyOf( map(invalidAsciiChars, [](auto input) { return ExtUtf8Char4{static_cast(input)}; }), ext_lib_char4_is_space)); ASSERT_TRUE(allOf( map(spaceChars, [](auto input) { return ExtUtf8Char4{static_cast(input)}; }), ext_lib_char4_is_space)); ASSERT_FALSE(anyOf( map(nonSpaceChars, [](auto input) { return ExtUtf8Char4{static_cast(input)}; }), ext_lib_char4_is_space)); ASSERT_FALSE(anyOf( map(invalidAsciiChars, [](auto input) { return ExtUtf8Char4{static_cast(input)}; }), ext_lib_char4_is_space)); Utf8 utf8{invalidAscii}; bool isAscii = false; ASSERT_EQ(ext_lib_utf8_is_space(nullptr, nullptr), ExtNullPointer); ASSERT_EQ(ext_lib_utf8_is_space(&utf8, nullptr), ExtNullPointer); ASSERT_EQ(ext_lib_utf8_is_space(nullptr, &isAscii), ExtNullPointer); ASSERT_EQ(ext_lib_utf8_is_space(&utf8, &isAscii), ExtInvalidInput); ASSERT_FALSE(isAscii); ASSERT_TRUE(allOf( map(spaceChars, [](char letter) { return FudUtf8::makeUtf8(ExtUtf8Char4{static_cast(letter)}); }), [](auto& utf8Letter) { bool predicate = false; auto isPredicateStatus = ext_lib_utf8_is_space(&utf8Letter, &predicate); return isPredicateStatus == ExtSuccess && predicate; })); ASSERT_FALSE(anyOf( map(nonSpaceChars, [](char letter) { return FudUtf8::makeUtf8(ExtUtf8Char4{static_cast(letter)}); }), [](auto& utf8Letter) { bool predicate = false; auto isPredicateStatus = ext_lib_utf8_is_space(&utf8Letter, &predicate); return isPredicateStatus != ExtSuccess || predicate; })); ASSERT_FALSE(allOf( map(nonSpaceChars, [](char letter) { return FudUtf8::makeUtf8(ExtUtf8Char4{static_cast(letter)}); }), [](auto& utf8Letter) { bool predicate = false; auto isPredicateStatus = ext_lib_utf8_is_space(&utf8Letter, &predicate); return isPredicateStatus == ExtInvalidInput && !predicate; })); } TEST(Utf8Test, Utf8IsBlank) { constexpr size_t numBlankChars = sizeof(" \t") - 1; Array blankCharLiteral{" \t"}; Array blankChars{}; copyMem(blankChars, blankCharLiteral); ASSERT_TRUE(allOf(blankChars, ext_lib_char_is_blank)); auto blankSetResult{StaticSet::makeFromArray(blankChars)}; ASSERT_TRUE(blankSetResult.isOkay()); auto blankSet{std::move(blankSetResult.getOkay())}; constexpr size_t numNonBlankChars = validAsciiSize - numBlankChars; FixedVector nonBlankChars{}; for (char idx = 0; idx < INT8_MAX; ++idx) { if (!blankSet.isKey(idx)) { ASSERT_TRUE(nonBlankChars.pushBack(idx)); } } ASSERT_FALSE(anyOf(nonBlankChars, ext_lib_char_is_blank)); auto invalidAsciiChars = generateInvalidAsciiChars(); ASSERT_FALSE(anyOf(invalidAsciiChars, ext_lib_char_is_blank)); ASSERT_TRUE(allOf( map(blankChars, [](auto input) { return ExtUtf8Char4{static_cast(input)}; }), ext_lib_char4_is_blank)); ASSERT_FALSE(anyOf( map(nonBlankChars, [](auto input) { return ExtUtf8Char4{static_cast(input)}; }), ext_lib_char4_is_blank)); ASSERT_FALSE(anyOf( map(invalidAsciiChars, [](auto input) { return ExtUtf8Char4{static_cast(input)}; }), ext_lib_char4_is_blank)); ASSERT_TRUE(allOf( map(blankChars, [](auto input) { return ExtUtf8Char4{static_cast(input)}; }), ext_lib_char4_is_blank)); ASSERT_FALSE(anyOf( map(nonBlankChars, [](auto input) { return ExtUtf8Char4{static_cast(input)}; }), ext_lib_char4_is_blank)); ASSERT_FALSE(anyOf( map(invalidAsciiChars, [](auto input) { return ExtUtf8Char4{static_cast(input)}; }), ext_lib_char4_is_blank)); Utf8 utf8{invalidAscii}; bool isAscii = false; ASSERT_EQ(ext_lib_utf8_is_blank(nullptr, nullptr), ExtNullPointer); ASSERT_EQ(ext_lib_utf8_is_blank(&utf8, nullptr), ExtNullPointer); ASSERT_EQ(ext_lib_utf8_is_blank(nullptr, &isAscii), ExtNullPointer); ASSERT_EQ(ext_lib_utf8_is_blank(&utf8, &isAscii), ExtInvalidInput); ASSERT_FALSE(isAscii); ASSERT_TRUE(allOf( map(blankChars, [](char letter) { return FudUtf8::makeUtf8(ExtUtf8Char4{static_cast(letter)}); }), [](auto& utf8Letter) { bool predicate = false; auto isPredicateStatus = ext_lib_utf8_is_blank(&utf8Letter, &predicate); return isPredicateStatus == ExtSuccess && predicate; })); ASSERT_FALSE(anyOf( map(nonBlankChars, [](char letter) { return FudUtf8::makeUtf8(ExtUtf8Char4{static_cast(letter)}); }), [](auto& utf8Letter) { bool predicate = false; auto isPredicateStatus = ext_lib_utf8_is_blank(&utf8Letter, &predicate); return isPredicateStatus != ExtSuccess || predicate; })); ASSERT_FALSE(allOf( map(nonBlankChars, [](char letter) { return FudUtf8::makeUtf8(ExtUtf8Char4{static_cast(letter)}); }), [](auto& utf8Letter) { bool predicate = false; auto isPredicateStatus = ext_lib_utf8_is_blank(&utf8Letter, &predicate); return isPredicateStatus == ExtInvalidInput && !predicate; })); } TEST(Utf8Test, Utf8IsPrintable) { constexpr size_t numPrintableChars = validAsciiSize - numControlChars; auto printableChars = generateIndexArray([](int idx) { return static_cast(idx + printableCharOffset); }); ASSERT_TRUE(allOf(printableChars, ext_lib_char_is_printable)); auto printableSetResult{StaticSet::makeFromArray(printableChars)}; ASSERT_TRUE(printableSetResult.isOkay()); auto printableSet{std::move(printableSetResult.getOkay())}; constexpr size_t numNonPrintableChars = validAsciiSize - numPrintableChars; FixedVector nonPrintableChars{}; for (char idx = 0; idx < INT8_MAX; ++idx) { if (!printableSet.isKey(idx)) { ASSERT_TRUE(nonPrintableChars.pushBack(idx)); } } ASSERT_FALSE(anyOf(nonPrintableChars, ext_lib_char_is_printable)); auto invalidAsciiChars = generateInvalidAsciiChars(); ASSERT_FALSE(anyOf(invalidAsciiChars, ext_lib_char_is_printable)); ASSERT_TRUE(allOf( map(printableChars, [](auto input) { return ExtUtf8Char4{static_cast(input)}; }), ext_lib_char4_is_printable)); ASSERT_FALSE(anyOf( map(nonPrintableChars, [](auto input) { return ExtUtf8Char4{static_cast(input)}; }), ext_lib_char4_is_printable)); ASSERT_FALSE(anyOf( map(invalidAsciiChars, [](auto input) { return ExtUtf8Char4{static_cast(input)}; }), ext_lib_char4_is_printable)); ASSERT_TRUE(allOf( map(printableChars, [](auto input) { return ExtUtf8Char4{static_cast(input)}; }), ext_lib_char4_is_printable)); ASSERT_FALSE(anyOf( map(nonPrintableChars, [](auto input) { return ExtUtf8Char4{static_cast(input)}; }), ext_lib_char4_is_printable)); ASSERT_FALSE(anyOf( map(invalidAsciiChars, [](auto input) { return ExtUtf8Char4{static_cast(input)}; }), ext_lib_char4_is_printable)); Utf8 utf8{invalidAscii}; bool isAscii = false; ASSERT_EQ(ext_lib_utf8_is_printable(nullptr, nullptr), ExtNullPointer); ASSERT_EQ(ext_lib_utf8_is_printable(&utf8, nullptr), ExtNullPointer); ASSERT_EQ(ext_lib_utf8_is_printable(nullptr, &isAscii), ExtNullPointer); ASSERT_EQ(ext_lib_utf8_is_printable(&utf8, &isAscii), ExtInvalidInput); ASSERT_FALSE(isAscii); ASSERT_TRUE(allOf( map(printableChars, [](char letter) { return FudUtf8::makeUtf8(ExtUtf8Char4{static_cast(letter)}); }), [](auto& utf8Letter) { bool predicate = false; auto isPredicateStatus = ext_lib_utf8_is_printable(&utf8Letter, &predicate); return isPredicateStatus == ExtSuccess && predicate; })); ASSERT_FALSE(anyOf( map(nonPrintableChars, [](char letter) { return FudUtf8::makeUtf8(ExtUtf8Char4{static_cast(letter)}); }), [](auto& utf8Letter) { bool predicate = false; auto isPredicateStatus = ext_lib_utf8_is_printable(&utf8Letter, &predicate); return isPredicateStatus != ExtSuccess || predicate; })); ASSERT_FALSE(allOf( map(nonPrintableChars, [](char letter) { return FudUtf8::makeUtf8(ExtUtf8Char4{static_cast(letter)}); }), [](auto& utf8Letter) { bool predicate = false; auto isPredicateStatus = ext_lib_utf8_is_printable(&utf8Letter, &predicate); return isPredicateStatus == ExtInvalidInput && !predicate; })); } TEST(Utf8Test, Utf8IsPunctuation) { constexpr size_t numPunctuationChars = sizeof(PUNCTUATION_CHARS) - 1; Array punctuationCharLiteral{PUNCTUATION_CHARS}; Array punctuationChars{}; copyMem(punctuationChars, punctuationCharLiteral); ASSERT_TRUE(allOf(punctuationChars, ext_lib_char_is_punctuation)); auto punctuationSetResult{StaticSet::makeFromArray(punctuationChars)}; ASSERT_TRUE(punctuationSetResult.isOkay()); auto punctuationSet{std::move(punctuationSetResult.getOkay())}; constexpr size_t numNonPunctuationChars = validAsciiSize - numPunctuationChars; FixedVector nonPunctuationChars{}; for (char idx = 0; idx < INT8_MAX; ++idx) { if (!punctuationSet.isKey(idx)) { ASSERT_TRUE(nonPunctuationChars.pushBack(idx)); } } ASSERT_FALSE(anyOf(nonPunctuationChars, ext_lib_char_is_punctuation)); auto invalidAsciiChars = generateInvalidAsciiChars(); ASSERT_FALSE(anyOf(invalidAsciiChars, ext_lib_char_is_punctuation)); ASSERT_TRUE(allOf( map(punctuationChars, [](auto input) { return ExtUtf8Char4{static_cast(input)}; }), ext_lib_char4_is_punctuation)); ASSERT_FALSE(anyOf( map(nonPunctuationChars, [](auto input) { return ExtUtf8Char4{static_cast(input)}; }), ext_lib_char4_is_punctuation)); ASSERT_FALSE(anyOf( map(invalidAsciiChars, [](auto input) { return ExtUtf8Char4{static_cast(input)}; }), ext_lib_char4_is_punctuation)); ASSERT_TRUE(allOf( map(punctuationChars, [](auto input) { return ExtUtf8Char4{static_cast(input)}; }), ext_lib_char4_is_punctuation)); ASSERT_FALSE(anyOf( map(nonPunctuationChars, [](auto input) { return ExtUtf8Char4{static_cast(input)}; }), ext_lib_char4_is_punctuation)); ASSERT_FALSE(anyOf( map(invalidAsciiChars, [](auto input) { return ExtUtf8Char4{static_cast(input)}; }), ext_lib_char4_is_punctuation)); Utf8 utf8{invalidAscii}; bool isAscii = false; ASSERT_EQ(ext_lib_utf8_is_punctuation(nullptr, nullptr), ExtNullPointer); ASSERT_EQ(ext_lib_utf8_is_punctuation(&utf8, nullptr), ExtNullPointer); ASSERT_EQ(ext_lib_utf8_is_punctuation(nullptr, &isAscii), ExtNullPointer); ASSERT_EQ(ext_lib_utf8_is_punctuation(&utf8, &isAscii), ExtInvalidInput); ASSERT_FALSE(isAscii); ASSERT_TRUE(allOf( map(punctuationChars, [](char letter) { return FudUtf8::makeUtf8(ExtUtf8Char4{static_cast(letter)}); }), [](auto& utf8Letter) { bool predicate = false; auto isPredicateStatus = ext_lib_utf8_is_punctuation(&utf8Letter, &predicate); return isPredicateStatus == ExtSuccess && predicate; })); ASSERT_FALSE(anyOf( map(nonPunctuationChars, [](char letter) { return FudUtf8::makeUtf8(ExtUtf8Char4{static_cast(letter)}); }), [](auto& utf8Letter) { bool predicate = false; auto isPredicateStatus = ext_lib_utf8_is_punctuation(&utf8Letter, &predicate); return isPredicateStatus != ExtSuccess || predicate; })); ASSERT_FALSE(allOf( map(nonPunctuationChars, [](char letter) { return FudUtf8::makeUtf8(ExtUtf8Char4{static_cast(letter)}); }), [](auto& utf8Letter) { bool predicate = false; auto isPredicateStatus = ext_lib_utf8_is_punctuation(&utf8Letter, &predicate); return isPredicateStatus == ExtInvalidInput && !predicate; })); } #endif } // namespace fud