| File: | root/firefox-clang/mfbt/tests/TestUtf8.cpp |
| Warning: | line 179, column 9 The left operand of '==' is a garbage value |
Press '?' to see keyboard shortcuts
Keyboard shortcuts:
| 1 | /* This Source Code Form is subject to the terms of the Mozilla Public | |||
| 2 | * License, v. 2.0. If a copy of the MPL was not distributed with this | |||
| 3 | * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ | |||
| 4 | ||||
| 5 | #define MOZ_PRETEND_NO_JSRUST1 1 | |||
| 6 | ||||
| 7 | #include "mozilla/Assertions.h" | |||
| 8 | #include "mozilla/EnumSet.h" | |||
| 9 | #include "mozilla/IntegerRange.h" | |||
| 10 | #include "mozilla/Span.h" | |||
| 11 | #include "mozilla/Utf8.h" | |||
| 12 | ||||
| 13 | using mozilla::AsChars; | |||
| 14 | using mozilla::DecodeOneUtf8CodePoint; | |||
| 15 | using mozilla::EnumSet; | |||
| 16 | using mozilla::IntegerRange; | |||
| 17 | using mozilla::IsAscii; | |||
| 18 | using mozilla::IsUtf8; | |||
| 19 | using mozilla::Span; | |||
| 20 | using mozilla::Utf8Unit; | |||
| 21 | ||||
| 22 | static void TestUtf8Unit() { | |||
| 23 | Utf8Unit c('A'); | |||
| 24 | MOZ_RELEASE_ASSERT(c.toChar() == 'A')do { static_assert( mozilla::detail::AssertionConditionType< decltype(c.toChar() == 'A')>::isValid, "invalid assertion condition" ); if ((__builtin_expect(!!(!(!!(c.toChar() == 'A'))), 0))) { do { } while (false); MOZ_ReportAssertionFailure("c.toChar() == 'A'" , "/root/firefox-clang/mfbt/tests/TestUtf8.cpp", 24); do { } while (false); do { MOZ_CrashSequence(__null, 24); __attribute__(( nomerge)) ::abort(); } while (false); } } while (false); | |||
| 25 | MOZ_RELEASE_ASSERT(c == Utf8Unit('A'))do { static_assert( mozilla::detail::AssertionConditionType< decltype(c == Utf8Unit('A'))>::isValid, "invalid assertion condition" ); if ((__builtin_expect(!!(!(!!(c == Utf8Unit('A')))), 0))) { do { } while (false); MOZ_ReportAssertionFailure("c == Utf8Unit('A')" , "/root/firefox-clang/mfbt/tests/TestUtf8.cpp", 25); do { } while (false); do { MOZ_CrashSequence(__null, 25); __attribute__(( nomerge)) ::abort(); } while (false); } } while (false); | |||
| 26 | MOZ_RELEASE_ASSERT(c != Utf8Unit('B'))do { static_assert( mozilla::detail::AssertionConditionType< decltype(c != Utf8Unit('B'))>::isValid, "invalid assertion condition" ); if ((__builtin_expect(!!(!(!!(c != Utf8Unit('B')))), 0))) { do { } while (false); MOZ_ReportAssertionFailure("c != Utf8Unit('B')" , "/root/firefox-clang/mfbt/tests/TestUtf8.cpp", 26); do { } while (false); do { MOZ_CrashSequence(__null, 26); __attribute__(( nomerge)) ::abort(); } while (false); } } while (false); | |||
| 27 | MOZ_RELEASE_ASSERT(c.toUint8() == 0x41)do { static_assert( mozilla::detail::AssertionConditionType< decltype(c.toUint8() == 0x41)>::isValid, "invalid assertion condition" ); if ((__builtin_expect(!!(!(!!(c.toUint8() == 0x41))), 0))) { do { } while (false); MOZ_ReportAssertionFailure("c.toUint8() == 0x41" , "/root/firefox-clang/mfbt/tests/TestUtf8.cpp", 27); do { } while (false); do { MOZ_CrashSequence(__null, 27); __attribute__(( nomerge)) ::abort(); } while (false); } } while (false); | |||
| 28 | ||||
| 29 | unsigned char asUnsigned = 'A'; | |||
| 30 | MOZ_RELEASE_ASSERT(c.toUnsignedChar() == asUnsigned)do { static_assert( mozilla::detail::AssertionConditionType< decltype(c.toUnsignedChar() == asUnsigned)>::isValid, "invalid assertion condition" ); if ((__builtin_expect(!!(!(!!(c.toUnsignedChar() == asUnsigned ))), 0))) { do { } while (false); MOZ_ReportAssertionFailure( "c.toUnsignedChar() == asUnsigned", "/root/firefox-clang/mfbt/tests/TestUtf8.cpp" , 30); do { } while (false); do { MOZ_CrashSequence(__null, 30 ); __attribute__((nomerge)) ::abort(); } while (false); } } while (false); | |||
| 31 | MOZ_RELEASE_ASSERT(Utf8Unit('B').toUnsignedChar() != asUnsigned)do { static_assert( mozilla::detail::AssertionConditionType< decltype(Utf8Unit('B').toUnsignedChar() != asUnsigned)>::isValid , "invalid assertion condition"); if ((__builtin_expect(!!(!( !!(Utf8Unit('B').toUnsignedChar() != asUnsigned))), 0))) { do { } while (false); MOZ_ReportAssertionFailure("Utf8Unit('B').toUnsignedChar() != asUnsigned" , "/root/firefox-clang/mfbt/tests/TestUtf8.cpp", 31); do { } while (false); do { MOZ_CrashSequence(__null, 31); __attribute__(( nomerge)) ::abort(); } while (false); } } while (false); | |||
| 32 | ||||
| 33 | Utf8Unit first('@'); | |||
| 34 | Utf8Unit second('#'); | |||
| 35 | ||||
| 36 | MOZ_RELEASE_ASSERT(first != second)do { static_assert( mozilla::detail::AssertionConditionType< decltype(first != second)>::isValid, "invalid assertion condition" ); if ((__builtin_expect(!!(!(!!(first != second))), 0))) { do { } while (false); MOZ_ReportAssertionFailure("first != second" , "/root/firefox-clang/mfbt/tests/TestUtf8.cpp", 36); do { } while (false); do { MOZ_CrashSequence(__null, 36); __attribute__(( nomerge)) ::abort(); } while (false); } } while (false); | |||
| 37 | ||||
| 38 | first = second; | |||
| 39 | MOZ_RELEASE_ASSERT(first == second)do { static_assert( mozilla::detail::AssertionConditionType< decltype(first == second)>::isValid, "invalid assertion condition" ); if ((__builtin_expect(!!(!(!!(first == second))), 0))) { do { } while (false); MOZ_ReportAssertionFailure("first == second" , "/root/firefox-clang/mfbt/tests/TestUtf8.cpp", 39); do { } while (false); do { MOZ_CrashSequence(__null, 39); __attribute__(( nomerge)) ::abort(); } while (false); } } while (false); | |||
| 40 | } | |||
| 41 | ||||
| 42 | template <typename Char> | |||
| 43 | struct ToUtf8Units { | |||
| 44 | public: | |||
| 45 | explicit ToUtf8Units(const Char* aStart, const Char* aEnd) | |||
| 46 | : lead(Utf8Unit(aStart[0])), iter(aStart + 1), end(aEnd) { | |||
| 47 | MOZ_RELEASE_ASSERT(!IsAscii(aStart[0]))do { static_assert( mozilla::detail::AssertionConditionType< decltype(!IsAscii(aStart[0]))>::isValid, "invalid assertion condition" ); if ((__builtin_expect(!!(!(!!(!IsAscii(aStart[0])))), 0))) { do { } while (false); MOZ_ReportAssertionFailure("!IsAscii(aStart[0])" , "/root/firefox-clang/mfbt/tests/TestUtf8.cpp", 47); do { } while (false); do { MOZ_CrashSequence(__null, 47); __attribute__(( nomerge)) ::abort(); } while (false); } } while (false); | |||
| 48 | } | |||
| 49 | ||||
| 50 | const Utf8Unit lead; | |||
| 51 | const Char* iter; | |||
| 52 | const Char* const end; | |||
| 53 | }; | |||
| 54 | ||||
| 55 | class AssertIfCalled { | |||
| 56 | public: | |||
| 57 | template <typename... Args> | |||
| 58 | void operator()(Args&&... aArgs) { | |||
| 59 | MOZ_RELEASE_ASSERT(false, "AssertIfCalled instance was called")do { static_assert( mozilla::detail::AssertionConditionType< decltype(false)>::isValid, "invalid assertion condition"); if ((__builtin_expect(!!(!(!!(false))), 0))) { do { } while ( false); MOZ_ReportAssertionFailure("false" " (" "AssertIfCalled instance was called" ")", "/root/firefox-clang/mfbt/tests/TestUtf8.cpp", 59); do { } while (false); do { MOZ_CrashSequence(__null, 59); __attribute__ ((nomerge)) ::abort(); } while (false); } } while (false); | |||
| 60 | } | |||
| 61 | }; | |||
| 62 | ||||
| 63 | // NOTE: For simplicity in treating |aCharN| identically regardless whether it's | |||
| 64 | // a string literal or a more-generalized array, we require |aCharN| be | |||
| 65 | // null-terminated. | |||
| 66 | ||||
| 67 | template <typename Char, size_t N> | |||
| 68 | static void ExpectValidCodePoint(const Char (&aCharN)[N], | |||
| 69 | char32_t aExpectedCodePoint) { | |||
| 70 | MOZ_RELEASE_ASSERT(aCharN[N - 1] == 0,do { static_assert( mozilla::detail::AssertionConditionType< decltype(aCharN[N - 1] == 0)>::isValid, "invalid assertion condition" ); if ((__builtin_expect(!!(!(!!(aCharN[N - 1] == 0))), 0))) { do { } while (false); MOZ_ReportAssertionFailure("aCharN[N - 1] == 0" " (" "array must be null-terminated for |aCharN + N - 1| to " "compute the value of |aIter| as altered by " "DecodeOneUtf8CodePoint" ")", "/root/firefox-clang/mfbt/tests/TestUtf8.cpp", 73); do { } while (false); do { MOZ_CrashSequence(__null, 73); __attribute__ ((nomerge)) ::abort(); } while (false); } } while (false) | |||
| 71 | "array must be null-terminated for |aCharN + N - 1| to "do { static_assert( mozilla::detail::AssertionConditionType< decltype(aCharN[N - 1] == 0)>::isValid, "invalid assertion condition" ); if ((__builtin_expect(!!(!(!!(aCharN[N - 1] == 0))), 0))) { do { } while (false); MOZ_ReportAssertionFailure("aCharN[N - 1] == 0" " (" "array must be null-terminated for |aCharN + N - 1| to " "compute the value of |aIter| as altered by " "DecodeOneUtf8CodePoint" ")", "/root/firefox-clang/mfbt/tests/TestUtf8.cpp", 73); do { } while (false); do { MOZ_CrashSequence(__null, 73); __attribute__ ((nomerge)) ::abort(); } while (false); } } while (false) | |||
| 72 | "compute the value of |aIter| as altered by "do { static_assert( mozilla::detail::AssertionConditionType< decltype(aCharN[N - 1] == 0)>::isValid, "invalid assertion condition" ); if ((__builtin_expect(!!(!(!!(aCharN[N - 1] == 0))), 0))) { do { } while (false); MOZ_ReportAssertionFailure("aCharN[N - 1] == 0" " (" "array must be null-terminated for |aCharN + N - 1| to " "compute the value of |aIter| as altered by " "DecodeOneUtf8CodePoint" ")", "/root/firefox-clang/mfbt/tests/TestUtf8.cpp", 73); do { } while (false); do { MOZ_CrashSequence(__null, 73); __attribute__ ((nomerge)) ::abort(); } while (false); } } while (false) | |||
| 73 | "DecodeOneUtf8CodePoint")do { static_assert( mozilla::detail::AssertionConditionType< decltype(aCharN[N - 1] == 0)>::isValid, "invalid assertion condition" ); if ((__builtin_expect(!!(!(!!(aCharN[N - 1] == 0))), 0))) { do { } while (false); MOZ_ReportAssertionFailure("aCharN[N - 1] == 0" " (" "array must be null-terminated for |aCharN + N - 1| to " "compute the value of |aIter| as altered by " "DecodeOneUtf8CodePoint" ")", "/root/firefox-clang/mfbt/tests/TestUtf8.cpp", 73); do { } while (false); do { MOZ_CrashSequence(__null, 73); __attribute__ ((nomerge)) ::abort(); } while (false); } } while (false); | |||
| 74 | ||||
| 75 | ToUtf8Units<Char> simpleUnit(aCharN, aCharN + N - 1); | |||
| 76 | auto simple = | |||
| 77 | DecodeOneUtf8CodePoint(simpleUnit.lead, &simpleUnit.iter, simpleUnit.end); | |||
| 78 | MOZ_RELEASE_ASSERT(simple.isSome())do { static_assert( mozilla::detail::AssertionConditionType< decltype(simple.isSome())>::isValid, "invalid assertion condition" ); if ((__builtin_expect(!!(!(!!(simple.isSome()))), 0))) { do { } while (false); MOZ_ReportAssertionFailure("simple.isSome()" , "/root/firefox-clang/mfbt/tests/TestUtf8.cpp", 78); do { } while (false); do { MOZ_CrashSequence(__null, 78); __attribute__(( nomerge)) ::abort(); } while (false); } } while (false); | |||
| 79 | MOZ_RELEASE_ASSERT(*simple == aExpectedCodePoint)do { static_assert( mozilla::detail::AssertionConditionType< decltype(*simple == aExpectedCodePoint)>::isValid, "invalid assertion condition" ); if ((__builtin_expect(!!(!(!!(*simple == aExpectedCodePoint ))), 0))) { do { } while (false); MOZ_ReportAssertionFailure( "*simple == aExpectedCodePoint", "/root/firefox-clang/mfbt/tests/TestUtf8.cpp" , 79); do { } while (false); do { MOZ_CrashSequence(__null, 79 ); __attribute__((nomerge)) ::abort(); } while (false); } } while (false); | |||
| 80 | MOZ_RELEASE_ASSERT(simpleUnit.iter == simpleUnit.end)do { static_assert( mozilla::detail::AssertionConditionType< decltype(simpleUnit.iter == simpleUnit.end)>::isValid, "invalid assertion condition" ); if ((__builtin_expect(!!(!(!!(simpleUnit.iter == simpleUnit .end))), 0))) { do { } while (false); MOZ_ReportAssertionFailure ("simpleUnit.iter == simpleUnit.end", "/root/firefox-clang/mfbt/tests/TestUtf8.cpp" , 80); do { } while (false); do { MOZ_CrashSequence(__null, 80 ); __attribute__((nomerge)) ::abort(); } while (false); } } while (false); | |||
| 81 | ||||
| 82 | ToUtf8Units<Char> complexUnit(aCharN, aCharN + N - 1); | |||
| 83 | auto complex = DecodeOneUtf8CodePoint( | |||
| 84 | complexUnit.lead, &complexUnit.iter, complexUnit.end, AssertIfCalled(), | |||
| 85 | AssertIfCalled(), AssertIfCalled(), AssertIfCalled(), AssertIfCalled()); | |||
| 86 | MOZ_RELEASE_ASSERT(complex.isSome())do { static_assert( mozilla::detail::AssertionConditionType< decltype(complex.isSome())>::isValid, "invalid assertion condition" ); if ((__builtin_expect(!!(!(!!(complex.isSome()))), 0))) { do { } while (false); MOZ_ReportAssertionFailure("complex.isSome()" , "/root/firefox-clang/mfbt/tests/TestUtf8.cpp", 86); do { } while (false); do { MOZ_CrashSequence(__null, 86); __attribute__(( nomerge)) ::abort(); } while (false); } } while (false); | |||
| 87 | MOZ_RELEASE_ASSERT(*complex == aExpectedCodePoint)do { static_assert( mozilla::detail::AssertionConditionType< decltype(*complex == aExpectedCodePoint)>::isValid, "invalid assertion condition" ); if ((__builtin_expect(!!(!(!!(*complex == aExpectedCodePoint ))), 0))) { do { } while (false); MOZ_ReportAssertionFailure( "*complex == aExpectedCodePoint", "/root/firefox-clang/mfbt/tests/TestUtf8.cpp" , 87); do { } while (false); do { MOZ_CrashSequence(__null, 87 ); __attribute__((nomerge)) ::abort(); } while (false); } } while (false); | |||
| 88 | MOZ_RELEASE_ASSERT(complexUnit.iter == complexUnit.end)do { static_assert( mozilla::detail::AssertionConditionType< decltype(complexUnit.iter == complexUnit.end)>::isValid, "invalid assertion condition" ); if ((__builtin_expect(!!(!(!!(complexUnit.iter == complexUnit .end))), 0))) { do { } while (false); MOZ_ReportAssertionFailure ("complexUnit.iter == complexUnit.end", "/root/firefox-clang/mfbt/tests/TestUtf8.cpp" , 88); do { } while (false); do { MOZ_CrashSequence(__null, 88 ); __attribute__((nomerge)) ::abort(); } while (false); } } while (false); | |||
| 89 | } | |||
| 90 | ||||
| 91 | enum class InvalidUtf8Reason { | |||
| 92 | BadLeadUnit, | |||
| 93 | NotEnoughUnits, | |||
| 94 | BadTrailingUnit, | |||
| 95 | BadCodePoint, | |||
| 96 | NotShortestForm, | |||
| 97 | }; | |||
| 98 | ||||
| 99 | template <typename Char, size_t N> | |||
| 100 | static void ExpectInvalidCodePointHelper(const Char (&aCharN)[N], | |||
| 101 | InvalidUtf8Reason aExpectedReason, | |||
| 102 | uint8_t aExpectedUnitsAvailable, | |||
| 103 | uint8_t aExpectedUnitsNeeded, | |||
| 104 | char32_t aExpectedBadCodePoint, | |||
| 105 | uint8_t aExpectedUnitsObserved) { | |||
| 106 | MOZ_RELEASE_ASSERT(aCharN[N - 1] == 0,do { static_assert( mozilla::detail::AssertionConditionType< decltype(aCharN[N - 1] == 0)>::isValid, "invalid assertion condition" ); if ((__builtin_expect(!!(!(!!(aCharN[N - 1] == 0))), 0))) { do { } while (false); MOZ_ReportAssertionFailure("aCharN[N - 1] == 0" " (" "array must be null-terminated for |aCharN + N - 1| to " "compute the value of |aIter| as altered by " "DecodeOneUtf8CodePoint" ")", "/root/firefox-clang/mfbt/tests/TestUtf8.cpp", 109); do { } while (false); do { MOZ_CrashSequence(__null, 109); __attribute__ ((nomerge)) ::abort(); } while (false); } } while (false) | |||
| ||||
| 107 | "array must be null-terminated for |aCharN + N - 1| to "do { static_assert( mozilla::detail::AssertionConditionType< decltype(aCharN[N - 1] == 0)>::isValid, "invalid assertion condition" ); if ((__builtin_expect(!!(!(!!(aCharN[N - 1] == 0))), 0))) { do { } while (false); MOZ_ReportAssertionFailure("aCharN[N - 1] == 0" " (" "array must be null-terminated for |aCharN + N - 1| to " "compute the value of |aIter| as altered by " "DecodeOneUtf8CodePoint" ")", "/root/firefox-clang/mfbt/tests/TestUtf8.cpp", 109); do { } while (false); do { MOZ_CrashSequence(__null, 109); __attribute__ ((nomerge)) ::abort(); } while (false); } } while (false) | |||
| 108 | "compute the value of |aIter| as altered by "do { static_assert( mozilla::detail::AssertionConditionType< decltype(aCharN[N - 1] == 0)>::isValid, "invalid assertion condition" ); if ((__builtin_expect(!!(!(!!(aCharN[N - 1] == 0))), 0))) { do { } while (false); MOZ_ReportAssertionFailure("aCharN[N - 1] == 0" " (" "array must be null-terminated for |aCharN + N - 1| to " "compute the value of |aIter| as altered by " "DecodeOneUtf8CodePoint" ")", "/root/firefox-clang/mfbt/tests/TestUtf8.cpp", 109); do { } while (false); do { MOZ_CrashSequence(__null, 109); __attribute__ ((nomerge)) ::abort(); } while (false); } } while (false) | |||
| 109 | "DecodeOneUtf8CodePoint")do { static_assert( mozilla::detail::AssertionConditionType< decltype(aCharN[N - 1] == 0)>::isValid, "invalid assertion condition" ); if ((__builtin_expect(!!(!(!!(aCharN[N - 1] == 0))), 0))) { do { } while (false); MOZ_ReportAssertionFailure("aCharN[N - 1] == 0" " (" "array must be null-terminated for |aCharN + N - 1| to " "compute the value of |aIter| as altered by " "DecodeOneUtf8CodePoint" ")", "/root/firefox-clang/mfbt/tests/TestUtf8.cpp", 109); do { } while (false); do { MOZ_CrashSequence(__null, 109); __attribute__ ((nomerge)) ::abort(); } while (false); } } while (false); | |||
| 110 | ||||
| 111 | ToUtf8Units<Char> simpleUnit(aCharN, aCharN + N - 1); | |||
| 112 | auto simple = | |||
| 113 | DecodeOneUtf8CodePoint(simpleUnit.lead, &simpleUnit.iter, simpleUnit.end); | |||
| 114 | MOZ_RELEASE_ASSERT(simple.isNothing())do { static_assert( mozilla::detail::AssertionConditionType< decltype(simple.isNothing())>::isValid, "invalid assertion condition" ); if ((__builtin_expect(!!(!(!!(simple.isNothing()))), 0))) { do { } while (false); MOZ_ReportAssertionFailure("simple.isNothing()" , "/root/firefox-clang/mfbt/tests/TestUtf8.cpp", 114); do { } while (false); do { MOZ_CrashSequence(__null, 114); __attribute__ ((nomerge)) ::abort(); } while (false); } } while (false); | |||
| 115 | MOZ_RELEASE_ASSERT(static_cast<const void*>(simpleUnit.iter) == aCharN)do { static_assert( mozilla::detail::AssertionConditionType< decltype(static_cast<const void*>(simpleUnit.iter) == aCharN )>::isValid, "invalid assertion condition"); if ((__builtin_expect (!!(!(!!(static_cast<const void*>(simpleUnit.iter) == aCharN ))), 0))) { do { } while (false); MOZ_ReportAssertionFailure( "static_cast<const void*>(simpleUnit.iter) == aCharN", "/root/firefox-clang/mfbt/tests/TestUtf8.cpp" , 115); do { } while (false); do { MOZ_CrashSequence(__null, 115 ); __attribute__((nomerge)) ::abort(); } while (false); } } while (false); | |||
| 116 | ||||
| 117 | EnumSet<InvalidUtf8Reason> reasons; | |||
| 118 | uint8_t unitsAvailable; | |||
| 119 | uint8_t unitsNeeded; | |||
| 120 | char32_t badCodePoint; | |||
| 121 | uint8_t unitsObserved; | |||
| 122 | ||||
| 123 | struct OnNotShortestForm { | |||
| 124 | EnumSet<InvalidUtf8Reason>& reasons; | |||
| 125 | char32_t& badCodePoint; | |||
| 126 | uint8_t& unitsObserved; | |||
| 127 | ||||
| 128 | void operator()(char32_t aBadCodePoint, uint8_t aUnitsObserved) { | |||
| 129 | reasons += InvalidUtf8Reason::NotShortestForm; | |||
| 130 | badCodePoint = aBadCodePoint; | |||
| 131 | unitsObserved = aUnitsObserved; | |||
| 132 | } | |||
| 133 | }; | |||
| 134 | ||||
| 135 | ToUtf8Units<Char> complexUnit(aCharN, aCharN + N - 1); | |||
| 136 | auto complex = DecodeOneUtf8CodePoint( | |||
| 137 | complexUnit.lead, &complexUnit.iter, complexUnit.end, | |||
| 138 | [&reasons]() { reasons += InvalidUtf8Reason::BadLeadUnit; }, | |||
| 139 | [&reasons, &unitsAvailable, &unitsNeeded](uint8_t aUnitsAvailable, | |||
| 140 | uint8_t aUnitsNeeded) { | |||
| 141 | reasons += InvalidUtf8Reason::NotEnoughUnits; | |||
| 142 | unitsAvailable = aUnitsAvailable; | |||
| 143 | unitsNeeded = aUnitsNeeded; | |||
| 144 | }, | |||
| 145 | [&reasons, &unitsObserved](uint8_t aUnitsObserved) { | |||
| 146 | reasons += InvalidUtf8Reason::BadTrailingUnit; | |||
| 147 | unitsObserved = aUnitsObserved; | |||
| 148 | }, | |||
| 149 | [&reasons, &badCodePoint, &unitsObserved](char32_t aBadCodePoint, | |||
| 150 | uint8_t aUnitsObserved) { | |||
| 151 | reasons += InvalidUtf8Reason::BadCodePoint; | |||
| 152 | badCodePoint = aBadCodePoint; | |||
| 153 | unitsObserved = aUnitsObserved; | |||
| 154 | }, | |||
| 155 | [&reasons, &badCodePoint, &unitsObserved](char32_t aBadCodePoint, | |||
| 156 | uint8_t aUnitsObserved) { | |||
| 157 | reasons += InvalidUtf8Reason::NotShortestForm; | |||
| 158 | badCodePoint = aBadCodePoint; | |||
| 159 | unitsObserved = aUnitsObserved; | |||
| 160 | }); | |||
| 161 | MOZ_RELEASE_ASSERT(complex.isNothing())do { static_assert( mozilla::detail::AssertionConditionType< decltype(complex.isNothing())>::isValid, "invalid assertion condition" ); if ((__builtin_expect(!!(!(!!(complex.isNothing()))), 0))) { do { } while (false); MOZ_ReportAssertionFailure("complex.isNothing()" , "/root/firefox-clang/mfbt/tests/TestUtf8.cpp", 161); do { } while (false); do { MOZ_CrashSequence(__null, 161); __attribute__ ((nomerge)) ::abort(); } while (false); } } while (false); | |||
| 162 | MOZ_RELEASE_ASSERT(static_cast<const void*>(complexUnit.iter) == aCharN)do { static_assert( mozilla::detail::AssertionConditionType< decltype(static_cast<const void*>(complexUnit.iter) == aCharN )>::isValid, "invalid assertion condition"); if ((__builtin_expect (!!(!(!!(static_cast<const void*>(complexUnit.iter) == aCharN ))), 0))) { do { } while (false); MOZ_ReportAssertionFailure( "static_cast<const void*>(complexUnit.iter) == aCharN", "/root/firefox-clang/mfbt/tests/TestUtf8.cpp", 162); do { } while (false); do { MOZ_CrashSequence(__null, 162); __attribute__( (nomerge)) ::abort(); } while (false); } } while (false); | |||
| 163 | ||||
| 164 | bool alreadyIterated = false; | |||
| 165 | for (InvalidUtf8Reason reason : reasons) { | |||
| 166 | MOZ_RELEASE_ASSERT(!alreadyIterated)do { static_assert( mozilla::detail::AssertionConditionType< decltype(!alreadyIterated)>::isValid, "invalid assertion condition" ); if ((__builtin_expect(!!(!(!!(!alreadyIterated))), 0))) { do { } while (false); MOZ_ReportAssertionFailure("!alreadyIterated" , "/root/firefox-clang/mfbt/tests/TestUtf8.cpp", 166); do { } while (false); do { MOZ_CrashSequence(__null, 166); __attribute__ ((nomerge)) ::abort(); } while (false); } } while (false); | |||
| 167 | alreadyIterated = true; | |||
| 168 | ||||
| 169 | switch (reason) { | |||
| 170 | case InvalidUtf8Reason::BadLeadUnit: | |||
| 171 | break; | |||
| 172 | ||||
| 173 | case InvalidUtf8Reason::NotEnoughUnits: | |||
| 174 | MOZ_RELEASE_ASSERT(unitsAvailable == aExpectedUnitsAvailable)do { static_assert( mozilla::detail::AssertionConditionType< decltype(unitsAvailable == aExpectedUnitsAvailable)>::isValid , "invalid assertion condition"); if ((__builtin_expect(!!(!( !!(unitsAvailable == aExpectedUnitsAvailable))), 0))) { do { } while (false); MOZ_ReportAssertionFailure("unitsAvailable == aExpectedUnitsAvailable" , "/root/firefox-clang/mfbt/tests/TestUtf8.cpp", 174); do { } while (false); do { MOZ_CrashSequence(__null, 174); __attribute__ ((nomerge)) ::abort(); } while (false); } } while (false); | |||
| 175 | MOZ_RELEASE_ASSERT(unitsNeeded == aExpectedUnitsNeeded)do { static_assert( mozilla::detail::AssertionConditionType< decltype(unitsNeeded == aExpectedUnitsNeeded)>::isValid, "invalid assertion condition" ); if ((__builtin_expect(!!(!(!!(unitsNeeded == aExpectedUnitsNeeded ))), 0))) { do { } while (false); MOZ_ReportAssertionFailure( "unitsNeeded == aExpectedUnitsNeeded", "/root/firefox-clang/mfbt/tests/TestUtf8.cpp" , 175); do { } while (false); do { MOZ_CrashSequence(__null, 175 ); __attribute__((nomerge)) ::abort(); } while (false); } } while (false); | |||
| 176 | break; | |||
| 177 | ||||
| 178 | case InvalidUtf8Reason::BadTrailingUnit: | |||
| 179 | MOZ_RELEASE_ASSERT(unitsObserved == aExpectedUnitsObserved)do { static_assert( mozilla::detail::AssertionConditionType< decltype(unitsObserved == aExpectedUnitsObserved)>::isValid , "invalid assertion condition"); if ((__builtin_expect(!!(!( !!(unitsObserved == aExpectedUnitsObserved))), 0))) { do { } while (false); MOZ_ReportAssertionFailure("unitsObserved == aExpectedUnitsObserved" , "/root/firefox-clang/mfbt/tests/TestUtf8.cpp", 179); do { } while (false); do { MOZ_CrashSequence(__null, 179); __attribute__ ((nomerge)) ::abort(); } while (false); } } while (false); | |||
| ||||
| 180 | break; | |||
| 181 | ||||
| 182 | case InvalidUtf8Reason::BadCodePoint: | |||
| 183 | MOZ_RELEASE_ASSERT(badCodePoint == aExpectedBadCodePoint)do { static_assert( mozilla::detail::AssertionConditionType< decltype(badCodePoint == aExpectedBadCodePoint)>::isValid, "invalid assertion condition"); if ((__builtin_expect(!!(!(! !(badCodePoint == aExpectedBadCodePoint))), 0))) { do { } while (false); MOZ_ReportAssertionFailure("badCodePoint == aExpectedBadCodePoint" , "/root/firefox-clang/mfbt/tests/TestUtf8.cpp", 183); do { } while (false); do { MOZ_CrashSequence(__null, 183); __attribute__ ((nomerge)) ::abort(); } while (false); } } while (false); | |||
| 184 | MOZ_RELEASE_ASSERT(unitsObserved == aExpectedUnitsObserved)do { static_assert( mozilla::detail::AssertionConditionType< decltype(unitsObserved == aExpectedUnitsObserved)>::isValid , "invalid assertion condition"); if ((__builtin_expect(!!(!( !!(unitsObserved == aExpectedUnitsObserved))), 0))) { do { } while (false); MOZ_ReportAssertionFailure("unitsObserved == aExpectedUnitsObserved" , "/root/firefox-clang/mfbt/tests/TestUtf8.cpp", 184); do { } while (false); do { MOZ_CrashSequence(__null, 184); __attribute__ ((nomerge)) ::abort(); } while (false); } } while (false); | |||
| 185 | break; | |||
| 186 | ||||
| 187 | case InvalidUtf8Reason::NotShortestForm: | |||
| 188 | MOZ_RELEASE_ASSERT(badCodePoint == aExpectedBadCodePoint)do { static_assert( mozilla::detail::AssertionConditionType< decltype(badCodePoint == aExpectedBadCodePoint)>::isValid, "invalid assertion condition"); if ((__builtin_expect(!!(!(! !(badCodePoint == aExpectedBadCodePoint))), 0))) { do { } while (false); MOZ_ReportAssertionFailure("badCodePoint == aExpectedBadCodePoint" , "/root/firefox-clang/mfbt/tests/TestUtf8.cpp", 188); do { } while (false); do { MOZ_CrashSequence(__null, 188); __attribute__ ((nomerge)) ::abort(); } while (false); } } while (false); | |||
| 189 | MOZ_RELEASE_ASSERT(unitsObserved == aExpectedUnitsObserved)do { static_assert( mozilla::detail::AssertionConditionType< decltype(unitsObserved == aExpectedUnitsObserved)>::isValid , "invalid assertion condition"); if ((__builtin_expect(!!(!( !!(unitsObserved == aExpectedUnitsObserved))), 0))) { do { } while (false); MOZ_ReportAssertionFailure("unitsObserved == aExpectedUnitsObserved" , "/root/firefox-clang/mfbt/tests/TestUtf8.cpp", 189); do { } while (false); do { MOZ_CrashSequence(__null, 189); __attribute__ ((nomerge)) ::abort(); } while (false); } } while (false); | |||
| 190 | break; | |||
| 191 | } | |||
| 192 | } | |||
| 193 | } | |||
| 194 | ||||
| 195 | // NOTE: For simplicity in treating |aCharN| identically regardless whether it's | |||
| 196 | // a string literal or a more-generalized array, we require |aCharN| be | |||
| 197 | // null-terminated in all these functions. | |||
| 198 | ||||
| 199 | template <typename Char, size_t N> | |||
| 200 | static void ExpectBadLeadUnit(const Char (&aCharN)[N]) { | |||
| 201 | ExpectInvalidCodePointHelper(aCharN, InvalidUtf8Reason::BadLeadUnit, 0xFF, | |||
| 202 | 0xFF, 0xFFFFFFFF, 0xFF); | |||
| 203 | } | |||
| 204 | ||||
| 205 | template <typename Char, size_t N> | |||
| 206 | static void ExpectNotEnoughUnits(const Char (&aCharN)[N], | |||
| 207 | uint8_t aExpectedUnitsAvailable, | |||
| 208 | uint8_t aExpectedUnitsNeeded) { | |||
| 209 | ExpectInvalidCodePointHelper(aCharN, InvalidUtf8Reason::NotEnoughUnits, | |||
| 210 | aExpectedUnitsAvailable, aExpectedUnitsNeeded, | |||
| 211 | 0xFFFFFFFF, 0xFF); | |||
| 212 | } | |||
| 213 | ||||
| 214 | template <typename Char, size_t N> | |||
| 215 | static void ExpectBadTrailingUnit(const Char (&aCharN)[N], | |||
| 216 | uint8_t aExpectedUnitsObserved) { | |||
| 217 | ExpectInvalidCodePointHelper(aCharN, InvalidUtf8Reason::BadTrailingUnit, 0xFF, | |||
| 218 | 0xFF, 0xFFFFFFFF, aExpectedUnitsObserved); | |||
| 219 | } | |||
| 220 | ||||
| 221 | template <typename Char, size_t N> | |||
| 222 | static void ExpectNotShortestForm(const Char (&aCharN)[N], | |||
| 223 | char32_t aExpectedBadCodePoint, | |||
| 224 | uint8_t aExpectedUnitsObserved) { | |||
| 225 | ExpectInvalidCodePointHelper(aCharN, InvalidUtf8Reason::NotShortestForm, 0xFF, | |||
| 226 | 0xFF, aExpectedBadCodePoint, | |||
| 227 | aExpectedUnitsObserved); | |||
| 228 | } | |||
| 229 | ||||
| 230 | template <typename Char, size_t N> | |||
| 231 | static void ExpectBadCodePoint(const Char (&aCharN)[N], | |||
| 232 | char32_t aExpectedBadCodePoint, | |||
| 233 | uint8_t aExpectedUnitsObserved) { | |||
| 234 | ExpectInvalidCodePointHelper(aCharN, InvalidUtf8Reason::BadCodePoint, 0xFF, | |||
| 235 | 0xFF, aExpectedBadCodePoint, | |||
| 236 | aExpectedUnitsObserved); | |||
| 237 | } | |||
| 238 | ||||
| 239 | static void TestIsUtf8() { | |||
| 240 | // Note we include the U+0000 NULL in this one -- and that's fine. | |||
| 241 | static const char asciiBytes[] = "How about a nice game of chess?"; | |||
| 242 | MOZ_RELEASE_ASSERT(IsUtf8(Span(asciiBytes, std::size(asciiBytes))))do { static_assert( mozilla::detail::AssertionConditionType< decltype(IsUtf8(Span(asciiBytes, std::size(asciiBytes))))> ::isValid, "invalid assertion condition"); if ((__builtin_expect (!!(!(!!(IsUtf8(Span(asciiBytes, std::size(asciiBytes)))))), 0 ))) { do { } while (false); MOZ_ReportAssertionFailure("IsUtf8(Span(asciiBytes, std::size(asciiBytes)))" , "/root/firefox-clang/mfbt/tests/TestUtf8.cpp", 242); do { } while (false); do { MOZ_CrashSequence(__null, 242); __attribute__ ((nomerge)) ::abort(); } while (false); } } while (false); | |||
| 243 | ||||
| 244 | static const char endNonAsciiBytes[] = "Life is like a 🌯"; | |||
| 245 | MOZ_RELEASE_ASSERT(do { static_assert( mozilla::detail::AssertionConditionType< decltype(IsUtf8(Span(endNonAsciiBytes, std::size(endNonAsciiBytes ) - 1)))>::isValid, "invalid assertion condition"); if ((__builtin_expect (!!(!(!!(IsUtf8(Span(endNonAsciiBytes, std::size(endNonAsciiBytes ) - 1))))), 0))) { do { } while (false); MOZ_ReportAssertionFailure ("IsUtf8(Span(endNonAsciiBytes, std::size(endNonAsciiBytes) - 1))" , "/root/firefox-clang/mfbt/tests/TestUtf8.cpp", 246); do { } while (false); do { MOZ_CrashSequence(__null, 246); __attribute__ ((nomerge)) ::abort(); } while (false); } } while (false) | |||
| 246 | IsUtf8(Span(endNonAsciiBytes, std::size(endNonAsciiBytes) - 1)))do { static_assert( mozilla::detail::AssertionConditionType< decltype(IsUtf8(Span(endNonAsciiBytes, std::size(endNonAsciiBytes ) - 1)))>::isValid, "invalid assertion condition"); if ((__builtin_expect (!!(!(!!(IsUtf8(Span(endNonAsciiBytes, std::size(endNonAsciiBytes ) - 1))))), 0))) { do { } while (false); MOZ_ReportAssertionFailure ("IsUtf8(Span(endNonAsciiBytes, std::size(endNonAsciiBytes) - 1))" , "/root/firefox-clang/mfbt/tests/TestUtf8.cpp", 246); do { } while (false); do { MOZ_CrashSequence(__null, 246); __attribute__ ((nomerge)) ::abort(); } while (false); } } while (false); | |||
| 247 | ||||
| 248 | static const unsigned char badLeading[] = {0x80}; | |||
| 249 | MOZ_RELEASE_ASSERT(!IsUtf8(AsChars(Span(badLeading, std::size(badLeading)))))do { static_assert( mozilla::detail::AssertionConditionType< decltype(!IsUtf8(AsChars(Span(badLeading, std::size(badLeading )))))>::isValid, "invalid assertion condition"); if ((__builtin_expect (!!(!(!!(!IsUtf8(AsChars(Span(badLeading, std::size(badLeading ))))))), 0))) { do { } while (false); MOZ_ReportAssertionFailure ("!IsUtf8(AsChars(Span(badLeading, std::size(badLeading))))", "/root/firefox-clang/mfbt/tests/TestUtf8.cpp", 249); do { } while (false); do { MOZ_CrashSequence(__null, 249); __attribute__( (nomerge)) ::abort(); } while (false); } } while (false); | |||
| 250 | ||||
| 251 | // Byte-counts | |||
| 252 | ||||
| 253 | // 1 | |||
| 254 | static const char oneBytes[] = "A"; // U+0041 LATIN CAPITAL LETTER A | |||
| 255 | constexpr size_t oneBytesLen = std::size(oneBytes); | |||
| 256 | static_assert(oneBytesLen == 2, "U+0041 plus nul"); | |||
| 257 | MOZ_RELEASE_ASSERT(IsUtf8(Span(oneBytes, oneBytesLen)))do { static_assert( mozilla::detail::AssertionConditionType< decltype(IsUtf8(Span(oneBytes, oneBytesLen)))>::isValid, "invalid assertion condition" ); if ((__builtin_expect(!!(!(!!(IsUtf8(Span(oneBytes, oneBytesLen ))))), 0))) { do { } while (false); MOZ_ReportAssertionFailure ("IsUtf8(Span(oneBytes, oneBytesLen))", "/root/firefox-clang/mfbt/tests/TestUtf8.cpp" , 257); do { } while (false); do { MOZ_CrashSequence(__null, 257 ); __attribute__((nomerge)) ::abort(); } while (false); } } while (false); | |||
| 258 | ||||
| 259 | // 2 | |||
| 260 | static const char twoBytes[] = "؆"; // U+0606 ARABIC-INDIC CUBE ROOT | |||
| 261 | constexpr size_t twoBytesLen = std::size(twoBytes); | |||
| 262 | static_assert(twoBytesLen == 3, "U+0606 in two bytes plus nul"); | |||
| 263 | MOZ_RELEASE_ASSERT(IsUtf8(Span(twoBytes, twoBytesLen)))do { static_assert( mozilla::detail::AssertionConditionType< decltype(IsUtf8(Span(twoBytes, twoBytesLen)))>::isValid, "invalid assertion condition" ); if ((__builtin_expect(!!(!(!!(IsUtf8(Span(twoBytes, twoBytesLen ))))), 0))) { do { } while (false); MOZ_ReportAssertionFailure ("IsUtf8(Span(twoBytes, twoBytesLen))", "/root/firefox-clang/mfbt/tests/TestUtf8.cpp" , 263); do { } while (false); do { MOZ_CrashSequence(__null, 263 ); __attribute__((nomerge)) ::abort(); } while (false); } } while (false); | |||
| 264 | ||||
| 265 | ExpectValidCodePoint(twoBytes, 0x0606); | |||
| 266 | ||||
| 267 | // 3 | |||
| 268 | static const char threeBytes[] = "᨞"; // U+1A1E BUGINESE PALLAWA | |||
| 269 | constexpr size_t threeBytesLen = std::size(threeBytes); | |||
| 270 | static_assert(threeBytesLen == 4, "U+1A1E in three bytes plus nul"); | |||
| 271 | MOZ_RELEASE_ASSERT(IsUtf8(Span(threeBytes, threeBytesLen)))do { static_assert( mozilla::detail::AssertionConditionType< decltype(IsUtf8(Span(threeBytes, threeBytesLen)))>::isValid , "invalid assertion condition"); if ((__builtin_expect(!!(!( !!(IsUtf8(Span(threeBytes, threeBytesLen))))), 0))) { do { } while (false); MOZ_ReportAssertionFailure("IsUtf8(Span(threeBytes, threeBytesLen))" , "/root/firefox-clang/mfbt/tests/TestUtf8.cpp", 271); do { } while (false); do { MOZ_CrashSequence(__null, 271); __attribute__ ((nomerge)) ::abort(); } while (false); } } while (false); | |||
| 272 | ||||
| 273 | ExpectValidCodePoint(threeBytes, 0x1A1E); | |||
| 274 | ||||
| 275 | // 4 | |||
| 276 | static const char fourBytes[] = "🁡"; // U+1F061 DOMINO TILE HORIZONTAL-06-06 | |||
| 277 | constexpr size_t fourBytesLen = std::size(fourBytes); | |||
| 278 | static_assert(fourBytesLen == 5, "U+1F061 in four bytes plus nul"); | |||
| 279 | MOZ_RELEASE_ASSERT(IsUtf8(Span(fourBytes, fourBytesLen)))do { static_assert( mozilla::detail::AssertionConditionType< decltype(IsUtf8(Span(fourBytes, fourBytesLen)))>::isValid, "invalid assertion condition"); if ((__builtin_expect(!!(!(! !(IsUtf8(Span(fourBytes, fourBytesLen))))), 0))) { do { } while (false); MOZ_ReportAssertionFailure("IsUtf8(Span(fourBytes, fourBytesLen))" , "/root/firefox-clang/mfbt/tests/TestUtf8.cpp", 279); do { } while (false); do { MOZ_CrashSequence(__null, 279); __attribute__ ((nomerge)) ::abort(); } while (false); } } while (false); | |||
| 280 | ||||
| 281 | ExpectValidCodePoint(fourBytes, 0x1F061); | |||
| 282 | ||||
| 283 | // Max code point | |||
| 284 | static const char maxCodePoint[] = ""; // U+10FFFF | |||
| 285 | constexpr size_t maxCodePointLen = std::size(maxCodePoint); | |||
| 286 | static_assert(maxCodePointLen == 5, "U+10FFFF in four bytes plus nul"); | |||
| 287 | MOZ_RELEASE_ASSERT(IsUtf8(Span(maxCodePoint, maxCodePointLen)))do { static_assert( mozilla::detail::AssertionConditionType< decltype(IsUtf8(Span(maxCodePoint, maxCodePointLen)))>::isValid , "invalid assertion condition"); if ((__builtin_expect(!!(!( !!(IsUtf8(Span(maxCodePoint, maxCodePointLen))))), 0))) { do { } while (false); MOZ_ReportAssertionFailure("IsUtf8(Span(maxCodePoint, maxCodePointLen))" , "/root/firefox-clang/mfbt/tests/TestUtf8.cpp", 287); do { } while (false); do { MOZ_CrashSequence(__null, 287); __attribute__ ((nomerge)) ::abort(); } while (false); } } while (false); | |||
| 288 | ||||
| 289 | ExpectValidCodePoint(maxCodePoint, 0x10FFFF); | |||
| 290 | ||||
| 291 | // One past max code point | |||
| 292 | static const unsigned char onePastMaxCodePoint[] = {0xF4, 0x90, 0x80, 0x80, | |||
| 293 | 0x0}; | |||
| 294 | constexpr size_t onePastMaxCodePointLen = std::size(onePastMaxCodePoint); | |||
| 295 | MOZ_RELEASE_ASSERT(do { static_assert( mozilla::detail::AssertionConditionType< decltype(!IsUtf8(AsChars(Span(onePastMaxCodePoint, onePastMaxCodePointLen ))))>::isValid, "invalid assertion condition"); if ((__builtin_expect (!!(!(!!(!IsUtf8(AsChars(Span(onePastMaxCodePoint, onePastMaxCodePointLen )))))), 0))) { do { } while (false); MOZ_ReportAssertionFailure ("!IsUtf8(AsChars(Span(onePastMaxCodePoint, onePastMaxCodePointLen)))" , "/root/firefox-clang/mfbt/tests/TestUtf8.cpp", 296); do { } while (false); do { MOZ_CrashSequence(__null, 296); __attribute__ ((nomerge)) ::abort(); } while (false); } } while (false) | |||
| 296 | !IsUtf8(AsChars(Span(onePastMaxCodePoint, onePastMaxCodePointLen))))do { static_assert( mozilla::detail::AssertionConditionType< decltype(!IsUtf8(AsChars(Span(onePastMaxCodePoint, onePastMaxCodePointLen ))))>::isValid, "invalid assertion condition"); if ((__builtin_expect (!!(!(!!(!IsUtf8(AsChars(Span(onePastMaxCodePoint, onePastMaxCodePointLen )))))), 0))) { do { } while (false); MOZ_ReportAssertionFailure ("!IsUtf8(AsChars(Span(onePastMaxCodePoint, onePastMaxCodePointLen)))" , "/root/firefox-clang/mfbt/tests/TestUtf8.cpp", 296); do { } while (false); do { MOZ_CrashSequence(__null, 296); __attribute__ ((nomerge)) ::abort(); } while (false); } } while (false); | |||
| 297 | ||||
| 298 | ExpectBadCodePoint(onePastMaxCodePoint, 0x110000, 4); | |||
| 299 | ||||
| 300 | // Surrogate-related testing | |||
| 301 | ||||
| 302 | // (Note that the various code unit sequences here are null-terminated to | |||
| 303 | // simplify life for ExpectValidCodePoint, which presumes null termination.) | |||
| 304 | ||||
| 305 | static const unsigned char justBeforeSurrogates[] = {0xED, 0x9F, 0xBF, 0x0}; | |||
| 306 | constexpr size_t justBeforeSurrogatesLen = | |||
| 307 | std::size(justBeforeSurrogates) - 1; | |||
| 308 | MOZ_RELEASE_ASSERT(do { static_assert( mozilla::detail::AssertionConditionType< decltype(IsUtf8(AsChars(Span(justBeforeSurrogates, justBeforeSurrogatesLen ))))>::isValid, "invalid assertion condition"); if ((__builtin_expect (!!(!(!!(IsUtf8(AsChars(Span(justBeforeSurrogates, justBeforeSurrogatesLen )))))), 0))) { do { } while (false); MOZ_ReportAssertionFailure ("IsUtf8(AsChars(Span(justBeforeSurrogates, justBeforeSurrogatesLen)))" , "/root/firefox-clang/mfbt/tests/TestUtf8.cpp", 309); do { } while (false); do { MOZ_CrashSequence(__null, 309); __attribute__ ((nomerge)) ::abort(); } while (false); } } while (false) | |||
| 309 | IsUtf8(AsChars(Span(justBeforeSurrogates, justBeforeSurrogatesLen))))do { static_assert( mozilla::detail::AssertionConditionType< decltype(IsUtf8(AsChars(Span(justBeforeSurrogates, justBeforeSurrogatesLen ))))>::isValid, "invalid assertion condition"); if ((__builtin_expect (!!(!(!!(IsUtf8(AsChars(Span(justBeforeSurrogates, justBeforeSurrogatesLen )))))), 0))) { do { } while (false); MOZ_ReportAssertionFailure ("IsUtf8(AsChars(Span(justBeforeSurrogates, justBeforeSurrogatesLen)))" , "/root/firefox-clang/mfbt/tests/TestUtf8.cpp", 309); do { } while (false); do { MOZ_CrashSequence(__null, 309); __attribute__ ((nomerge)) ::abort(); } while (false); } } while (false); | |||
| 310 | ||||
| 311 | ExpectValidCodePoint(justBeforeSurrogates, 0xD7FF); | |||
| 312 | ||||
| 313 | static const unsigned char leastSurrogate[] = {0xED, 0xA0, 0x80, 0x0}; | |||
| 314 | constexpr size_t leastSurrogateLen = std::size(leastSurrogate) - 1; | |||
| 315 | MOZ_RELEASE_ASSERT(!IsUtf8(AsChars(Span(leastSurrogate, leastSurrogateLen))))do { static_assert( mozilla::detail::AssertionConditionType< decltype(!IsUtf8(AsChars(Span(leastSurrogate, leastSurrogateLen ))))>::isValid, "invalid assertion condition"); if ((__builtin_expect (!!(!(!!(!IsUtf8(AsChars(Span(leastSurrogate, leastSurrogateLen )))))), 0))) { do { } while (false); MOZ_ReportAssertionFailure ("!IsUtf8(AsChars(Span(leastSurrogate, leastSurrogateLen)))", "/root/firefox-clang/mfbt/tests/TestUtf8.cpp", 315); do { } while (false); do { MOZ_CrashSequence(__null, 315); __attribute__( (nomerge)) ::abort(); } while (false); } } while (false); | |||
| 316 | ||||
| 317 | ExpectBadCodePoint(leastSurrogate, 0xD800, 3); | |||
| 318 | ||||
| 319 | static const unsigned char arbitraryHighSurrogate[] = {0xED, 0xA2, 0x87, 0x0}; | |||
| 320 | constexpr size_t arbitraryHighSurrogateLen = | |||
| 321 | std::size(arbitraryHighSurrogate) - 1; | |||
| 322 | MOZ_RELEASE_ASSERT(!IsUtf8(do { static_assert( mozilla::detail::AssertionConditionType< decltype(!IsUtf8( AsChars(Span(arbitraryHighSurrogate, arbitraryHighSurrogateLen ))))>::isValid, "invalid assertion condition"); if ((__builtin_expect (!!(!(!!(!IsUtf8( AsChars(Span(arbitraryHighSurrogate, arbitraryHighSurrogateLen )))))), 0))) { do { } while (false); MOZ_ReportAssertionFailure ("!IsUtf8( AsChars(Span(arbitraryHighSurrogate, arbitraryHighSurrogateLen)))" , "/root/firefox-clang/mfbt/tests/TestUtf8.cpp", 323); do { } while (false); do { MOZ_CrashSequence(__null, 323); __attribute__ ((nomerge)) ::abort(); } while (false); } } while (false) | |||
| 323 | AsChars(Span(arbitraryHighSurrogate, arbitraryHighSurrogateLen))))do { static_assert( mozilla::detail::AssertionConditionType< decltype(!IsUtf8( AsChars(Span(arbitraryHighSurrogate, arbitraryHighSurrogateLen ))))>::isValid, "invalid assertion condition"); if ((__builtin_expect (!!(!(!!(!IsUtf8( AsChars(Span(arbitraryHighSurrogate, arbitraryHighSurrogateLen )))))), 0))) { do { } while (false); MOZ_ReportAssertionFailure ("!IsUtf8( AsChars(Span(arbitraryHighSurrogate, arbitraryHighSurrogateLen)))" , "/root/firefox-clang/mfbt/tests/TestUtf8.cpp", 323); do { } while (false); do { MOZ_CrashSequence(__null, 323); __attribute__ ((nomerge)) ::abort(); } while (false); } } while (false); | |||
| 324 | ||||
| 325 | ExpectBadCodePoint(arbitraryHighSurrogate, 0xD887, 3); | |||
| 326 | ||||
| 327 | static const unsigned char arbitraryLowSurrogate[] = {0xED, 0xB7, 0xAF, 0x0}; | |||
| 328 | constexpr size_t arbitraryLowSurrogateLen = | |||
| 329 | std::size(arbitraryLowSurrogate) - 1; | |||
| 330 | MOZ_RELEASE_ASSERT(do { static_assert( mozilla::detail::AssertionConditionType< decltype(!IsUtf8(AsChars(Span(arbitraryLowSurrogate, arbitraryLowSurrogateLen ))))>::isValid, "invalid assertion condition"); if ((__builtin_expect (!!(!(!!(!IsUtf8(AsChars(Span(arbitraryLowSurrogate, arbitraryLowSurrogateLen )))))), 0))) { do { } while (false); MOZ_ReportAssertionFailure ("!IsUtf8(AsChars(Span(arbitraryLowSurrogate, arbitraryLowSurrogateLen)))" , "/root/firefox-clang/mfbt/tests/TestUtf8.cpp", 331); do { } while (false); do { MOZ_CrashSequence(__null, 331); __attribute__ ((nomerge)) ::abort(); } while (false); } } while (false) | |||
| 331 | !IsUtf8(AsChars(Span(arbitraryLowSurrogate, arbitraryLowSurrogateLen))))do { static_assert( mozilla::detail::AssertionConditionType< decltype(!IsUtf8(AsChars(Span(arbitraryLowSurrogate, arbitraryLowSurrogateLen ))))>::isValid, "invalid assertion condition"); if ((__builtin_expect (!!(!(!!(!IsUtf8(AsChars(Span(arbitraryLowSurrogate, arbitraryLowSurrogateLen )))))), 0))) { do { } while (false); MOZ_ReportAssertionFailure ("!IsUtf8(AsChars(Span(arbitraryLowSurrogate, arbitraryLowSurrogateLen)))" , "/root/firefox-clang/mfbt/tests/TestUtf8.cpp", 331); do { } while (false); do { MOZ_CrashSequence(__null, 331); __attribute__ ((nomerge)) ::abort(); } while (false); } } while (false); | |||
| 332 | ||||
| 333 | ExpectBadCodePoint(arbitraryLowSurrogate, 0xDDEF, 3); | |||
| 334 | ||||
| 335 | static const unsigned char greatestSurrogate[] = {0xED, 0xBF, 0xBF, 0x0}; | |||
| 336 | constexpr size_t greatestSurrogateLen = std::size(greatestSurrogate) - 1; | |||
| 337 | MOZ_RELEASE_ASSERT(do { static_assert( mozilla::detail::AssertionConditionType< decltype(!IsUtf8(AsChars(Span(greatestSurrogate, greatestSurrogateLen ))))>::isValid, "invalid assertion condition"); if ((__builtin_expect (!!(!(!!(!IsUtf8(AsChars(Span(greatestSurrogate, greatestSurrogateLen )))))), 0))) { do { } while (false); MOZ_ReportAssertionFailure ("!IsUtf8(AsChars(Span(greatestSurrogate, greatestSurrogateLen)))" , "/root/firefox-clang/mfbt/tests/TestUtf8.cpp", 338); do { } while (false); do { MOZ_CrashSequence(__null, 338); __attribute__ ((nomerge)) ::abort(); } while (false); } } while (false) | |||
| 338 | !IsUtf8(AsChars(Span(greatestSurrogate, greatestSurrogateLen))))do { static_assert( mozilla::detail::AssertionConditionType< decltype(!IsUtf8(AsChars(Span(greatestSurrogate, greatestSurrogateLen ))))>::isValid, "invalid assertion condition"); if ((__builtin_expect (!!(!(!!(!IsUtf8(AsChars(Span(greatestSurrogate, greatestSurrogateLen )))))), 0))) { do { } while (false); MOZ_ReportAssertionFailure ("!IsUtf8(AsChars(Span(greatestSurrogate, greatestSurrogateLen)))" , "/root/firefox-clang/mfbt/tests/TestUtf8.cpp", 338); do { } while (false); do { MOZ_CrashSequence(__null, 338); __attribute__ ((nomerge)) ::abort(); } while (false); } } while (false); | |||
| 339 | ||||
| 340 | ExpectBadCodePoint(greatestSurrogate, 0xDFFF, 3); | |||
| 341 | ||||
| 342 | static const unsigned char justAfterSurrogates[] = {0xEE, 0x80, 0x80, 0x0}; | |||
| 343 | constexpr size_t justAfterSurrogatesLen = std::size(justAfterSurrogates) - 1; | |||
| 344 | MOZ_RELEASE_ASSERT(do { static_assert( mozilla::detail::AssertionConditionType< decltype(IsUtf8(AsChars(Span(justAfterSurrogates, justAfterSurrogatesLen ))))>::isValid, "invalid assertion condition"); if ((__builtin_expect (!!(!(!!(IsUtf8(AsChars(Span(justAfterSurrogates, justAfterSurrogatesLen )))))), 0))) { do { } while (false); MOZ_ReportAssertionFailure ("IsUtf8(AsChars(Span(justAfterSurrogates, justAfterSurrogatesLen)))" , "/root/firefox-clang/mfbt/tests/TestUtf8.cpp", 345); do { } while (false); do { MOZ_CrashSequence(__null, 345); __attribute__ ((nomerge)) ::abort(); } while (false); } } while (false) | |||
| 345 | IsUtf8(AsChars(Span(justAfterSurrogates, justAfterSurrogatesLen))))do { static_assert( mozilla::detail::AssertionConditionType< decltype(IsUtf8(AsChars(Span(justAfterSurrogates, justAfterSurrogatesLen ))))>::isValid, "invalid assertion condition"); if ((__builtin_expect (!!(!(!!(IsUtf8(AsChars(Span(justAfterSurrogates, justAfterSurrogatesLen )))))), 0))) { do { } while (false); MOZ_ReportAssertionFailure ("IsUtf8(AsChars(Span(justAfterSurrogates, justAfterSurrogatesLen)))" , "/root/firefox-clang/mfbt/tests/TestUtf8.cpp", 345); do { } while (false); do { MOZ_CrashSequence(__null, 345); __attribute__ ((nomerge)) ::abort(); } while (false); } } while (false); | |||
| 346 | ||||
| 347 | ExpectValidCodePoint(justAfterSurrogates, 0xE000); | |||
| 348 | } | |||
| 349 | ||||
| 350 | static void TestDecodeOneValidUtf8CodePoint() { | |||
| 351 | // NOTE: DecodeOneUtf8CodePoint decodes only *non*-ASCII code points that | |||
| 352 | // consist of multiple code units, so there are no ASCII tests below. | |||
| 353 | ||||
| 354 | // Length two. | |||
| 355 | ||||
| 356 | ExpectValidCodePoint("", 0x80); // <control> | |||
| 357 | ExpectValidCodePoint("©", 0xA9); // COPYRIGHT SIGN | |||
| 358 | ExpectValidCodePoint("¶", 0xB6); // PILCROW SIGN | |||
| 359 | ExpectValidCodePoint("¾", 0xBE); // VULGAR FRACTION THREE QUARTERS | |||
| 360 | ExpectValidCodePoint("÷", 0xF7); // DIVISION SIGN | |||
| 361 | ExpectValidCodePoint("ÿ", 0xFF); // LATIN SMALL LETTER Y WITH DIAERESIS | |||
| 362 | ExpectValidCodePoint("Ā", 0x100); // LATIN CAPITAL LETTER A WITH MACRON | |||
| 363 | ExpectValidCodePoint("IJ", 0x132); // LATIN CAPITAL LETTER LIGATURE IJ | |||
| 364 | ExpectValidCodePoint("ͼ", 0x37C); // GREEK SMALL DOTTED LUNATE SIGMA SYMBOL | |||
| 365 | ExpectValidCodePoint("Ӝ", | |||
| 366 | 0x4DC); // CYRILLIC CAPITAL LETTER ZHE WITTH DIAERESIS | |||
| 367 | ExpectValidCodePoint("۩", 0x6E9); // ARABIC PLACE OF SAJDAH | |||
| 368 | ExpectValidCodePoint("߿", 0x7FF); // <not assigned> | |||
| 369 | ||||
| 370 | // Length three. | |||
| 371 | ||||
| 372 | ExpectValidCodePoint("ࠀ", 0x800); // SAMARITAN LETTER ALAF | |||
| 373 | ExpectValidCodePoint("ࡁ", 0x841); // MANDAIC LETTER AB | |||
| 374 | ExpectValidCodePoint("ࣿ", 0x8FF); // ARABIC MARK SIDEWAYS NOON GHUNNA | |||
| 375 | ExpectValidCodePoint("ஆ", 0xB86); // TAMIL LETTER AA | |||
| 376 | ExpectValidCodePoint("༃", | |||
| 377 | 0xF03); // TIBETAN MARK GTER YIG MGO -UM GTER TSHEG MA | |||
| 378 | ExpectValidCodePoint( | |||
| 379 | "࿉", | |||
| 380 | 0xFC9); // TIBETAN SYMBOL NOR BU (but on my system it really looks like | |||
| 381 | // SOFT-SERVE ICE CREAM FROM ABOVE THE PLANE if you ask me) | |||
| 382 | ExpectValidCodePoint("ဪ", 0x102A); // MYANMAR LETTER AU | |||
| 383 | ExpectValidCodePoint("ᚏ", 0x168F); // OGHAM LETTER RUIS | |||
| 384 | ExpectValidCodePoint("\xE2\x80\xA8", 0x2028); // (the hated) LINE SEPARATOR | |||
| 385 | ExpectValidCodePoint("\xE2\x80\xA9", | |||
| 386 | 0x2029); // (the hated) PARAGRAPH SEPARATOR | |||
| 387 | ExpectValidCodePoint("☬", 0x262C); // ADI SHAKTI | |||
| 388 | ExpectValidCodePoint("㊮", 0x32AE); // CIRCLED IDEOGRAPH RESOURCE | |||
| 389 | ExpectValidCodePoint("㏖", 0x33D6); // SQUARE MOL | |||
| 390 | ExpectValidCodePoint("ꔄ", 0xA504); // VAI SYLLABLE WEEN | |||
| 391 | ExpectValidCodePoint("ퟕ", 0xD7D5); // HANGUL JONGSEONG RIEUL-SSANGKIYEOK | |||
| 392 | ExpectValidCodePoint("", 0xD7FF); // <not assigned> | |||
| 393 | ExpectValidCodePoint("", 0xE000); // <Private Use> | |||
| 394 | ExpectValidCodePoint("鱗", 0xF9F2); // CJK COMPATIBILITY IDEOGRAPH-F9F | |||
| 395 | ExpectValidCodePoint( | |||
| 396 | "﷽", 0xFDFD); // ARABIC LIGATURE BISMILLAH AR-RAHMAN AR-RAHHHEEEEM | |||
| 397 | ExpectValidCodePoint("", 0xFFFF); // <not assigned> | |||
| 398 | ||||
| 399 | // Length four. | |||
| 400 | ExpectValidCodePoint("𐀀", 0x10000); // LINEAR B SYLLABLE B008 A | |||
| 401 | ExpectValidCodePoint("𔑀", 0x14440); // ANATOLIAN HIEROGLYPH A058 | |||
| 402 | ExpectValidCodePoint("𝛗", 0x1D6D7); // MATHEMATICAL BOLD SMALL PHI | |||
| 403 | ExpectValidCodePoint("💩", 0x1F4A9); // PILE OF POO | |||
| 404 | ExpectValidCodePoint("🔫", 0x1F52B); // PISTOL | |||
| 405 | ExpectValidCodePoint("🥌", 0x1F94C); // CURLING STONE | |||
| 406 | ExpectValidCodePoint("🥏", 0x1F94F); // FLYING DISC | |||
| 407 | ExpectValidCodePoint("𠍆", 0x20346); // CJK UNIFIED IDEOGRAPH-20346 | |||
| 408 | ExpectValidCodePoint("𡠺", 0x2183A); // CJK UNIFIED IDEOGRAPH-2183A | |||
| 409 | ExpectValidCodePoint("", 0x417F6); // <not assigned> | |||
| 410 | ExpectValidCodePoint("", 0x7E836); // <not assigned> | |||
| 411 | ExpectValidCodePoint("", 0xFEF67); // <Plane 15 Private Use> | |||
| 412 | ExpectValidCodePoint("", 0x10FFFF); // | |||
| 413 | } | |||
| 414 | ||||
| 415 | static void TestDecodeBadLeadUnit() { | |||
| 416 | // These tests are actually exhaustive. | |||
| 417 | ||||
| 418 | unsigned char badLead[] = {'\0', '\0'}; | |||
| 419 | ||||
| 420 | for (uint8_t lead : IntegerRange(0b1000'0000, 0b1100'0000)) { | |||
| 421 | badLead[0] = lead; | |||
| 422 | ExpectBadLeadUnit(badLead); | |||
| 423 | } | |||
| 424 | ||||
| 425 | { | |||
| 426 | uint8_t lead = 0b1111'1000; | |||
| 427 | do { | |||
| 428 | badLead[0] = lead; | |||
| 429 | ExpectBadLeadUnit(badLead); | |||
| 430 | if (lead == 0b1111'1111) { | |||
| 431 | break; | |||
| 432 | } | |||
| 433 | ||||
| 434 | lead++; | |||
| 435 | } while (true); | |||
| 436 | } | |||
| 437 | } | |||
| 438 | ||||
| 439 | static void TestTooFewOrBadTrailingUnits() { | |||
| 440 | // Lead unit indicates a two-byte code point. | |||
| 441 | ||||
| 442 | char truncatedTwo[] = {'\0', '\0'}; | |||
| 443 | char badTrailTwo[] = {'\0', '\0', '\0'}; | |||
| 444 | ||||
| 445 | for (uint8_t lead : IntegerRange(0b1100'0000, 0b1110'0000)) { | |||
| 446 | truncatedTwo[0] = lead; | |||
| 447 | ExpectNotEnoughUnits(truncatedTwo, 1, 2); | |||
| 448 | ||||
| 449 | badTrailTwo[0] = lead; | |||
| 450 | for (uint8_t trail : IntegerRange(0b0000'0000, 0b1000'0000)) { | |||
| 451 | badTrailTwo[1] = trail; | |||
| 452 | ExpectBadTrailingUnit(badTrailTwo, 2); | |||
| 453 | } | |||
| 454 | ||||
| 455 | for (uint8_t trail : IntegerRange(0b1100'0000, 0b1111'1111)) { | |||
| 456 | badTrailTwo[1] = trail; | |||
| 457 | ExpectBadTrailingUnit(badTrailTwo, 2); | |||
| 458 | } | |||
| 459 | } | |||
| 460 | ||||
| 461 | // Lead unit indicates a three-byte code point. | |||
| 462 | ||||
| 463 | char truncatedThreeOne[] = {'\0', '\0'}; | |||
| 464 | char truncatedThreeTwo[] = {'\0', '\0', '\0'}; | |||
| 465 | unsigned char badTrailThree[] = {'\0', '\0', '\0', '\0'}; | |||
| 466 | ||||
| 467 | for (uint8_t lead : IntegerRange(0b1110'0000, 0b1111'0000)) { | |||
| 468 | truncatedThreeOne[0] = lead; | |||
| 469 | ExpectNotEnoughUnits(truncatedThreeOne, 1, 3); | |||
| 470 | ||||
| 471 | truncatedThreeTwo[0] = lead; | |||
| 472 | ExpectNotEnoughUnits(truncatedThreeTwo, 2, 3); | |||
| 473 | ||||
| 474 | badTrailThree[0] = lead; | |||
| 475 | badTrailThree[2] = 0b1011'1111; // make valid to test overreads | |||
| 476 | for (uint8_t mid : IntegerRange(0b0000'0000, 0b1000'0000)) { | |||
| 477 | badTrailThree[1] = mid; | |||
| 478 | ExpectBadTrailingUnit(badTrailThree, 2); | |||
| 479 | } | |||
| 480 | { | |||
| 481 | uint8_t mid = 0b1100'0000; | |||
| 482 | do { | |||
| 483 | badTrailThree[1] = mid; | |||
| 484 | ExpectBadTrailingUnit(badTrailThree, 2); | |||
| 485 | if (mid == 0b1111'1111) { | |||
| 486 | break; | |||
| 487 | } | |||
| 488 | ||||
| 489 | mid++; | |||
| 490 | } while (true); | |||
| 491 | } | |||
| 492 | ||||
| 493 | badTrailThree[1] = 0b1011'1111; | |||
| 494 | for (uint8_t last : IntegerRange(0b0000'0000, 0b1000'0000)) { | |||
| 495 | badTrailThree[2] = last; | |||
| 496 | ExpectBadTrailingUnit(badTrailThree, 3); | |||
| 497 | } | |||
| 498 | { | |||
| 499 | uint8_t last = 0b1100'0000; | |||
| 500 | do { | |||
| 501 | badTrailThree[2] = last; | |||
| 502 | ExpectBadTrailingUnit(badTrailThree, 3); | |||
| 503 | if (last == 0b1111'1111) { | |||
| 504 | break; | |||
| 505 | } | |||
| 506 | ||||
| 507 | last++; | |||
| 508 | } while (true); | |||
| 509 | } | |||
| 510 | } | |||
| 511 | ||||
| 512 | // Lead unit indicates a four-byte code point. | |||
| 513 | ||||
| 514 | char truncatedFourOne[] = {'\0', '\0'}; | |||
| 515 | char truncatedFourTwo[] = {'\0', '\0', '\0'}; | |||
| 516 | char truncatedFourThree[] = {'\0', '\0', '\0', '\0'}; | |||
| 517 | ||||
| 518 | unsigned char badTrailFour[] = {'\0', '\0', '\0', '\0', '\0'}; | |||
| 519 | ||||
| 520 | for (uint8_t lead : IntegerRange(0b1111'0000, 0b1111'1000)) { | |||
| 521 | truncatedFourOne[0] = lead; | |||
| 522 | ExpectNotEnoughUnits(truncatedFourOne, 1, 4); | |||
| 523 | ||||
| 524 | truncatedFourTwo[0] = lead; | |||
| 525 | ExpectNotEnoughUnits(truncatedFourTwo, 2, 4); | |||
| 526 | ||||
| 527 | truncatedFourThree[0] = lead; | |||
| 528 | ExpectNotEnoughUnits(truncatedFourThree, 3, 4); | |||
| 529 | ||||
| 530 | badTrailFour[0] = lead; | |||
| 531 | badTrailFour[2] = badTrailFour[3] = 0b1011'1111; // test for overreads | |||
| 532 | for (uint8_t second : IntegerRange(0b0000'0000, 0b1000'0000)) { | |||
| 533 | badTrailFour[1] = second; | |||
| 534 | ExpectBadTrailingUnit(badTrailFour, 2); | |||
| 535 | } | |||
| 536 | { | |||
| 537 | uint8_t second = 0b1100'0000; | |||
| 538 | do { | |||
| 539 | badTrailFour[1] = second; | |||
| 540 | ExpectBadTrailingUnit(badTrailFour, 2); | |||
| 541 | if (second == 0b1111'1111) { | |||
| 542 | break; | |||
| 543 | } | |||
| 544 | ||||
| 545 | second++; | |||
| 546 | } while (true); | |||
| 547 | } | |||
| 548 | ||||
| 549 | badTrailFour[1] = badTrailFour[3] = 0b1011'1111; // test for overreads | |||
| 550 | for (uint8_t third : IntegerRange(0b0000'0000, 0b1000'0000)) { | |||
| 551 | badTrailFour[2] = third; | |||
| 552 | ExpectBadTrailingUnit(badTrailFour, 3); | |||
| 553 | } | |||
| 554 | { | |||
| 555 | uint8_t third = 0b1100'0000; | |||
| 556 | do { | |||
| 557 | badTrailFour[2] = third; | |||
| 558 | ExpectBadTrailingUnit(badTrailFour, 3); | |||
| 559 | if (third == 0b1111'1111) { | |||
| 560 | break; | |||
| 561 | } | |||
| 562 | ||||
| 563 | third++; | |||
| 564 | } while (true); | |||
| 565 | } | |||
| 566 | ||||
| 567 | badTrailFour[2] = 0b1011'1111; | |||
| 568 | for (uint8_t fourth : IntegerRange(0b0000'0000, 0b1000'0000)) { | |||
| 569 | badTrailFour[3] = fourth; | |||
| 570 | ExpectBadTrailingUnit(badTrailFour, 4); | |||
| 571 | } | |||
| 572 | { | |||
| 573 | uint8_t fourth = 0b1100'0000; | |||
| 574 | do { | |||
| 575 | badTrailFour[3] = fourth; | |||
| 576 | ExpectBadTrailingUnit(badTrailFour, 4); | |||
| 577 | if (fourth == 0b1111'1111) { | |||
| 578 | break; | |||
| 579 | } | |||
| 580 | ||||
| 581 | fourth++; | |||
| 582 | } while (true); | |||
| 583 | } | |||
| 584 | } | |||
| 585 | } | |||
| 586 | ||||
| 587 | static void TestBadSurrogate() { | |||
| 588 | // These tests are actually exhaustive. | |||
| 589 | ||||
| 590 | ExpectValidCodePoint("\xED\x9F\xBF", 0xD7FF); // last before surrogates | |||
| 591 | ExpectValidCodePoint("\xEE\x80\x80", 0xE000); // first after surrogates | |||
| 592 | ||||
| 593 | // First invalid surrogate encoding is { 0xED, 0xA0, 0x80 }. Last invalid | |||
| 594 | // surrogate encoding is { 0xED, 0xBF, 0xBF }. | |||
| 595 | ||||
| 596 | char badSurrogate[] = {'\xED', '\0', '\0', '\0'}; | |||
| 597 | ||||
| 598 | for (char32_t c = 0xD800; c < 0xE000; c++) { | |||
| 599 | badSurrogate[1] = 0b1000'0000 ^ ((c & 0b1111'1100'0000) >> 6); | |||
| 600 | badSurrogate[2] = 0b1000'0000 ^ ((c & 0b0000'0011'1111)); | |||
| 601 | ||||
| 602 | ExpectBadCodePoint(badSurrogate, c, 3); | |||
| 603 | } | |||
| 604 | } | |||
| 605 | ||||
| 606 | static void TestBadTooBig() { | |||
| 607 | // These tests are actually exhaustive. | |||
| 608 | ||||
| 609 | ExpectValidCodePoint("\xF4\x8F\xBF\xBF", 0x10'FFFF); // last code point | |||
| 610 | ||||
| 611 | // Four-byte code points are | |||
| 612 | // | |||
| 613 | // 0b1111'0xxx 0b10xx'xxxx 0b10xx'xxxx 0b10xx'xxxx | |||
| 614 | // | |||
| 615 | // with 3 + 6 + 6 + 6 == 21 unconstrained bytes, so the structurally | |||
| 616 | // representable limit (exclusive) is 2**21 - 1 == 2097152. | |||
| 617 | ||||
| 618 | char tooLargeCodePoint[] = {'\0', '\0', '\0', '\0', '\0'}; | |||
| 619 | ||||
| 620 | for (char32_t c = 0x11'0000; c < (1 << 21); c++) { | |||
| 621 | tooLargeCodePoint[0] = | |||
| 622 | 0b1111'0000 ^ ((c & 0b1'1100'0000'0000'0000'0000) >> 18); | |||
| 623 | tooLargeCodePoint[1] = | |||
| 624 | 0b1000'0000 ^ ((c & 0b0'0011'1111'0000'0000'0000) >> 12); | |||
| 625 | tooLargeCodePoint[2] = | |||
| 626 | 0b1000'0000 ^ ((c & 0b0'0000'0000'1111'1100'0000) >> 6); | |||
| 627 | tooLargeCodePoint[3] = 0b1000'0000 ^ ((c & 0b0'0000'0000'0000'0011'1111)); | |||
| 628 | ||||
| 629 | ExpectBadCodePoint(tooLargeCodePoint, c, 4); | |||
| 630 | } | |||
| 631 | } | |||
| 632 | ||||
| 633 | static void TestBadCodePoint() { | |||
| 634 | TestBadSurrogate(); | |||
| 635 | TestBadTooBig(); | |||
| 636 | } | |||
| 637 | ||||
| 638 | static void TestNotShortestForm() { | |||
| 639 | { | |||
| 640 | // One-byte in two-byte. | |||
| 641 | ||||
| 642 | char oneInTwo[] = {'\0', '\0', '\0'}; | |||
| 643 | ||||
| 644 | for (char32_t c = '\0'; c < 0x80; c++) { | |||
| 645 | oneInTwo[0] = 0b1100'0000 ^ ((c & 0b0111'1100'0000) >> 6); | |||
| 646 | oneInTwo[1] = 0b1000'0000 ^ ((c & 0b0000'0011'1111)); | |||
| 647 | ||||
| 648 | ExpectNotShortestForm(oneInTwo, c, 2); | |||
| 649 | } | |||
| 650 | ||||
| 651 | // One-byte in three-byte. | |||
| 652 | ||||
| 653 | char oneInThree[] = {'\0', '\0', '\0', '\0'}; | |||
| 654 | ||||
| 655 | for (char32_t c = '\0'; c < 0x80; c++) { | |||
| 656 | oneInThree[0] = 0b1110'0000 ^ ((c & 0b1111'0000'0000'0000) >> 12); | |||
| 657 | oneInThree[1] = 0b1000'0000 ^ ((c & 0b0000'1111'1100'0000) >> 6); | |||
| 658 | oneInThree[2] = 0b1000'0000 ^ ((c & 0b0000'0000'0011'1111)); | |||
| 659 | ||||
| 660 | ExpectNotShortestForm(oneInThree, c, 3); | |||
| 661 | } | |||
| 662 | ||||
| 663 | // One-byte in four-byte. | |||
| 664 | ||||
| 665 | char oneInFour[] = {'\0', '\0', '\0', '\0', '\0'}; | |||
| 666 | ||||
| 667 | for (char32_t c = '\0'; c < 0x80; c++) { | |||
| 668 | oneInFour[0] = 0b1111'0000 ^ ((c & 0b1'1100'0000'0000'0000'0000) >> 18); | |||
| 669 | oneInFour[1] = 0b1000'0000 ^ ((c & 0b0'0011'1111'0000'0000'0000) >> 12); | |||
| 670 | oneInFour[2] = 0b1000'0000 ^ ((c & 0b0'0000'0000'1111'1100'0000) >> 6); | |||
| 671 | oneInFour[3] = 0b1000'0000 ^ ((c & 0b0'0000'0000'0000'0011'1111)); | |||
| 672 | ||||
| 673 | ExpectNotShortestForm(oneInFour, c, 4); | |||
| 674 | } | |||
| 675 | } | |||
| 676 | ||||
| 677 | { | |||
| 678 | // Two-byte in three-byte. | |||
| 679 | ||||
| 680 | char twoInThree[] = {'\0', '\0', '\0', '\0'}; | |||
| 681 | ||||
| 682 | for (char32_t c = 0x80; c < 0x800; c++) { | |||
| 683 | twoInThree[0] = 0b1110'0000 ^ ((c & 0b1111'0000'0000'0000) >> 12); | |||
| 684 | twoInThree[1] = 0b1000'0000 ^ ((c & 0b0000'1111'1100'0000) >> 6); | |||
| 685 | twoInThree[2] = 0b1000'0000 ^ ((c & 0b0000'0000'0011'1111)); | |||
| 686 | ||||
| 687 | ExpectNotShortestForm(twoInThree, c, 3); | |||
| 688 | } | |||
| 689 | ||||
| 690 | // Two-byte in four-byte. | |||
| 691 | ||||
| 692 | char twoInFour[] = {'\0', '\0', '\0', '\0', '\0'}; | |||
| 693 | ||||
| 694 | for (char32_t c = 0x80; c < 0x800; c++) { | |||
| 695 | twoInFour[0] = 0b1111'0000 ^ ((c & 0b1'1100'0000'0000'0000'0000) >> 18); | |||
| 696 | twoInFour[1] = 0b1000'0000 ^ ((c & 0b0'0011'1111'0000'0000'0000) >> 12); | |||
| 697 | twoInFour[2] = 0b1000'0000 ^ ((c & 0b0'0000'0000'1111'1100'0000) >> 6); | |||
| 698 | twoInFour[3] = 0b1000'0000 ^ ((c & 0b0'0000'0000'0000'0011'1111)); | |||
| 699 | ||||
| 700 | ExpectNotShortestForm(twoInFour, c, 4); | |||
| 701 | } | |||
| 702 | } | |||
| 703 | ||||
| 704 | { | |||
| 705 | // Three-byte in four-byte. | |||
| 706 | ||||
| 707 | char threeInFour[] = {'\0', '\0', '\0', '\0', '\0'}; | |||
| 708 | ||||
| 709 | for (char32_t c = 0x800; c < 0x1'0000; c++) { | |||
| 710 | threeInFour[0] = 0b1111'0000 ^ ((c & 0b1'1100'0000'0000'0000'0000) >> 18); | |||
| 711 | threeInFour[1] = 0b1000'0000 ^ ((c & 0b0'0011'1111'0000'0000'0000) >> 12); | |||
| 712 | threeInFour[2] = 0b1000'0000 ^ ((c & 0b0'0000'0000'1111'1100'0000) >> 6); | |||
| 713 | threeInFour[3] = 0b1000'0000 ^ ((c & 0b0'0000'0000'0000'0011'1111)); | |||
| 714 | ||||
| 715 | ExpectNotShortestForm(threeInFour, c, 4); | |||
| 716 | } | |||
| 717 | } | |||
| 718 | } | |||
| 719 | ||||
| 720 | static void TestDecodeOneInvalidUtf8CodePoint() { | |||
| 721 | TestDecodeBadLeadUnit(); | |||
| 722 | TestTooFewOrBadTrailingUnits(); | |||
| 723 | TestBadCodePoint(); | |||
| 724 | TestNotShortestForm(); | |||
| 725 | } | |||
| 726 | ||||
| 727 | static void TestDecodeOneUtf8CodePoint() { | |||
| 728 | TestDecodeOneValidUtf8CodePoint(); | |||
| 729 | TestDecodeOneInvalidUtf8CodePoint(); | |||
| 730 | } | |||
| 731 | ||||
| 732 | int main() { | |||
| 733 | TestUtf8Unit(); | |||
| 734 | TestIsUtf8(); | |||
| 735 | TestDecodeOneUtf8CodePoint(); | |||
| 736 | return 0; | |||
| 737 | } |