diff options
Diffstat (limited to 'test')
-rw-r--r-- | test/CMakeLists.txt | 12 | ||||
-rw-r--r-- | test/test_common.hpp | 11 | ||||
-rw-r--r-- | test/test_format.cpp | 12 | ||||
-rw-r--r-- | test/test_utf8.cpp | 1163 |
4 files changed, 1180 insertions, 18 deletions
diff --git a/test/CMakeLists.txt b/test/CMakeLists.txt index 0860c0d..c4d957b 100644 --- a/test/CMakeLists.txt +++ b/test/CMakeLists.txt @@ -59,23 +59,17 @@ endfunction() fud_add_test(test_fud SOURCES test_fud.cpp) fud_add_test(test_allocator SOURCES test_allocator.cpp) fud_add_test(test_assert SOURCES test_assert.cpp) +# fud_add_test(test_c_file SOURCES test_c_file.cpp) fud_add_test(test_directory SOURCES test_directory.cpp) fud_add_test(test_format SOURCES test_format.cpp) fud_add_test(test_result SOURCES test_result.cpp) fud_add_test(test_span SOURCES test_span.cpp) fud_add_test(test_sqlite SOURCES test_sqlite.cpp) fud_add_test(test_string SOURCES test_string.cpp) +fud_add_test(test_utf8 SOURCES test_utf8.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 # test_ext_unique_array.cpp) -# fud_add_test(test_ext_utf8 SOURCES -# test_ext_utf8.cpp) -# fud_add_test(test_ext_string SOURCES -# test_ext_string.cpp -# test_ext_string_cxx.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.hpp b/test/test_common.hpp index 05f86db..0ca8eb4 100644 --- a/test/test_common.hpp +++ b/test/test_common.hpp @@ -34,7 +34,16 @@ static_assert(sizeof(THREE_BYTE) == 3 + 1); static_assert(sizeof(FOUR_BYTE) == 4 + 1); #define CHQUOTE "why waste time learning, when ignorance is instantaneous?" -#define CHARACTER_SET "abcdefghijklmnopqrstuvwxyz ABCDEFGHIJKLMNOPQRSTUVWXYZ" + +#define LOWERCASE_CHARS "abcdefghijklmnopqrstuvwxyz" +#define UPPERCASE_CHARS "ABCDEFGHIJKLMNOPQRSTUVWXYZ" +#define DECIMAL_CHARS "0123456789" +#define ALPHA_CHARS LOWERCASE_CHARS UPPERCASE_CHARS +#define ALPHA_NUMERIC_CHARS ALPHA_CHARS DECIMAL_CHARS +#define PUNCTUATION_CHARS "!\"#$%&'()*+,-./:;<=>?@[\\]^_`{|}~" +#define GRAPHICAL_CHARS ALPHA_NUMERIC_CHARS PUNCTUATION_CHARS +#define CHARACTER_SET LOWERCASE_CHARS " " UPPERCASE_CHARS + // NOLINTEND(cppcoreguidelines-macro-usage) constexpr size_t charSetSize = sizeof(CHARACTER_SET) - 1; diff --git a/test/test_format.cpp b/test/test_format.cpp index a373fec..319ed22 100644 --- a/test/test_format.cpp +++ b/test/test_format.cpp @@ -15,21 +15,17 @@ * limitations under the License. */ -#include "fud_array.hpp" -#include "fud_format.hpp" -#include "fud_span.hpp" +// #include "fud_array.hpp" +// #include "fud_format.hpp" +// #include "fud_span.hpp" #include "gtest/gtest.h" namespace fud { -TEST(FormatTest, BasicTest) +TEST(FormatTest, FormatSpecTest) { - auto buffer{Array<char, 64>::constFill('\0')}; - auto span = Span<char, buffer.size() - 1U>::makeCStringBuffer(buffer); - auto formatResult = format(span, "Hello, {}! {}", "world", 42); - printf("%s\n", buffer.data()); } } // namespace fud diff --git a/test/test_utf8.cpp b/test/test_utf8.cpp new file mode 100644 index 0000000..8f1d655 --- /dev/null +++ b/test/test_utf8.cpp @@ -0,0 +1,1163 @@ +/* + * 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<utf8> iota{}; + return generate([]() { return Array<utf8, invalidAsciiSize>{}; }, [&]() { return iota().value(); }); +} + +TEST(Utf8Test, Utf8Creation) +{ + const Array<utf8, 4> 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<utf8, 4> asciiLetter = {'A'}; + utf8Point = FudUtf8::make(asciiLetter); + ASSERT_NE(utf8Point.data(), nullptr); + ASSERT_EQ(utf8Point.size(), 1); + + const Array<utf8, 4> twoByte = {TWO_BYTE}; + utf8Point = FudUtf8::make(twoByte); + ASSERT_NE(utf8Point.data(), nullptr); + ASSERT_EQ(utf8Point.size(), 2); + ASSERT_NE(utf8Point.hash(), -1); + + Array<utf8, 4> fourByte = { + static_cast<utf8>(FOUR_BYTE[0]), + static_cast<utf8>(FOUR_BYTE[1]), + static_cast<utf8>(FOUR_BYTE[2]), + static_cast<utf8>(FOUR_BYTE[3])}; + utf8Point = FudUtf8::make(fourByte); + ASSERT_NE(utf8Point.data(), nullptr); + ASSERT_EQ(utf8Point.size(), 4); + ASSERT_NE(utf8Point.hash(), -1); + + const Array<utf8, 4> 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<utf8, sizeof(MULTI_BYTE_LITERAL)> data{MULTI_BYTE_LITERAL}; + constexpr size_t bufSize = data.size(); + EXPECT_EQ(data[bufSize - 1], '\0'); + + class FixedAllocator final : public Allocator { + private: + Array<utf8, bufSize> m_memory{}; + size_t m_allocated{0}; + + public: + virtual ~FixedAllocator() override final = default; + + virtual Result<void*, FudStatus> allocate(size_t bytes, size_t alignment) override final + { + static_cast<void>(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<void>(pointer); + static_cast<void>(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<FudUtf8, 16> 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<int>(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<int16_t> charIota{0, 1, validAsciiSize}; + + ASSERT_TRUE(allOf( + [&]() -> std::optional<char> { + auto value = charIota(); + return value ? std::optional<char>(static_cast<char>(*value)) : std::nullopt; + }, + charIsAscii)); + + Iota<int16_t> invalidCharIota{validAsciiSize, 1, invalidAsciiSize}; + + ASSERT_FALSE(anyOf( + [&]() -> std::optional<char> { + auto value = invalidCharIota(); + return value ? std::optional<char>(static_cast<char>(*value)) : std::nullopt; + }, + charIsAscii)); + + FudUtf8 unicode{FudUtf8::invalidAscii()}; + ASSERT_FALSE(utf8IsAscii(unicode)); + + charIota.set(0); + ASSERT_TRUE(allOf( + [&]() -> std::optional<FudUtf8> { + auto value = charIota(); + return value ? std::optional<FudUtf8>(FudUtf8::make(static_cast<utf8>(*value))) : std::nullopt; + }, + utf8IsAscii)); + + invalidCharIota.set(invalidAsciiSize); + ASSERT_FALSE(anyOf( + [&]() -> std::optional<FudUtf8> { + auto value = invalidCharIota(); + return value ? std::optional<FudUtf8>(FudUtf8::make(static_cast<utf8>(*value))) : std::nullopt; + }, + utf8IsAscii)); +} + +TEST(Utf8Test, Utf8IsAlphaNumeric) +{ + constexpr size_t numAlphaNumericChars = 26 * 2 + 10; + Array<char, numAlphaNumericChars + 1> alphaNumericCharLiteral{ALPHA_NUMERIC_CHARS}; + Array<char, numAlphaNumericChars> alphaNumericChars{}; + copyMem<numAlphaNumericChars>(alphaNumericChars, alphaNumericCharLiteral); +#if 0 + ASSERT_TRUE(allOf(alphaNumericChars, charIsAlphanumeric)); + + auto alphaNumericSetResult{StaticSet<char, numAlphaNumericChars>::makeFromArray(alphaNumericChars)}; + ASSERT_TRUE(alphaNumericSetResult.isOkay()); + auto alphaNumericSet{std::move(alphaNumericSetResult.getOkay())}; + + constexpr size_t numNonAlphaNumericChars = validAsciiSize - numAlphaNumericChars; + FixedVector<char, numNonAlphaNumericChars> 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<utf8>(input)}; }), + ext_lib_char4_is_alphanumeric)); + ASSERT_FALSE(anyOf( + map(nonAlphaNumericChars, [](auto input) { return ExtUtf8Char4{static_cast<utf8>(input)}; }), + ext_lib_char4_is_alphanumeric)); + ASSERT_FALSE(anyOf( + map(invalidAsciiChars, [](auto input) { return ExtUtf8Char4{static_cast<utf8>(input)}; }), + ext_lib_char4_is_alphanumeric)); + + ASSERT_TRUE(allOf( + map(alphaNumericChars, [](auto input) { return ExtUtf8Char4{static_cast<utf8>(input)}; }), + ext_lib_char4_is_alphanumeric)); + ASSERT_FALSE(anyOf( + map(nonAlphaNumericChars, [](auto input) { return ExtUtf8Char4{static_cast<utf8>(input)}; }), + ext_lib_char4_is_alphanumeric)); + ASSERT_FALSE(anyOf( + map(invalidAsciiChars, [](auto input) { return ExtUtf8Char4{static_cast<utf8>(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<utf8>(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<utf8>(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<utf8>(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<char, numAlphaChars + 1> alphaCharLiteral{ALPHA_CHARS}; + Array<char, numAlphaChars> alphaChars{}; + copyMem<numAlphaChars>(alphaChars, alphaCharLiteral); + + ASSERT_TRUE(allOf(alphaChars, ext_lib_char_is_alpha)); + + auto alphaSetResult{StaticSet<char, numAlphaChars>::makeFromArray(alphaChars)}; + ASSERT_TRUE(alphaSetResult.isOkay()); + auto alphaSet{std::move(alphaSetResult.getOkay())}; + + constexpr size_t numNonAlphaChars = validAsciiSize - numAlphaChars; + FixedVector<char, numNonAlphaChars> 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<utf8>(input)}; }), + ext_lib_char4_is_alpha)); + ASSERT_FALSE(anyOf( + map(nonAlphaChars, [](auto input) { return ExtUtf8Char4{static_cast<utf8>(input)}; }), + ext_lib_char4_is_alpha)); + ASSERT_FALSE(anyOf( + map(invalidAsciiChars, [](auto input) { return ExtUtf8Char4{static_cast<utf8>(input)}; }), + ext_lib_char4_is_alpha)); + + ASSERT_TRUE(allOf( + map(alphaChars, [](auto input) { return ExtUtf8Char4{static_cast<utf8>(input)}; }), + ext_lib_char4_is_alpha)); + ASSERT_FALSE(anyOf( + map(nonAlphaChars, [](auto input) { return ExtUtf8Char4{static_cast<utf8>(input)}; }), + ext_lib_char4_is_alpha)); + ASSERT_FALSE(anyOf( + map(invalidAsciiChars, [](auto input) { return ExtUtf8Char4{static_cast<utf8>(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<utf8>(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<utf8>(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<utf8>(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<char, numLowerChars + 1> lowerCharLiteral{LOWERCASE_CHARS}; + Array<char, numLowerChars> lowerChars{}; + copyMem<numLowerChars>(lowerChars, lowerCharLiteral); + + ASSERT_TRUE(allOf(lowerChars, ext_lib_char_is_lowercase)); + + auto lowerSetResult{StaticSet<char, numLowerChars>::makeFromArray(lowerChars)}; + ASSERT_TRUE(lowerSetResult.isOkay()); + auto lowerSet{std::move(lowerSetResult.getOkay())}; + + constexpr size_t numNonLowerChars = validAsciiSize - numLowerChars; + FixedVector<char, numNonLowerChars> 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<utf8>(input)}; }), + ext_lib_char4_is_lowercase)); + ASSERT_FALSE(anyOf( + map(nonLowerChars, [](auto input) { return ExtUtf8Char4{static_cast<utf8>(input)}; }), + ext_lib_char4_is_lowercase)); + ASSERT_FALSE(anyOf( + map(invalidAsciiChars, [](auto input) { return ExtUtf8Char4{static_cast<utf8>(input)}; }), + ext_lib_char4_is_lowercase)); + + ASSERT_TRUE(allOf( + map(lowerChars, [](auto input) { return ExtUtf8Char4{static_cast<utf8>(input)}; }), + ext_lib_char4_is_lowercase)); + ASSERT_FALSE(anyOf( + map(nonLowerChars, [](auto input) { return ExtUtf8Char4{static_cast<utf8>(input)}; }), + ext_lib_char4_is_lowercase)); + ASSERT_FALSE(anyOf( + map(invalidAsciiChars, [](auto input) { return ExtUtf8Char4{static_cast<utf8>(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<utf8>(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<utf8>(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<utf8>(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<char, numUpperChars + 1> upperCharLiteral{UPPERCASE_CHARS}; + Array<char, numUpperChars> upperChars{}; + copyMem<numUpperChars>(upperChars, upperCharLiteral); + + ASSERT_TRUE(allOf(upperChars, ext_lib_char_is_uppercase)); + + auto upperSetResult{StaticSet<char, numUpperChars>::makeFromArray(upperChars)}; + ASSERT_TRUE(upperSetResult.isOkay()); + auto upperSet{std::move(upperSetResult.getOkay())}; + + constexpr size_t numNonUpperChars = validAsciiSize - numUpperChars; + FixedVector<char, numNonUpperChars> 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<utf8>(input)}; }), + ext_lib_char4_is_uppercase)); + ASSERT_FALSE(anyOf( + map(nonUpperChars, [](auto input) { return ExtUtf8Char4{static_cast<utf8>(input)}; }), + ext_lib_char4_is_uppercase)); + ASSERT_FALSE(anyOf( + map(invalidAsciiChars, [](auto input) { return ExtUtf8Char4{static_cast<utf8>(input)}; }), + ext_lib_char4_is_uppercase)); + + ASSERT_TRUE(allOf( + map(upperChars, [](auto input) { return ExtUtf8Char4{static_cast<utf8>(input)}; }), + ext_lib_char4_is_uppercase)); + ASSERT_FALSE(anyOf( + map(nonUpperChars, [](auto input) { return ExtUtf8Char4{static_cast<utf8>(input)}; }), + ext_lib_char4_is_uppercase)); + ASSERT_FALSE(anyOf( + map(invalidAsciiChars, [](auto input) { return ExtUtf8Char4{static_cast<utf8>(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<utf8>(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<utf8>(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<utf8>(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<char, numDigitChars + 1> digitCharLiteral{"0123456789"}; + Array<char, numDigitChars> digitChars{}; + copyMem<numDigitChars>(digitChars, digitCharLiteral); + + ASSERT_TRUE(allOf(digitChars, ext_lib_char_is_digit)); + + auto digitSetResult{StaticSet<char, numDigitChars>::makeFromArray(digitChars)}; + ASSERT_TRUE(digitSetResult.isOkay()); + auto digitSet{std::move(digitSetResult.getOkay())}; + + constexpr size_t numNonDigitChars = validAsciiSize - numDigitChars; + FixedVector<char, numNonDigitChars> 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<utf8>(input)}; }), + ext_lib_char4_is_digit)); + ASSERT_FALSE(anyOf( + map(nonDigitChars, [](auto input) { return ExtUtf8Char4{static_cast<utf8>(input)}; }), + ext_lib_char4_is_digit)); + ASSERT_FALSE(anyOf( + map(invalidAsciiChars, [](auto input) { return ExtUtf8Char4{static_cast<utf8>(input)}; }), + ext_lib_char4_is_digit)); + + ASSERT_TRUE(allOf( + map(digitChars, [](auto input) { return ExtUtf8Char4{static_cast<utf8>(input)}; }), + ext_lib_char4_is_digit)); + ASSERT_FALSE(anyOf( + map(nonDigitChars, [](auto input) { return ExtUtf8Char4{static_cast<utf8>(input)}; }), + ext_lib_char4_is_digit)); + ASSERT_FALSE(anyOf( + map(invalidAsciiChars, [](auto input) { return ExtUtf8Char4{static_cast<utf8>(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<utf8>(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<utf8>(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<utf8>(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<char, numHexDigitChars + 1> hexDigitCharLiteral{"abcdefABCDEF0123456789"}; + Array<char, numHexDigitChars> hexDigitChars{}; + copyMem<numHexDigitChars>(hexDigitChars, hexDigitCharLiteral); + + ASSERT_TRUE(allOf(hexDigitChars, ext_lib_char_is_hex_digit)); + + auto hexDigitSetResult{StaticSet<char, numHexDigitChars>::makeFromArray(hexDigitChars)}; + ASSERT_TRUE(hexDigitSetResult.isOkay()); + auto hexDigitSet{std::move(hexDigitSetResult.getOkay())}; + + constexpr size_t numNonHexDigitChars = validAsciiSize - numHexDigitChars; + FixedVector<char, numNonHexDigitChars> 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<utf8>(input)}; }), + ext_lib_char4_is_hex_digit)); + ASSERT_FALSE(anyOf( + map(nonHexDigitChars, [](auto input) { return ExtUtf8Char4{static_cast<utf8>(input)}; }), + ext_lib_char4_is_hex_digit)); + ASSERT_FALSE(anyOf( + map(invalidAsciiChars, [](auto input) { return ExtUtf8Char4{static_cast<utf8>(input)}; }), + ext_lib_char4_is_hex_digit)); + + ASSERT_TRUE(allOf( + map(hexDigitChars, [](auto input) { return ExtUtf8Char4{static_cast<utf8>(input)}; }), + ext_lib_char4_is_hex_digit)); + ASSERT_FALSE(anyOf( + map(nonHexDigitChars, [](auto input) { return ExtUtf8Char4{static_cast<utf8>(input)}; }), + ext_lib_char4_is_hex_digit)); + ASSERT_FALSE(anyOf( + map(invalidAsciiChars, [](auto input) { return ExtUtf8Char4{static_cast<utf8>(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<utf8>(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<utf8>(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<utf8>(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<Array, char, numControlChars>([](int idx) { return static_cast<char>(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<Array, char, numControlChars>([](int idx) { + return static_cast<char>(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<utf8>(input)}; }), + ext_lib_char4_is_control)); + ASSERT_FALSE(anyOf( + map(nonControlChars, [](auto input) { return ExtUtf8Char4{static_cast<utf8>(input)}; }), + ext_lib_char4_is_control)); + ASSERT_FALSE(anyOf( + map(invalidAsciiChars, [](auto input) { return ExtUtf8Char4{static_cast<utf8>(input)}; }), + ext_lib_char4_is_control)); + + ASSERT_TRUE(allOf( + map(controlChars, [](auto input) { return ExtUtf8Char4{static_cast<utf8>(input)}; }), + ext_lib_char4_is_control)); + ASSERT_FALSE(anyOf( + map(nonControlChars, [](auto input) { return ExtUtf8Char4{static_cast<utf8>(input)}; }), + ext_lib_char4_is_control)); + ASSERT_FALSE(anyOf( + map(invalidAsciiChars, [](auto input) { return ExtUtf8Char4{static_cast<utf8>(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<utf8>(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<utf8>(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<utf8>(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<char, numGraphicalChars + 1> graphicalCharLiteral{GRAPHICAL_CHARS}; + Array<char, numGraphicalChars> graphicalChars{}; + copyMem<numGraphicalChars>(graphicalChars, graphicalCharLiteral); + + ASSERT_TRUE(allOf(graphicalChars, ext_lib_char_is_graphical)); + + auto graphicalSetResult{StaticSet<char, numGraphicalChars>::makeFromArray(graphicalChars)}; + ASSERT_TRUE(graphicalSetResult.isOkay()); + auto graphicalSet{std::move(graphicalSetResult.getOkay())}; + + constexpr size_t numNonGraphicalChars = validAsciiSize - numGraphicalChars; + FixedVector<char, numNonGraphicalChars> 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<utf8>(input)}; }), + ext_lib_char4_is_graphical)); + ASSERT_FALSE(anyOf( + map(nonGraphicalChars, [](auto input) { return ExtUtf8Char4{static_cast<utf8>(input)}; }), + ext_lib_char4_is_graphical)); + ASSERT_FALSE(anyOf( + map(invalidAsciiChars, [](auto input) { return ExtUtf8Char4{static_cast<utf8>(input)}; }), + ext_lib_char4_is_graphical)); + + ASSERT_TRUE(allOf( + map(graphicalChars, [](auto input) { return ExtUtf8Char4{static_cast<utf8>(input)}; }), + ext_lib_char4_is_graphical)); + ASSERT_FALSE(anyOf( + map(nonGraphicalChars, [](auto input) { return ExtUtf8Char4{static_cast<utf8>(input)}; }), + ext_lib_char4_is_graphical)); + ASSERT_FALSE(anyOf( + map(invalidAsciiChars, [](auto input) { return ExtUtf8Char4{static_cast<utf8>(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<utf8>(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<utf8>(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<utf8>(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<char, numSpaceChars + 1> spaceCharLiteral{" \t\v\r\n"}; + Array<char, numSpaceChars> spaceChars{}; + copyMem<numSpaceChars>(spaceChars, spaceCharLiteral); + + ASSERT_TRUE(allOf(spaceChars, ext_lib_char_is_space)); + + auto spaceSetResult{StaticSet<char, numSpaceChars>::makeFromArray(spaceChars)}; + ASSERT_TRUE(spaceSetResult.isOkay()); + auto spaceSet{std::move(spaceSetResult.getOkay())}; + + constexpr size_t numNonSpaceChars = validAsciiSize - numSpaceChars; + FixedVector<char, numNonSpaceChars> 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<utf8>(input)}; }), + ext_lib_char4_is_space)); + ASSERT_FALSE(anyOf( + map(nonSpaceChars, [](auto input) { return ExtUtf8Char4{static_cast<utf8>(input)}; }), + ext_lib_char4_is_space)); + ASSERT_FALSE(anyOf( + map(invalidAsciiChars, [](auto input) { return ExtUtf8Char4{static_cast<utf8>(input)}; }), + ext_lib_char4_is_space)); + + ASSERT_TRUE(allOf( + map(spaceChars, [](auto input) { return ExtUtf8Char4{static_cast<utf8>(input)}; }), + ext_lib_char4_is_space)); + ASSERT_FALSE(anyOf( + map(nonSpaceChars, [](auto input) { return ExtUtf8Char4{static_cast<utf8>(input)}; }), + ext_lib_char4_is_space)); + ASSERT_FALSE(anyOf( + map(invalidAsciiChars, [](auto input) { return ExtUtf8Char4{static_cast<utf8>(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<utf8>(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<utf8>(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<utf8>(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<char, numBlankChars + 1> blankCharLiteral{" \t"}; + Array<char, numBlankChars> blankChars{}; + copyMem<numBlankChars>(blankChars, blankCharLiteral); + + ASSERT_TRUE(allOf(blankChars, ext_lib_char_is_blank)); + + auto blankSetResult{StaticSet<char, numBlankChars>::makeFromArray(blankChars)}; + ASSERT_TRUE(blankSetResult.isOkay()); + auto blankSet{std::move(blankSetResult.getOkay())}; + + constexpr size_t numNonBlankChars = validAsciiSize - numBlankChars; + FixedVector<char, numNonBlankChars> 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<utf8>(input)}; }), + ext_lib_char4_is_blank)); + ASSERT_FALSE(anyOf( + map(nonBlankChars, [](auto input) { return ExtUtf8Char4{static_cast<utf8>(input)}; }), + ext_lib_char4_is_blank)); + ASSERT_FALSE(anyOf( + map(invalidAsciiChars, [](auto input) { return ExtUtf8Char4{static_cast<utf8>(input)}; }), + ext_lib_char4_is_blank)); + + ASSERT_TRUE(allOf( + map(blankChars, [](auto input) { return ExtUtf8Char4{static_cast<utf8>(input)}; }), + ext_lib_char4_is_blank)); + ASSERT_FALSE(anyOf( + map(nonBlankChars, [](auto input) { return ExtUtf8Char4{static_cast<utf8>(input)}; }), + ext_lib_char4_is_blank)); + ASSERT_FALSE(anyOf( + map(invalidAsciiChars, [](auto input) { return ExtUtf8Char4{static_cast<utf8>(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<utf8>(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<utf8>(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<utf8>(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<Array, char, numPrintableChars>([](int idx) { + return static_cast<char>(idx + printableCharOffset); + }); + + ASSERT_TRUE(allOf(printableChars, ext_lib_char_is_printable)); + + auto printableSetResult{StaticSet<char, numPrintableChars>::makeFromArray(printableChars)}; + ASSERT_TRUE(printableSetResult.isOkay()); + auto printableSet{std::move(printableSetResult.getOkay())}; + + constexpr size_t numNonPrintableChars = validAsciiSize - numPrintableChars; + FixedVector<char, numNonPrintableChars> 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<utf8>(input)}; }), + ext_lib_char4_is_printable)); + ASSERT_FALSE(anyOf( + map(nonPrintableChars, [](auto input) { return ExtUtf8Char4{static_cast<utf8>(input)}; }), + ext_lib_char4_is_printable)); + ASSERT_FALSE(anyOf( + map(invalidAsciiChars, [](auto input) { return ExtUtf8Char4{static_cast<utf8>(input)}; }), + ext_lib_char4_is_printable)); + + ASSERT_TRUE(allOf( + map(printableChars, [](auto input) { return ExtUtf8Char4{static_cast<utf8>(input)}; }), + ext_lib_char4_is_printable)); + ASSERT_FALSE(anyOf( + map(nonPrintableChars, [](auto input) { return ExtUtf8Char4{static_cast<utf8>(input)}; }), + ext_lib_char4_is_printable)); + ASSERT_FALSE(anyOf( + map(invalidAsciiChars, [](auto input) { return ExtUtf8Char4{static_cast<utf8>(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<utf8>(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<utf8>(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<utf8>(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<char, numPunctuationChars + 1> punctuationCharLiteral{PUNCTUATION_CHARS}; + Array<char, numPunctuationChars> punctuationChars{}; + copyMem<numPunctuationChars>(punctuationChars, punctuationCharLiteral); + + ASSERT_TRUE(allOf(punctuationChars, ext_lib_char_is_punctuation)); + + auto punctuationSetResult{StaticSet<char, numPunctuationChars>::makeFromArray(punctuationChars)}; + ASSERT_TRUE(punctuationSetResult.isOkay()); + auto punctuationSet{std::move(punctuationSetResult.getOkay())}; + + constexpr size_t numNonPunctuationChars = validAsciiSize - numPunctuationChars; + FixedVector<char, numNonPunctuationChars> 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<utf8>(input)}; }), + ext_lib_char4_is_punctuation)); + ASSERT_FALSE(anyOf( + map(nonPunctuationChars, [](auto input) { return ExtUtf8Char4{static_cast<utf8>(input)}; }), + ext_lib_char4_is_punctuation)); + ASSERT_FALSE(anyOf( + map(invalidAsciiChars, [](auto input) { return ExtUtf8Char4{static_cast<utf8>(input)}; }), + ext_lib_char4_is_punctuation)); + + ASSERT_TRUE(allOf( + map(punctuationChars, [](auto input) { return ExtUtf8Char4{static_cast<utf8>(input)}; }), + ext_lib_char4_is_punctuation)); + ASSERT_FALSE(anyOf( + map(nonPunctuationChars, [](auto input) { return ExtUtf8Char4{static_cast<utf8>(input)}; }), + ext_lib_char4_is_punctuation)); + ASSERT_FALSE(anyOf( + map(invalidAsciiChars, [](auto input) { return ExtUtf8Char4{static_cast<utf8>(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<utf8>(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<utf8>(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<utf8>(letter)}); }), + [](auto& utf8Letter) { + bool predicate = false; + auto isPredicateStatus = ext_lib_utf8_is_punctuation(&utf8Letter, &predicate); + return isPredicateStatus == ExtInvalidInput && !predicate; + })); +} +#endif + +} // namespace fud |