diff options
author | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-04-28 14:29:10 +0000 |
---|---|---|
committer | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-04-28 14:29:10 +0000 |
commit | 2aa4a82499d4becd2284cdb482213d541b8804dd (patch) | |
tree | b80bf8bf13c3766139fbacc530efd0dd9d54394c /js/src/jsapi-tests/testAtomizeUtf8NonAsciiLatin1CodePoint.cpp | |
parent | Initial commit. (diff) | |
download | firefox-2aa4a82499d4becd2284cdb482213d541b8804dd.tar.xz firefox-2aa4a82499d4becd2284cdb482213d541b8804dd.zip |
Adding upstream version 86.0.1.upstream/86.0.1upstream
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'js/src/jsapi-tests/testAtomizeUtf8NonAsciiLatin1CodePoint.cpp')
-rw-r--r-- | js/src/jsapi-tests/testAtomizeUtf8NonAsciiLatin1CodePoint.cpp | 213 |
1 files changed, 213 insertions, 0 deletions
diff --git a/js/src/jsapi-tests/testAtomizeUtf8NonAsciiLatin1CodePoint.cpp b/js/src/jsapi-tests/testAtomizeUtf8NonAsciiLatin1CodePoint.cpp new file mode 100644 index 0000000000..967f764ac4 --- /dev/null +++ b/js/src/jsapi-tests/testAtomizeUtf8NonAsciiLatin1CodePoint.cpp @@ -0,0 +1,213 @@ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +#include "mozilla/Maybe.h" // mozilla::Maybe +#include "mozilla/Utf8.h" // mozilla::IsTrailingUnit, mozilla::Utf8Unit, mozilla::DecodeOneUtf8CodePoint + +#include <inttypes.h> // UINT8_MAX +#include <stdint.h> // uint16_t + +#include "jsapi.h" // JS_IsExceptionPending, JS_ClearPendingException + +#include "js/RootingAPI.h" // JS::Rooted, JS::MutableHandle +#include "jsapi-tests/tests.h" // BEGIN_TEST, END_TEST, CHECK +#include "vm/JSAtom.h" // js::AtomizeChars, js::AtomizeUTF8Chars +#include "vm/StringType.h" // JSAtom + +using mozilla::DecodeOneUtf8CodePoint; +using mozilla::IsAscii; +using mozilla::IsTrailingUnit; +using mozilla::Maybe; +using mozilla::Utf8Unit; + +using JS::Latin1Char; +using JS::MutableHandle; +using JS::Rooted; + +BEGIN_TEST(testAtomizeTwoByteUTF8) { + Rooted<JSAtom*> atom16(cx); + Rooted<JSAtom*> atom8(cx); + + for (uint16_t i = 0; i <= UINT8_MAX; i++) { + // Test cases where the first unit is ASCII. + if (IsAscii(char16_t(i))) { + for (uint16_t j = 0; j <= UINT8_MAX; j++) { + if (IsAscii(char16_t(j))) { + // If both units are ASCII, the sequence encodes a two-code point + // string. + if (!shouldBeTwoCodePoints(i, j, &atom16, &atom8)) { + return false; + } + } else { + // ASCII followed by non-ASCII should be invalid. + if (!shouldBeInvalid(i, j)) { + return false; + } + } + } + + continue; + } + + // Test remaining cases where the first unit isn't a two-byte lead. + if ((i & 0b1110'0000) != 0b1100'0000) { + for (uint16_t j = 0; j <= UINT8_MAX; j++) { + // If the first unit isn't a two-byte lead, the sequence is invalid no + // matter what the second unit is. + if (!shouldBeInvalid(i, j)) { + return false; + } + } + + continue; + } + + // Test remaining cases where the first unit is the two-byte lead of a + // non-Latin-1 code point. + if (i >= 0b1100'0100) { + for (uint16_t j = 0; j <= UINT8_MAX; j++) { + if (IsTrailingUnit(Utf8Unit(static_cast<uint8_t>(j)))) { + if (!shouldBeSingleNonLatin1(i, j, &atom16, &atom8)) { + return false; + } + } else { + if (!shouldBeInvalid(i, j)) { + return false; + } + } + } + + continue; + } + + // Test remaining cases where the first unit is the two-byte lead of an + // overlong ASCII code point. + if (i < 0b1100'0010) { + for (uint16_t j = 0; j <= UINT8_MAX; j++) { + if (!shouldBeInvalid(i, j)) { + return false; + } + } + + continue; + } + + // Finally, test remaining cases where the first unit is the two-byte lead + // of a Latin-1 code point. + for (uint16_t j = 0; j <= UINT8_MAX; j++) { + if (IsTrailingUnit(Utf8Unit(static_cast<uint8_t>(j)))) { + if (!shouldBeSingleLatin1(i, j, &atom16, &atom8)) { + return false; + } + } else { + if (!shouldBeInvalid(i, j)) { + return false; + } + } + } + } + + return true; +} + +bool shouldBeTwoCodePoints(uint16_t first, uint16_t second, + MutableHandle<JSAtom*> atom16, + MutableHandle<JSAtom*> atom8) { + CHECK(first <= UINT8_MAX); + CHECK(second <= UINT8_MAX); + CHECK(IsAscii(char16_t(first))); + CHECK(IsAscii(char16_t(second))); + + const char16_t utf16[] = {static_cast<char16_t>(first), + static_cast<char16_t>(second)}; + atom16.set(js::AtomizeChars(cx, utf16, 2)); + CHECK(atom16); + CHECK(atom16->length() == 2); + CHECK(atom16->latin1OrTwoByteChar(0) == first); + CHECK(atom16->latin1OrTwoByteChar(1) == second); + + const char utf8[] = {static_cast<char>(first), static_cast<char>(second)}; + atom8.set(js::AtomizeUTF8Chars(cx, utf8, 2)); + CHECK(atom8); + CHECK(atom8->length() == 2); + CHECK(atom8->latin1OrTwoByteChar(0) == first); + CHECK(atom8->latin1OrTwoByteChar(1) == second); + + CHECK(atom16 == atom8); + + return true; +} + +bool shouldBeOneCodePoint(uint16_t first, uint16_t second, char32_t v, + MutableHandle<JSAtom*> atom16, + MutableHandle<JSAtom*> atom8) { + CHECK(first <= UINT8_MAX); + CHECK(second <= UINT8_MAX); + CHECK(v <= UINT16_MAX); + + const char16_t utf16[] = {static_cast<char16_t>(v)}; + atom16.set(js::AtomizeChars(cx, utf16, 1)); + CHECK(atom16); + CHECK(atom16->length() == 1); + CHECK(atom16->latin1OrTwoByteChar(0) == v); + + const char utf8[] = {static_cast<char>(first), static_cast<char>(second)}; + atom8.set(js::AtomizeUTF8Chars(cx, utf8, 2)); + CHECK(atom8); + CHECK(atom8->length() == 1); + CHECK(atom8->latin1OrTwoByteChar(0) == v); + + CHECK(atom16 == atom8); + + return true; +} + +bool shouldBeSingleNonLatin1(uint16_t first, uint16_t second, + MutableHandle<JSAtom*> atom16, + MutableHandle<JSAtom*> atom8) { + CHECK(first <= UINT8_MAX); + CHECK(second <= UINT8_MAX); + + const char bytes[] = {static_cast<char>(first), static_cast<char>(second)}; + const char* iter = &bytes[1]; + Maybe<char32_t> cp = + DecodeOneUtf8CodePoint(Utf8Unit(bytes[0]), &iter, bytes + 2); + CHECK(cp.isSome()); + + char32_t v = cp.value(); + CHECK(v > UINT8_MAX); + + return shouldBeOneCodePoint(first, second, v, atom16, atom8); +} + +bool shouldBeSingleLatin1(uint16_t first, uint16_t second, + MutableHandle<JSAtom*> atom16, + MutableHandle<JSAtom*> atom8) { + CHECK(first <= UINT8_MAX); + CHECK(second <= UINT8_MAX); + + const char bytes[] = {static_cast<char>(first), static_cast<char>(second)}; + const char* iter = &bytes[1]; + Maybe<char32_t> cp = + DecodeOneUtf8CodePoint(Utf8Unit(bytes[0]), &iter, bytes + 2); + CHECK(cp.isSome()); + + char32_t v = cp.value(); + CHECK(v <= UINT8_MAX); + + return shouldBeOneCodePoint(first, second, v, atom16, atom8); +} + +bool shouldBeInvalid(uint16_t first, uint16_t second) { + CHECK(first <= UINT8_MAX); + CHECK(second <= UINT8_MAX); + + const char invalid[] = {static_cast<char>(first), static_cast<char>(second)}; + CHECK(!js::AtomizeUTF8Chars(cx, invalid, 2)); + CHECK(JS_IsExceptionPending(cx)); + JS_ClearPendingException(cx); + + return true; +} +END_TEST(testAtomizeTwoByteUTF8) |