diff --git a/test/src/unit-unicode.cpp b/test/src/unit-unicode.cpp index 7b94db67..67e97346 100644 --- a/test/src/unit-unicode.cpp +++ b/test/src/unit-unicode.cpp @@ -74,523 +74,525 @@ void check_utf8string(bool success_expected, int byte1, int byte2 = -1, int byte } } -TEST_CASE("RFC 3629", "[hide]") +TEST_CASE("Unicode", "[hide]") { - /* - RFC 3629 describes in Sect. 4 the syntax of UTF-8 byte sequences as - follows: - - A UTF-8 string is a sequence of octets representing a sequence of UCS - characters. An octet sequence is valid UTF-8 only if it matches the - following syntax, which is derived from the rules for encoding UTF-8 - and is expressed in the ABNF of [RFC2234]. - - UTF8-octets = *( UTF8-char ) - UTF8-char = UTF8-1 / UTF8-2 / UTF8-3 / UTF8-4 - UTF8-1 = %x00-7F - UTF8-2 = %xC2-DF UTF8-tail - UTF8-3 = %xE0 %xA0-BF UTF8-tail / %xE1-EC 2( UTF8-tail ) / - %xED %x80-9F UTF8-tail / %xEE-EF 2( UTF8-tail ) - UTF8-4 = %xF0 %x90-BF 2( UTF8-tail ) / %xF1-F3 3( UTF8-tail ) / - %xF4 %x80-8F 2( UTF8-tail ) - UTF8-tail = %x80-BF - */ - - SECTION("ill-formed first byte") + SECTION("RFC 3629") { - for (int byte1 = 0x80; byte1 <= 0xC1; ++byte1) - { - check_utf8string(false, byte1); - } + /* + RFC 3629 describes in Sect. 4 the syntax of UTF-8 byte sequences as + follows: - for (int byte1 = 0xF5; byte1 <= 0xFF; ++byte1) - { - check_utf8string(false, byte1); - } - } + A UTF-8 string is a sequence of octets representing a sequence of UCS + characters. An octet sequence is valid UTF-8 only if it matches the + following syntax, which is derived from the rules for encoding UTF-8 + and is expressed in the ABNF of [RFC2234]. - SECTION("UTF8-1 (x00-x7F)") - { - SECTION("well-formed") + UTF8-octets = *( UTF8-char ) + UTF8-char = UTF8-1 / UTF8-2 / UTF8-3 / UTF8-4 + UTF8-1 = %x00-7F + UTF8-2 = %xC2-DF UTF8-tail + UTF8-3 = %xE0 %xA0-BF UTF8-tail / %xE1-EC 2( UTF8-tail ) / + %xED %x80-9F UTF8-tail / %xEE-EF 2( UTF8-tail ) + UTF8-4 = %xF0 %x90-BF 2( UTF8-tail ) / %xF1-F3 3( UTF8-tail ) / + %xF4 %x80-8F 2( UTF8-tail ) + UTF8-tail = %x80-BF + */ + + SECTION("ill-formed first byte") { - for (int byte1 = 0x00; byte1 <= 0x7F; ++byte1) + for (int byte1 = 0x80; byte1 <= 0xC1; ++byte1) { - // unescaped control characters are parse errors in JSON - if (0x00 <= byte1 and byte1 <= 0x1F) + check_utf8string(false, byte1); + } + + for (int byte1 = 0xF5; byte1 <= 0xFF; ++byte1) + { + check_utf8string(false, byte1); + } + } + + SECTION("UTF8-1 (x00-x7F)") + { + SECTION("well-formed") + { + for (int byte1 = 0x00; byte1 <= 0x7F; ++byte1) + { + // unescaped control characters are parse errors in JSON + if (0x00 <= byte1 and byte1 <= 0x1F) + { + check_utf8string(false, byte1); + continue; + } + + // a single quote is a parse error in JSON + if (byte1 == 0x22) + { + check_utf8string(false, byte1); + continue; + } + + // a single backslash is a parse error in JSON + if (byte1 == 0x5C) + { + check_utf8string(false, byte1); + continue; + } + + // all other characters are OK + check_utf8string(true, byte1); + } + } + } + + SECTION("UTF8-2 (xC2-xDF UTF8-tail)") + { + SECTION("well-formed") + { + for (int byte1 = 0xC2; byte1 <= 0xDF; ++byte1) + { + for (int byte2 = 0x80; byte2 <= 0xBF; ++byte2) + { + check_utf8string(true, byte1, byte2); + } + } + } + + SECTION("ill-formed: missing second byte") + { + for (int byte1 = 0xC2; byte1 <= 0xDF; ++byte1) { check_utf8string(false, byte1); - continue; } + } - // a single quote is a parse error in JSON - if (byte1 == 0x22) + SECTION("ill-formed: wrong second byte") + { + for (int byte1 = 0xC2; byte1 <= 0xDF; ++byte1) + { + for (int byte2 = 0x00; byte2 <= 0xFF; ++byte2) + { + // skip correct second byte + if (0x80 <= byte2 and byte2 <= 0xBF) + { + continue; + } + + check_utf8string(false, byte1, byte2); + } + } + } + } + + SECTION("UTF8-3 (xE0 xA0-BF UTF8-tail)") + { + SECTION("well-formed") + { + for (int byte1 = 0xE0; byte1 <= 0xE0; ++byte1) + { + for (int byte2 = 0xA0; byte2 <= 0xBF; ++byte2) + { + for (int byte3 = 0x80; byte3 <= 0xBF; ++byte3) + { + check_utf8string(true, byte1, byte2, byte3); + } + } + } + } + + SECTION("ill-formed: missing second byte") + { + for (int byte1 = 0xE0; byte1 <= 0xE0; ++byte1) { check_utf8string(false, byte1); - continue; } + } - // a single backslash is a parse error in JSON - if (byte1 == 0x5C) + SECTION("ill-formed: missing third byte") + { + for (int byte1 = 0xE0; byte1 <= 0xE0; ++byte1) + { + for (int byte2 = 0xA0; byte2 <= 0xBF; ++byte2) + { + check_utf8string(false, byte1, byte2); + } + } + } + + SECTION("ill-formed: wrong second byte") + { + for (int byte1 = 0xE0; byte1 <= 0xE0; ++byte1) + { + for (int byte2 = 0x00; byte2 <= 0xFF; ++byte2) + { + // skip correct second byte + if (0xA0 <= byte2 and byte2 <= 0xBF) + { + continue; + } + + for (int byte3 = 0x80; byte3 <= 0xBF; ++byte3) + { + check_utf8string(false, byte1, byte2, byte3); + } + } + } + } + + SECTION("ill-formed: wrong third byte") + { + for (int byte1 = 0xE0; byte1 <= 0xE0; ++byte1) + { + for (int byte2 = 0xA0; byte2 <= 0xBF; ++byte2) + { + for (int byte3 = 0x00; byte3 <= 0xFF; ++byte3) + { + // skip correct third byte + if (0x80 <= byte3 and byte3 <= 0xBF) + { + continue; + } + + check_utf8string(false, byte1, byte2, byte3); + } + } + } + } + } + + SECTION("UTF8-3 (xE1-xEC UTF8-tail UTF8-tail)") + { + SECTION("well-formed") + { + for (int byte1 = 0xE1; byte1 <= 0xEC; ++byte1) + { + for (int byte2 = 0x80; byte2 <= 0xBF; ++byte2) + { + for (int byte3 = 0x80; byte3 <= 0xBF; ++byte3) + { + check_utf8string(true, byte1, byte2, byte3); + } + } + } + } + + SECTION("ill-formed: missing second byte") + { + for (int byte1 = 0xE1; byte1 <= 0xEC; ++byte1) { check_utf8string(false, byte1); - continue; - } - - // all other characters are OK - check_utf8string(true, byte1); - } - } - } - - SECTION("UTF8-2 (xC2-xDF UTF8-tail)") - { - SECTION("well-formed") - { - for (int byte1 = 0xC2; byte1 <= 0xDF; ++byte1) - { - for (int byte2 = 0x80; byte2 <= 0xBF; ++byte2) - { - check_utf8string(true, byte1, byte2); } } - } - SECTION("ill-formed: missing second byte") - { - for (int byte1 = 0xC2; byte1 <= 0xDF; ++byte1) + SECTION("ill-formed: missing third byte") { - check_utf8string(false, byte1); - } - } - - SECTION("ill-formed: wrong second byte") - { - for (int byte1 = 0xC2; byte1 <= 0xDF; ++byte1) - { - for (int byte2 = 0x00; byte2 <= 0xFF; ++byte2) + for (int byte1 = 0xE1; byte1 <= 0xEC; ++byte1) { - // skip correct second byte - if (0x80 <= byte2 and byte2 <= 0xBF) + for (int byte2 = 0x80; byte2 <= 0xBF; ++byte2) { - continue; - } - - check_utf8string(false, byte1, byte2); - } - } - } - } - - SECTION("UTF8-3 (xE0 xA0-BF UTF8-tail)") - { - SECTION("well-formed") - { - for (int byte1 = 0xE0; byte1 <= 0xE0; ++byte1) - { - for (int byte2 = 0xA0; byte2 <= 0xBF; ++byte2) - { - for (int byte3 = 0x80; byte3 <= 0xBF; ++byte3) - { - check_utf8string(true, byte1, byte2, byte3); + check_utf8string(false, byte1, byte2); } } } - } - SECTION("ill-formed: missing second byte") - { - for (int byte1 = 0xE0; byte1 <= 0xE0; ++byte1) + SECTION("ill-formed: wrong second byte") { - check_utf8string(false, byte1); - } - } - - SECTION("ill-formed: missing third byte") - { - for (int byte1 = 0xE0; byte1 <= 0xE0; ++byte1) - { - for (int byte2 = 0xA0; byte2 <= 0xBF; ++byte2) + for (int byte1 = 0xE1; byte1 <= 0xEC; ++byte1) { - check_utf8string(false, byte1, byte2); - } - } - } - - SECTION("ill-formed: wrong second byte") - { - for (int byte1 = 0xE0; byte1 <= 0xE0; ++byte1) - { - for (int byte2 = 0x00; byte2 <= 0xFF; ++byte2) - { - // skip correct second byte - if (0xA0 <= byte2 and byte2 <= 0xBF) + for (int byte2 = 0x00; byte2 <= 0xFF; ++byte2) { - continue; - } - - for (int byte3 = 0x80; byte3 <= 0xBF; ++byte3) - { - check_utf8string(false, byte1, byte2, byte3); - } - } - } - } - - SECTION("ill-formed: wrong third byte") - { - for (int byte1 = 0xE0; byte1 <= 0xE0; ++byte1) - { - for (int byte2 = 0xA0; byte2 <= 0xBF; ++byte2) - { - for (int byte3 = 0x00; byte3 <= 0xFF; ++byte3) - { - // skip correct third byte - if (0x80 <= byte3 and byte3 <= 0xBF) + // skip correct second byte + if (0x80 <= byte2 and byte2 <= 0xBF) { continue; } - check_utf8string(false, byte1, byte2, byte3); + for (int byte3 = 0x80; byte3 <= 0xBF; ++byte3) + { + check_utf8string(false, byte1, byte2, byte3); + } } } } - } - } - SECTION("UTF8-3 (xE1-xEC UTF8-tail UTF8-tail)") - { - SECTION("well-formed") - { - for (int byte1 = 0xE1; byte1 <= 0xEC; ++byte1) + SECTION("ill-formed: wrong third byte") { - for (int byte2 = 0x80; byte2 <= 0xBF; ++byte2) + for (int byte1 = 0xE1; byte1 <= 0xEC; ++byte1) { - for (int byte3 = 0x80; byte3 <= 0xBF; ++byte3) + for (int byte2 = 0x80; byte2 <= 0xBF; ++byte2) { - check_utf8string(true, byte1, byte2, byte3); + for (int byte3 = 0x00; byte3 <= 0xFF; ++byte3) + { + // skip correct third byte + if (0x80 <= byte3 and byte3 <= 0xBF) + { + continue; + } + + check_utf8string(false, byte1, byte2, byte3); + } } } } } - SECTION("ill-formed: missing second byte") + SECTION("UTF8-3 (xED x80-9F UTF8-tail)") { - for (int byte1 = 0xE1; byte1 <= 0xEC; ++byte1) + SECTION("well-formed") { - check_utf8string(false, byte1); - } - } - - SECTION("ill-formed: missing third byte") - { - for (int byte1 = 0xE1; byte1 <= 0xEC; ++byte1) - { - for (int byte2 = 0x80; byte2 <= 0xBF; ++byte2) + for (int byte1 = 0xED; byte1 <= 0xED; ++byte1) { - check_utf8string(false, byte1, byte2); - } - } - } - - SECTION("ill-formed: wrong second byte") - { - for (int byte1 = 0xE1; byte1 <= 0xEC; ++byte1) - { - for (int byte2 = 0x00; byte2 <= 0xFF; ++byte2) - { - // skip correct second byte - if (0x80 <= byte2 and byte2 <= 0xBF) + for (int byte2 = 0x80; byte2 <= 0x9F; ++byte2) { - continue; - } - - for (int byte3 = 0x80; byte3 <= 0xBF; ++byte3) - { - check_utf8string(false, byte1, byte2, byte3); + for (int byte3 = 0x80; byte3 <= 0xBF; ++byte3) + { + check_utf8string(true, byte1, byte2, byte3); + } } } } - } - SECTION("ill-formed: wrong third byte") - { - for (int byte1 = 0xE1; byte1 <= 0xEC; ++byte1) + SECTION("ill-formed: missing second byte") { - for (int byte2 = 0x80; byte2 <= 0xBF; ++byte2) + for (int byte1 = 0xED; byte1 <= 0xED; ++byte1) { - for (int byte3 = 0x00; byte3 <= 0xFF; ++byte3) + check_utf8string(false, byte1); + } + } + + SECTION("ill-formed: missing third byte") + { + for (int byte1 = 0xED; byte1 <= 0xED; ++byte1) + { + for (int byte2 = 0x80; byte2 <= 0x9F; ++byte2) { - // skip correct third byte - if (0x80 <= byte3 and byte3 <= 0xBF) + check_utf8string(false, byte1, byte2); + } + } + } + + SECTION("ill-formed: wrong second byte") + { + for (int byte1 = 0xED; byte1 <= 0xED; ++byte1) + { + for (int byte2 = 0x00; byte2 <= 0xFF; ++byte2) + { + // skip correct second byte + if (0x80 <= byte2 and byte2 <= 0x9F) { continue; } - check_utf8string(false, byte1, byte2, byte3); + for (int byte3 = 0x80; byte3 <= 0xBF; ++byte3) + { + check_utf8string(false, byte1, byte2, byte3); + } } } } - } - } - SECTION("UTF8-3 (xED x80-9F UTF8-tail)") - { - SECTION("well-formed") - { - for (int byte1 = 0xED; byte1 <= 0xED; ++byte1) + SECTION("ill-formed: wrong third byte") { - for (int byte2 = 0x80; byte2 <= 0x9F; ++byte2) + for (int byte1 = 0xED; byte1 <= 0xED; ++byte1) { - for (int byte3 = 0x80; byte3 <= 0xBF; ++byte3) + for (int byte2 = 0x80; byte2 <= 0x9F; ++byte2) { - check_utf8string(true, byte1, byte2, byte3); + for (int byte3 = 0x00; byte3 <= 0xFF; ++byte3) + { + // skip correct third byte + if (0x80 <= byte3 and byte3 <= 0xBF) + { + continue; + } + + check_utf8string(false, byte1, byte2, byte3); + } } } } } - SECTION("ill-formed: missing second byte") + SECTION("UTF8-3 (xEE-xEF UTF8-tail UTF8-tail)") { - for (int byte1 = 0xED; byte1 <= 0xED; ++byte1) + SECTION("well-formed") { - check_utf8string(false, byte1); - } - } - - SECTION("ill-formed: missing third byte") - { - for (int byte1 = 0xED; byte1 <= 0xED; ++byte1) - { - for (int byte2 = 0x80; byte2 <= 0x9F; ++byte2) + for (int byte1 = 0xEE; byte1 <= 0xEF; ++byte1) { - check_utf8string(false, byte1, byte2); - } - } - } - - SECTION("ill-formed: wrong second byte") - { - for (int byte1 = 0xED; byte1 <= 0xED; ++byte1) - { - for (int byte2 = 0x00; byte2 <= 0xFF; ++byte2) - { - // skip correct second byte - if (0x80 <= byte2 and byte2 <= 0x9F) + for (int byte2 = 0x80; byte2 <= 0xBF; ++byte2) { - continue; - } - - for (int byte3 = 0x80; byte3 <= 0xBF; ++byte3) - { - check_utf8string(false, byte1, byte2, byte3); + for (int byte3 = 0x80; byte3 <= 0xBF; ++byte3) + { + check_utf8string(true, byte1, byte2, byte3); + } } } } - } - SECTION("ill-formed: wrong third byte") - { - for (int byte1 = 0xED; byte1 <= 0xED; ++byte1) + SECTION("ill-formed: missing second byte") { - for (int byte2 = 0x80; byte2 <= 0x9F; ++byte2) + for (int byte1 = 0xEE; byte1 <= 0xEF; ++byte1) { - for (int byte3 = 0x00; byte3 <= 0xFF; ++byte3) + check_utf8string(false, byte1); + } + } + + SECTION("ill-formed: missing third byte") + { + for (int byte1 = 0xEE; byte1 <= 0xEF; ++byte1) + { + for (int byte2 = 0x80; byte2 <= 0xBF; ++byte2) { - // skip correct third byte - if (0x80 <= byte3 and byte3 <= 0xBF) + check_utf8string(false, byte1, byte2); + } + } + } + + SECTION("ill-formed: wrong second byte") + { + for (int byte1 = 0xEE; byte1 <= 0xEF; ++byte1) + { + for (int byte2 = 0x00; byte2 <= 0xFF; ++byte2) + { + // skip correct second byte + if (0x80 <= byte2 and byte2 <= 0xBF) { continue; } - check_utf8string(false, byte1, byte2, byte3); + for (int byte3 = 0x80; byte3 <= 0xBF; ++byte3) + { + check_utf8string(false, byte1, byte2, byte3); + } } } } - } - } - SECTION("UTF8-3 (xEE-xEF UTF8-tail UTF8-tail)") - { - SECTION("well-formed") - { - for (int byte1 = 0xEE; byte1 <= 0xEF; ++byte1) + SECTION("ill-formed: wrong third byte") { - for (int byte2 = 0x80; byte2 <= 0xBF; ++byte2) + for (int byte1 = 0xEE; byte1 <= 0xEF; ++byte1) { - for (int byte3 = 0x80; byte3 <= 0xBF; ++byte3) + for (int byte2 = 0x80; byte2 <= 0xBF; ++byte2) { - check_utf8string(true, byte1, byte2, byte3); + for (int byte3 = 0x00; byte3 <= 0xFF; ++byte3) + { + // skip correct third byte + if (0x80 <= byte3 and byte3 <= 0xBF) + { + continue; + } + + check_utf8string(false, byte1, byte2, byte3); + } } } } } - SECTION("ill-formed: missing second byte") + SECTION("UTF8-4 (xF0 x90-BF UTF8-tail UTF8-tail)") { - for (int byte1 = 0xEE; byte1 <= 0xEF; ++byte1) + SECTION("well-formed") { - check_utf8string(false, byte1); - } - } - - SECTION("ill-formed: missing third byte") - { - for (int byte1 = 0xEE; byte1 <= 0xEF; ++byte1) - { - for (int byte2 = 0x80; byte2 <= 0xBF; ++byte2) + for (int byte1 = 0xF0; byte1 <= 0xF0; ++byte1) { - check_utf8string(false, byte1, byte2); - } - } - } - - SECTION("ill-formed: wrong second byte") - { - for (int byte1 = 0xEE; byte1 <= 0xEF; ++byte1) - { - for (int byte2 = 0x00; byte2 <= 0xFF; ++byte2) - { - // skip correct second byte - if (0x80 <= byte2 and byte2 <= 0xBF) + for (int byte2 = 0x90; byte2 <= 0xBF; ++byte2) { - continue; - } - - for (int byte3 = 0x80; byte3 <= 0xBF; ++byte3) - { - check_utf8string(false, byte1, byte2, byte3); + for (int byte3 = 0x80; byte3 <= 0xBF; ++byte3) + { + for (int byte4 = 0x80; byte4 <= 0xBF; ++byte4) + { + check_utf8string(true, byte1, byte2, byte3, byte4); + } + } } } } - } - SECTION("ill-formed: wrong third byte") - { - for (int byte1 = 0xEE; byte1 <= 0xEF; ++byte1) + SECTION("ill-formed: missing second byte") { - for (int byte2 = 0x80; byte2 <= 0xBF; ++byte2) + for (int byte1 = 0xF0; byte1 <= 0xF0; ++byte1) { - for (int byte3 = 0x00; byte3 <= 0xFF; ++byte3) + check_utf8string(false, byte1); + } + } + + SECTION("ill-formed: missing third byte") + { + for (int byte1 = 0xF0; byte1 <= 0xF0; ++byte1) + { + for (int byte2 = 0x90; byte2 <= 0xBF; ++byte2) { - // skip correct third byte - if (0x80 <= byte3 and byte3 <= 0xBF) + check_utf8string(false, byte1, byte2); + } + } + } + + SECTION("ill-formed: missing fourth byte") + { + for (int byte1 = 0xF0; byte1 <= 0xF0; ++byte1) + { + for (int byte2 = 0x90; byte2 <= 0xBF; ++byte2) + { + for (int byte3 = 0x80; byte3 <= 0xBF; ++byte3) + { + check_utf8string(false, byte1, byte2, byte3); + } + } + } + } + + SECTION("ill-formed: wrong second byte") + { + for (int byte1 = 0xF0; byte1 <= 0xF0; ++byte1) + { + for (int byte2 = 0x00; byte2 <= 0xFF; ++byte2) + { + // skip correct second byte + if (0x90 <= byte2 and byte2 <= 0xBF) { continue; } - check_utf8string(false, byte1, byte2, byte3); - } - } - } - } - } - - SECTION("UTF8-4 (xF0 x90-BF UTF8-tail UTF8-tail)") - { - SECTION("well-formed") - { - for (int byte1 = 0xF0; byte1 <= 0xF0; ++byte1) - { - for (int byte2 = 0x90; byte2 <= 0xBF; ++byte2) - { - for (int byte3 = 0x80; byte3 <= 0xBF; ++byte3) - { - for (int byte4 = 0x80; byte4 <= 0xBF; ++byte4) + for (int byte3 = 0x80; byte3 <= 0xBF; ++byte3) { - check_utf8string(true, byte1, byte2, byte3, byte4); + for (int byte4 = 0x80; byte4 <= 0xBF; ++byte4) + { + check_utf8string(false, byte1, byte2, byte3, byte4); + } } } } } - } - SECTION("ill-formed: missing second byte") - { - for (int byte1 = 0xF0; byte1 <= 0xF0; ++byte1) + SECTION("ill-formed: wrong third byte") { - check_utf8string(false, byte1); - } - } - - SECTION("ill-formed: missing third byte") - { - for (int byte1 = 0xF0; byte1 <= 0xF0; ++byte1) - { - for (int byte2 = 0x90; byte2 <= 0xBF; ++byte2) + for (int byte1 = 0xF0; byte1 <= 0xF0; ++byte1) { - check_utf8string(false, byte1, byte2); - } - } - } - - SECTION("ill-formed: missing fourth byte") - { - for (int byte1 = 0xF0; byte1 <= 0xF0; ++byte1) - { - for (int byte2 = 0x90; byte2 <= 0xBF; ++byte2) - { - for (int byte3 = 0x80; byte3 <= 0xBF; ++byte3) + for (int byte2 = 0x90; byte2 <= 0xBF; ++byte2) { - check_utf8string(false, byte1, byte2, byte3); - } - } - } - } - - SECTION("ill-formed: wrong second byte") - { - for (int byte1 = 0xF0; byte1 <= 0xF0; ++byte1) - { - for (int byte2 = 0x00; byte2 <= 0xFF; ++byte2) - { - // skip correct second byte - if (0x90 <= byte2 and byte2 <= 0xBF) - { - continue; - } - - for (int byte3 = 0x80; byte3 <= 0xBF; ++byte3) - { - for (int byte4 = 0x80; byte4 <= 0xBF; ++byte4) + for (int byte3 = 0x00; byte3 <= 0xFF; ++byte3) { - check_utf8string(false, byte1, byte2, byte3, byte4); + // skip correct third byte + if (0x80 <= byte3 and byte3 <= 0xBF) + { + continue; + } + + for (int byte4 = 0x80; byte4 <= 0xBF; ++byte4) + { + check_utf8string(false, byte1, byte2, byte3, byte4); + } } } } } - } - SECTION("ill-formed: wrong third byte") - { - for (int byte1 = 0xF0; byte1 <= 0xF0; ++byte1) + SECTION("ill-formed: wrong fourth byte") { - for (int byte2 = 0x90; byte2 <= 0xBF; ++byte2) + for (int byte1 = 0xF0; byte1 <= 0xF0; ++byte1) { - for (int byte3 = 0x00; byte3 <= 0xFF; ++byte3) + for (int byte2 = 0x90; byte2 <= 0xBF; ++byte2) { - // skip correct third byte - if (0x80 <= byte3 and byte3 <= 0xBF) + for (int byte3 = 0x80; byte3 <= 0xBF; ++byte3) { - continue; - } - - for (int byte4 = 0x80; byte4 <= 0xBF; ++byte4) - { - check_utf8string(false, byte1, byte2, byte3, byte4); - } - } - } - } - } - - SECTION("ill-formed: wrong fourth byte") - { - for (int byte1 = 0xF0; byte1 <= 0xF0; ++byte1) - { - for (int byte2 = 0x90; byte2 <= 0xBF; ++byte2) - { - for (int byte3 = 0x80; byte3 <= 0xBF; ++byte3) - { for (int byte4 = 0x00; byte4 <= 0xFF; ++byte4) { // skip fourth second byte @@ -601,269 +603,263 @@ TEST_CASE("RFC 3629", "[hide]") check_utf8string(false, byte1, byte2, byte3, byte4); } - } - } - } - } - } - - SECTION("UTF8-4 (xF1-F3 UTF8-tail UTF8-tail UTF8-tail)") - { - SECTION("well-formed") - { - for (int byte1 = 0xF1; byte1 <= 0xF3; ++byte1) - { - for (int byte2 = 0x80; byte2 <= 0xBF; ++byte2) - { - for (int byte3 = 0x80; byte3 <= 0xBF; ++byte3) - { - for (int byte4 = 0x80; byte4 <= 0xBF; ++byte4) - { - check_utf8string(true, byte1, byte2, byte3, byte4); } } } } } - SECTION("ill-formed: missing second byte") + SECTION("UTF8-4 (xF1-F3 UTF8-tail UTF8-tail UTF8-tail)") { - for (int byte1 = 0xF1; byte1 <= 0xF3; ++byte1) + SECTION("well-formed") { - check_utf8string(false, byte1); - } - } - - SECTION("ill-formed: missing third byte") - { - for (int byte1 = 0xF1; byte1 <= 0xF3; ++byte1) - { - for (int byte2 = 0x80; byte2 <= 0xBF; ++byte2) + for (int byte1 = 0xF1; byte1 <= 0xF3; ++byte1) { - check_utf8string(false, byte1, byte2); - } - } - } - - SECTION("ill-formed: missing fourth byte") - { - for (int byte1 = 0xF1; byte1 <= 0xF3; ++byte1) - { - for (int byte2 = 0x80; byte2 <= 0xBF; ++byte2) - { - for (int byte3 = 0x80; byte3 <= 0xBF; ++byte3) + for (int byte2 = 0x80; byte2 <= 0xBF; ++byte2) { - check_utf8string(false, byte1, byte2, byte3); - } - } - } - } - - SECTION("ill-formed: wrong second byte") - { - for (int byte1 = 0xF1; byte1 <= 0xF3; ++byte1) - { - for (int byte2 = 0x00; byte2 <= 0xFF; ++byte2) - { - // skip correct second byte - if (0x80 <= byte2 and byte2 <= 0xBF) - { - continue; - } - - for (int byte3 = 0x80; byte3 <= 0xBF; ++byte3) - { - for (int byte4 = 0x80; byte4 <= 0xBF; ++byte4) + for (int byte3 = 0x80; byte3 <= 0xBF; ++byte3) { - check_utf8string(false, byte1, byte2, byte3, byte4); + for (int byte4 = 0x80; byte4 <= 0xBF; ++byte4) + { + check_utf8string(true, byte1, byte2, byte3, byte4); + } } } } } - } - SECTION("ill-formed: wrong third byte") - { - for (int byte1 = 0xF1; byte1 <= 0xF3; ++byte1) + SECTION("ill-formed: missing second byte") { - for (int byte2 = 0x80; byte2 <= 0xBF; ++byte2) + for (int byte1 = 0xF1; byte1 <= 0xF3; ++byte1) { - for (int byte3 = 0x00; byte3 <= 0xFF; ++byte3) + check_utf8string(false, byte1); + } + } + + SECTION("ill-formed: missing third byte") + { + for (int byte1 = 0xF1; byte1 <= 0xF3; ++byte1) + { + for (int byte2 = 0x80; byte2 <= 0xBF; ++byte2) { - // skip correct third byte - if (0x80 <= byte3 and byte3 <= 0xBF) + check_utf8string(false, byte1, byte2); + } + } + } + + SECTION("ill-formed: missing fourth byte") + { + for (int byte1 = 0xF1; byte1 <= 0xF3; ++byte1) + { + for (int byte2 = 0x80; byte2 <= 0xBF; ++byte2) + { + for (int byte3 = 0x80; byte3 <= 0xBF; ++byte3) + { + check_utf8string(false, byte1, byte2, byte3); + } + } + } + } + + SECTION("ill-formed: wrong second byte") + { + for (int byte1 = 0xF1; byte1 <= 0xF3; ++byte1) + { + for (int byte2 = 0x00; byte2 <= 0xFF; ++byte2) + { + // skip correct second byte + if (0x80 <= byte2 and byte2 <= 0xBF) { continue; } - for (int byte4 = 0x80; byte4 <= 0xBF; ++byte4) + for (int byte3 = 0x80; byte3 <= 0xBF; ++byte3) { - check_utf8string(false, byte1, byte2, byte3, byte4); + for (int byte4 = 0x80; byte4 <= 0xBF; ++byte4) + { + check_utf8string(false, byte1, byte2, byte3, byte4); + } } } } } - } - SECTION("ill-formed: wrong fourth byte") - { - for (int byte1 = 0xF1; byte1 <= 0xF3; ++byte1) + SECTION("ill-formed: wrong third byte") { - for (int byte2 = 0x80; byte2 <= 0xBF; ++byte2) + for (int byte1 = 0xF1; byte1 <= 0xF3; ++byte1) { - for (int byte3 = 0x80; byte3 <= 0xBF; ++byte3) + for (int byte2 = 0x80; byte2 <= 0xBF; ++byte2) { - for (int byte4 = 0x00; byte4 <= 0xFF; ++byte4) + for (int byte3 = 0x00; byte3 <= 0xFF; ++byte3) { - // skip correct fourth byte + // skip correct third byte if (0x80 <= byte3 and byte3 <= 0xBF) { continue; } - check_utf8string(false, byte1, byte2, byte3, byte4); + for (int byte4 = 0x80; byte4 <= 0xBF; ++byte4) + { + check_utf8string(false, byte1, byte2, byte3, byte4); + } } } } } - } - } - SECTION("UTF8-4 (xF4 x80-8F UTF8-tail UTF8-tail)") - { - SECTION("well-formed") - { - for (int byte1 = 0xF4; byte1 <= 0xF4; ++byte1) + SECTION("ill-formed: wrong fourth byte") { - for (int byte2 = 0x80; byte2 <= 0x8F; ++byte2) + for (int byte1 = 0xF1; byte1 <= 0xF3; ++byte1) { - for (int byte3 = 0x80; byte3 <= 0xBF; ++byte3) + for (int byte2 = 0x80; byte2 <= 0xBF; ++byte2) { - for (int byte4 = 0x80; byte4 <= 0xBF; ++byte4) + for (int byte3 = 0x80; byte3 <= 0xBF; ++byte3) { - check_utf8string(true, byte1, byte2, byte3, byte4); + for (int byte4 = 0x00; byte4 <= 0xFF; ++byte4) + { + // skip correct fourth byte + if (0x80 <= byte3 and byte3 <= 0xBF) + { + continue; + } + + check_utf8string(false, byte1, byte2, byte3, byte4); + } } } } } } - SECTION("ill-formed: missing second byte") + SECTION("UTF8-4 (xF4 x80-8F UTF8-tail UTF8-tail)") { - for (int byte1 = 0xF4; byte1 <= 0xF4; ++byte1) + SECTION("well-formed") { - check_utf8string(false, byte1); - } - } - - SECTION("ill-formed: missing third byte") - { - for (int byte1 = 0xF4; byte1 <= 0xF4; ++byte1) - { - for (int byte2 = 0x80; byte2 <= 0x8F; ++byte2) + for (int byte1 = 0xF4; byte1 <= 0xF4; ++byte1) { - check_utf8string(false, byte1, byte2); - } - } - } - - SECTION("ill-formed: missing fourth byte") - { - for (int byte1 = 0xF4; byte1 <= 0xF4; ++byte1) - { - for (int byte2 = 0x80; byte2 <= 0x8F; ++byte2) - { - for (int byte3 = 0x80; byte3 <= 0xBF; ++byte3) + for (int byte2 = 0x80; byte2 <= 0x8F; ++byte2) { - check_utf8string(false, byte1, byte2, byte3); - } - } - } - } - - SECTION("ill-formed: wrong second byte") - { - for (int byte1 = 0xF4; byte1 <= 0xF4; ++byte1) - { - for (int byte2 = 0x00; byte2 <= 0xFF; ++byte2) - { - // skip correct second byte - if (0x80 <= byte2 and byte2 <= 0x8F) - { - continue; - } - - for (int byte3 = 0x80; byte3 <= 0xBF; ++byte3) - { - for (int byte4 = 0x80; byte4 <= 0xBF; ++byte4) + for (int byte3 = 0x80; byte3 <= 0xBF; ++byte3) { - check_utf8string(false, byte1, byte2, byte3, byte4); + for (int byte4 = 0x80; byte4 <= 0xBF; ++byte4) + { + check_utf8string(true, byte1, byte2, byte3, byte4); + } } } } } - } - SECTION("ill-formed: wrong third byte") - { - for (int byte1 = 0xF4; byte1 <= 0xF4; ++byte1) + SECTION("ill-formed: missing second byte") { - for (int byte2 = 0x80; byte2 <= 0x8F; ++byte2) + for (int byte1 = 0xF4; byte1 <= 0xF4; ++byte1) { - for (int byte3 = 0x00; byte3 <= 0xFF; ++byte3) + check_utf8string(false, byte1); + } + } + + SECTION("ill-formed: missing third byte") + { + for (int byte1 = 0xF4; byte1 <= 0xF4; ++byte1) + { + for (int byte2 = 0x80; byte2 <= 0x8F; ++byte2) { - // skip correct third byte - if (0x80 <= byte3 and byte3 <= 0xBF) + check_utf8string(false, byte1, byte2); + } + } + } + + SECTION("ill-formed: missing fourth byte") + { + for (int byte1 = 0xF4; byte1 <= 0xF4; ++byte1) + { + for (int byte2 = 0x80; byte2 <= 0x8F; ++byte2) + { + for (int byte3 = 0x80; byte3 <= 0xBF; ++byte3) + { + check_utf8string(false, byte1, byte2, byte3); + } + } + } + } + + SECTION("ill-formed: wrong second byte") + { + for (int byte1 = 0xF4; byte1 <= 0xF4; ++byte1) + { + for (int byte2 = 0x00; byte2 <= 0xFF; ++byte2) + { + // skip correct second byte + if (0x80 <= byte2 and byte2 <= 0x8F) { continue; } - for (int byte4 = 0x80; byte4 <= 0xBF; ++byte4) + for (int byte3 = 0x80; byte3 <= 0xBF; ++byte3) { - check_utf8string(false, byte1, byte2, byte3, byte4); + for (int byte4 = 0x80; byte4 <= 0xBF; ++byte4) + { + check_utf8string(false, byte1, byte2, byte3, byte4); + } } } } } - } - SECTION("ill-formed: wrong fourth byte") - { - for (int byte1 = 0xF4; byte1 <= 0xF4; ++byte1) + SECTION("ill-formed: wrong third byte") { - for (int byte2 = 0x80; byte2 <= 0x8F; ++byte2) + for (int byte1 = 0xF4; byte1 <= 0xF4; ++byte1) { - for (int byte3 = 0x80; byte3 <= 0xBF; ++byte3) + for (int byte2 = 0x80; byte2 <= 0x8F; ++byte2) { - for (int byte4 = 0x00; byte4 <= 0xFF; ++byte4) + for (int byte3 = 0x00; byte3 <= 0xFF; ++byte3) { - // skip correct fourth byte + // skip correct third byte if (0x80 <= byte3 and byte3 <= 0xBF) { continue; } - check_utf8string(false, byte1, byte2, byte3, byte4); + for (int byte4 = 0x80; byte4 <= 0xBF; ++byte4) + { + check_utf8string(false, byte1, byte2, byte3, byte4); + } + } + } + } + } + + SECTION("ill-formed: wrong fourth byte") + { + for (int byte1 = 0xF4; byte1 <= 0xF4; ++byte1) + { + for (int byte2 = 0x80; byte2 <= 0x8F; ++byte2) + { + for (int byte3 = 0x80; byte3 <= 0xBF; ++byte3) + { + for (int byte4 = 0x00; byte4 <= 0xFF; ++byte4) + { + // skip correct fourth byte + if (0x80 <= byte3 and byte3 <= 0xBF) + { + continue; + } + + check_utf8string(false, byte1, byte2, byte3, byte4); + } } } } } } } -} -TEST_CASE("Unicode", "[hide]") -{ - /* NOTE: to_unicode is not used any more - SECTION("full enumeration of Unicode code points") + SECTION("\\uxxxx sequences") { - // lexer to call to_unicode on - json::lexer dummy_lexer("", 0); - // create an escaped string from a code point const auto codepoint_to_unicode = [](std::size_t cp) { - // copd points are represented as a six-character sequence: a + // code points are represented as a six-character sequence: a // reverse solidus, followed by the lowercase letter u, followed // by four hexadecimal digits that encode the character's code // point @@ -872,72 +868,101 @@ TEST_CASE("Unicode", "[hide]") return ss.str(); }; - // generate all UTF-8 code points; in total, 1112064 code points are - // generated: 0x1FFFFF code points - 2048 invalid values between - // 0xD800 and 0xDFFF. - for (std::size_t cp = 0; cp <= 0x10FFFFu; ++cp) + SECTION("correct sequences") { - // The Unicode standard permanently reserves these code point - // values for UTF-16 encoding of the high and low surrogates, and - // they will never be assigned a character, so there should be no - // reason to encode them. The official Unicode standard says that - // no UTF forms, including UTF-16, can encode these code points. - if (cp >= 0xD800u and cp <= 0xDFFFu) + // generate all UTF-8 code points; in total, 1112064 code points are + // generated: 0x1FFFFF code points - 2048 invalid values between + // 0xD800 and 0xDFFF. + for (std::size_t cp = 0; cp <= 0x10FFFFu; ++cp) { - // if we would not skip these code points, we would get a - // "missing low surrogate" exception - continue; - } + // string to store the code point as in \uxxxx format + std::string json_text = "\""; - // string to store the code point as in \uxxxx format - std::string escaped_string; - // string to store the code point as unescaped character sequence - std::string unescaped_string; - - if (cp < 0x10000u) - { - // code points in the Basic Multilingual Plane can be - // represented with one \\uxxxx sequence - escaped_string = codepoint_to_unicode(cp); - - // All Unicode characters may be placed within the quotation - // marks, except for the characters that must be escaped: - // quotation mark, reverse solidus, and the control characters - // (U+0000 through U+001F); we ignore these code points as - // they are checked with codepoint_to_unicode. - if (cp > 0x1f and cp != 0x22 and cp != 0x5c) + // decide whether to use one or two \uxxxx sequences + if (cp < 0x10000u) { - unescaped_string = dummy_lexer.to_unicode(cp); + // The Unicode standard permanently reserves these code point + // values for UTF-16 encoding of the high and low surrogates, and + // they will never be assigned a character, so there should be no + // reason to encode them. The official Unicode standard says that + // no UTF forms, including UTF-16, can encode these code points. + if (cp >= 0xD800u and cp <= 0xDFFFu) + { + // if we would not skip these code points, we would get a + // "missing low surrogate" exception + continue; + } + + // code points in the Basic Multilingual Plane can be + // represented with one \uxxxx sequence + json_text += codepoint_to_unicode(cp); + } + else + { + // To escape an extended character that is not in the Basic + // Multilingual Plane, the character is represented as a + // 12-character sequence, encoding the UTF-16 surrogate pair + const auto codepoint1 = 0xd800u + (((cp - 0x10000u) >> 10) & 0x3ffu); + const auto codepoint2 = 0xdc00u + ((cp - 0x10000u) & 0x3ffu); + json_text += codepoint_to_unicode(codepoint1) + codepoint_to_unicode(codepoint2); + } + + json_text += "\""; + CAPTURE(json_text); + CHECK_NOTHROW(json::parse(json_text)); + } + } + + SECTION("incorrect sequences") + { + SECTION("high surrogate without low surrogate") + { + // D800..DBFF are high surrogates and must be followed by low + // surrogates DC00..DFFF; here, nothing follows + for (std::size_t cp = 0xD800u; cp <= 0xDBFFu; ++cp) + { + std::string json_text = "\"" + codepoint_to_unicode(cp) + "\""; + CAPTURE(json_text); + CHECK_THROWS_AS(json::parse(json_text), json::parse_error); } } - else + +#if 0 + SECTION("high surrogate with wrong low surrogate") { - // To escape an extended character that is not in the Basic - // Multilingual Plane, the character is represented as a - // 12-character sequence, encoding the UTF-16 surrogate pair - const auto codepoint1 = 0xd800u + (((cp - 0x10000u) >> 10) & 0x3ffu); - const auto codepoint2 = 0xdc00u + ((cp - 0x10000u) & 0x3ffu); - escaped_string = codepoint_to_unicode(codepoint1); - escaped_string += codepoint_to_unicode(codepoint2); - unescaped_string += dummy_lexer.to_unicode(codepoint1, codepoint2); + // D800..DBFF are high surrogates and must be followed by low + // surrogates DC00..DFFF; here a different sequence follows + for (std::size_t cp1 = 0xD800u; cp1 <= 0xDBFFu; ++cp1) + { + for (std::size_t cp2 = 0x0000u; cp2 <= 0xFFFFu; ++cp2) + { + if (0xDC00u <= cp2 and cp2 <= 0xDFFFu) + { + continue; + } + + std::string json_text = "\"" + codepoint_to_unicode(cp1) + codepoint_to_unicode(cp2) + "\""; + CAPTURE(json_text); + CHECK_THROWS_AS(json::parse(json_text), json::parse_error); + } + } + } +#endif + + SECTION("low surrogate without high surrogate") + { + // low surrogates DC00..DFFF must follow high surrogates; here, + // they occur alone + for (std::size_t cp = 0xDC00u; cp <= 0xDFFFu; ++cp) + { + std::string json_text = "\"" + codepoint_to_unicode(cp) + "\""; + CAPTURE(json_text); + CHECK_THROWS_AS(json::parse(json_text), json::parse_error); + } } - // all other code points are valid and must not yield parse errors - CAPTURE(cp); - CAPTURE(escaped_string); - CAPTURE(unescaped_string); - - json j1, j2, j3, j4; - CHECK_NOTHROW(j1 = json::parse("\"" + escaped_string + "\"")); - CHECK_NOTHROW(j2 = json::parse(j1.dump())); - CHECK(j1 == j2); - - CHECK_NOTHROW(j3 = json::parse("\"" + unescaped_string + "\"")); - CHECK_NOTHROW(j4 = json::parse(j3.dump())); - CHECK(j3 == j4); } } - */ SECTION("read all unicode characters") {