From 6a27a2a4032e88fa9154ef0f0741edc584f7a701 Mon Sep 17 00:00:00 2001 From: Dominick Allen Date: Sun, 20 Oct 2024 10:48:19 -0500 Subject: Lots of work. --- test/CMakeLists.txt | 12 +- test/test_common.hpp | 11 +- test/test_format.cpp | 12 +- test/test_utf8.cpp | 1163 ++++++++++++++++++++++++++++++++++++++++++++++++++ 4 files changed, 1180 insertions(+), 18 deletions(-) create mode 100644 test/test_utf8.cpp (limited to 'test') 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::constFill('\0')}; - auto span = Span::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 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 -- cgit v1.2.3