| /* |
| * Copyright 2026 Rive |
| */ |
| |
| #include <catch.hpp> |
| #include "rive/text/utf.hpp" |
| |
| using namespace rive; |
| |
| // Decode a surrogate pair back to the code point it stands for. |
| static Unichar fromSurrogatePair(uint16_t hi, uint16_t lo) |
| { |
| return 0x10000 + ((Unichar(hi) - 0xD800) << 10) + (Unichar(lo) - 0xDC00); |
| } |
| |
| TEST_CASE("BMP code points encode to a single UTF-16 unit", "[utf]") |
| { |
| uint16_t utf16[2]; |
| for (Unichar uni : {Unichar(0), |
| Unichar('A'), |
| Unichar(0xD7FF), |
| Unichar(0xE000), |
| Unichar(0xFFFF)}) |
| { |
| REQUIRE(UTF::ToUTF16(uni, utf16) == 1); |
| CHECK(utf16[0] == uni); |
| } |
| } |
| |
| TEST_CASE("supplementary code points encode to a valid surrogate pair", "[utf]") |
| { |
| // 0xD835/0xDC0C is MATHEMATICAL BOLD CAPITAL M; the old bit-or shortcut |
| // produced 0xD7F5 for its lead unit, which is not a surrogate at all. |
| struct |
| { |
| Unichar uni; |
| uint16_t hi, lo; |
| } cases[] = { |
| {0x10000, 0xD800, 0xDC00}, |
| {0x1D40C, 0xD835, 0xDC0C}, |
| {0x1F600, 0xD83D, 0xDE00}, |
| {0x10FFFF, 0xDBFF, 0xDFFF}, |
| }; |
| |
| uint16_t utf16[2]; |
| for (auto& c : cases) |
| { |
| REQUIRE(UTF::ToUTF16(c.uni, utf16) == 2); |
| CHECK(utf16[0] == c.hi); |
| CHECK(utf16[1] == c.lo); |
| } |
| } |
| |
| TEST_CASE("every supplementary code point round trips through UTF-16", "[utf]") |
| { |
| uint16_t utf16[2]; |
| for (Unichar uni = 0x10000; uni <= 0x10FFFF; ++uni) |
| { |
| REQUIRE(UTF::ToUTF16(uni, utf16) == 2); |
| REQUIRE(utf16[0] >= 0xD800); |
| REQUIRE(utf16[0] <= 0xDBFF); |
| REQUIRE(utf16[1] >= 0xDC00); |
| REQUIRE(utf16[1] <= 0xDFFF); |
| REQUIRE(fromSurrogatePair(utf16[0], utf16[1]) == uni); |
| } |
| } |