### NPF-01 The service ignores the presence of a byte order mark. **Supported Requests:** - [PJD-01](PJD.md#pjd-01) **Supporting Items:** - [NPF-01.1](NPF.md#npf-01.1) - [NPF-01.2](NPF.md#npf-01.2) - [NPF-01.3](NPF.md#npf-01.3) - [NPF-01.4](NPF.md#npf-01.4) - [NPF-01.5](NPF.md#npf-01.5) **References:** _None_ **Fallacies:** _None_ **Graph:** _No Historic Data Found_ --- ### NPF-01.1 The service ignores the presence of a single UTF-8 byte order mark at the very beginning of the input. **Supported Requests:** - [NPF-01](NPF.md#npf-01) **Supporting Items:** _None_ **References:** - `cpp-test: [Unicode (1/5);ignore byte-order-mark] (tests/src/unit-unicode1.cpp)` ```cpp SECTION("ignore byte-order-mark") { SECTION("in a stream") { // read a file with a UTF-8 BOM std::ifstream f(TEST_DATA_DIRECTORY "/json_nlohmann_tests/bom.json"); json j; CHECK_NOTHROW(f >> j); } SECTION("with an iterator") { std::string i = "\xef\xbb\xbf{\n \"foo\": true\n}"; json _; CHECK_NOTHROW(_ = json::parse(i.begin(), i.end())); } } ``` - `cpp-test: [deserialization;ignoring byte-order marks;BOM and content] (tests/src/unit-deserialization.cpp)` ```cpp SECTION("BOM and content") { CHECK(json::parse(bom + "1") == 1); CHECK(json::parse(std::istringstream(bom + "1")) == 1); SaxEventLogger l1; SaxEventLogger l2; CHECK(json::sax_parse(std::istringstream(bom + "1"), &l1)); CHECK(json::sax_parse(bom + "1", &l2)); CHECK(l1.events.size() == 1); CHECK(l1.events == std::vector<std::string>( { "number_unsigned(1)" })); CHECK(l2.events.size() == 1); CHECK(l2.events == std::vector<std::string>( { "number_unsigned(1)" })); } ``` **Fallacies:** _None_ **Graph:** _No Historic Data Found_ --- ### NPF-01.2 The service does not parse multiple UTF-8 byte order marks at the beginning of the input and throws an exception. **Supported Requests:** - [NPF-01](NPF.md#npf-01) - [TIJ-06](TIJ.md#tij-06) **Supporting Items:** _None_ **References:** - `cpp-test: [parse;UTF-8;multiple BOM] (TSF/tests/unit-byte_order_mark.cpp)` ```cpp SECTION("multiple BOM") { // Whenever a fourth character of a BOM-candidate is read, an error is thrown. // This error does not depend on any trailing garbage. CHECK_THROWS_WITH_AS(parser_helper("\xEF\xBB\xBF\xEF\xBB\xBF"),"[json.exception.parse_error.101] parse error at line 1, column 4: syntax error while parsing value - invalid literal; last read: '\xEF\xBB\xBF\xEF'", json::parse_error&); CHECK_THROWS_WITH_AS(parser_helper("\xEF\xBB\xBF\xEF\xBB\xBF\xEF\xBB\xBF"),"[json.exception.parse_error.101] parse error at line 1, column 4: syntax error while parsing value - invalid literal; last read: '\xEF\xBB\xBF\xEF'", json::parse_error&); CHECK_THROWS_WITH_AS(parser_helper("\xEF\xBB\xBF\xEF\xBB\xBF\xEF\xBB\xBF\xEF\xBB\xBF"),"[json.exception.parse_error.101] parse error at line 1, column 4: syntax error while parsing value - invalid literal; last read: '\xEF\xBB\xBF\xEF'", json::parse_error&); CHECK_THROWS_WITH_AS(parser_helper("\xEF\xBB\xBF\xEF\xBB"),"[json.exception.parse_error.101] parse error at line 1, column 4: syntax error while parsing value - invalid literal; last read: '\xEF\xBB\xBF\xEF'", json::parse_error&); CHECK_THROWS_WITH_AS(parser_helper("\xEF\xBB\xBF\xEF foo"),"[json.exception.parse_error.101] parse error at line 1, column 4: syntax error while parsing value - invalid literal; last read: '\xEF\xBB\xBF\xEF'", json::parse_error&); } ``` **Fallacies:** _None_ **Graph:** _No Historic Data Found_ --- ### NPF-01.3 The service does not parse UTF-8 byte order marks outside of a string and the first three characters of the input, and throws an exception. **Supported Requests:** - [NPF-01](NPF.md#npf-01) - [TIJ-06](TIJ.md#tij-06) **Supporting Items:** _None_ **References:** - `cpp-test: [parse;UTF-8;unexpected BOM] (TSF/tests/unit-byte_order_mark.cpp)` ```cpp SECTION("unexpected BOM") { // A byte order mark at any other position than the very first character is illegal and an error is thrown. CHECK_THROWS_AS(parser_helper(" \xEF\xBB\xBF"), json::parse_error&); CHECK_THROWS_AS(parser_helper("\t\xEF\xBB\xBF"), json::parse_error&); CHECK_THROWS_AS(parser_helper("\n\xEF\xBB\xBF"), json::parse_error&); CHECK_THROWS_AS(parser_helper("\xEF\xBB\xBF"), json::parse_error&); CHECK_THROWS_AS(parser_helper("\u000d\xEF\xBB\xBF"), json::parse_error&); CHECK_THROWS_AS(parser_helper("1\xEF\xBB\xBF"), json::parse_error&); CHECK_THROWS_AS(parser_helper("\"foo\"\xEF\xBB\xBF"), json::parse_error&); CHECK_THROWS_AS(parser_helper("[42]\xEF\xBB\xBF"), json::parse_error&); CHECK_THROWS_AS(parser_helper("{\"foo\":\"bar\"}\xEF\xBB\xBF"), json::parse_error&); } ``` **Fallacies:** _None_ **Graph:** _No Historic Data Found_ --- ### NPF-01.4 The service does not parse UTF-16 and UTF-32 byte order mark instead of an UTF-8 byte order mark, and throws an exception. **Supported Requests:** - [NPF-01](NPF.md#npf-01) - [TIJ-06](TIJ.md#tij-06) **Supporting Items:** _None_ **References:** - `cpp-test: [parse;other BOM] (TSF/tests/unit-byte_order_mark.cpp)` ```cpp SECTION("other BOM") { SECTION("UTF-16") { CHECK_THROWS_AS(parser_helper("\xFE\xFF\"foo\""),json::parse_error&); CHECK_THROWS_AS(parser_helper("\xFF\xFE\"foo\""),json::parse_error&); } SECTION("UTF-32") { const std::string utf32bom1("\x00\x00\xFE\xFF\x30", 5); const std::string utf32bom2("\xFF\xFE\x00\x00\x30", 5); CHECK_THROWS_AS(parser_helper(utf32bom1),json::parse_error&); CHECK_THROWS_AS(parser_helper(utf32bom2),json::parse_error&); } } ``` **Fallacies:** _None_ **Graph:** _No Historic Data Found_ --- ### NPF-01.5 The service does not parse partial and perturbed UTF-8 byte order marks within the first three characters of the input and throws an exception. **Supported Requests:** - [NPF-01](NPF.md#npf-01) - [TIJ-06](TIJ.md#tij-06) **Supporting Items:** _None_ **References:** - `cpp-test: [deserialization;ignoring byte-order marks;2 byte of BOM] (tests/src/unit-deserialization.cpp)` ```cpp SECTION("2 byte of BOM") { json _; CHECK_THROWS_WITH_AS(_ = json::parse(bom.substr(0, 2)), "[json.exception.parse_error.101] parse error at line 1, column 3: syntax error while parsing value - invalid BOM; must be 0xEF 0xBB 0xBF if given; last read: '\xEF\xBB'", json::parse_error&); CHECK_THROWS_WITH_AS(_ = json::parse(std::istringstream(bom.substr(0, 2))), "[json.exception.parse_error.101] parse error at line 1, column 3: syntax error while parsing value - invalid BOM; must be 0xEF 0xBB 0xBF if given; last read: '\xEF\xBB'", json::parse_error&); SaxEventLogger l1; SaxEventLogger l2; CHECK(!json::sax_parse(std::istringstream(bom.substr(0, 2)), &l1)); CHECK(!json::sax_parse(bom.substr(0, 2), &l2)); CHECK(l1.events.size() == 1); CHECK(l1.events == std::vector<std::string>( { "parse_error(3)" })); CHECK(l2.events.size() == 1); CHECK(l2.events == std::vector<std::string>( { "parse_error(3)" })); } ``` - `cpp-test: [deserialization;ignoring byte-order marks;1 byte of BOM] (tests/src/unit-deserialization.cpp)` ```cpp SECTION("1 byte of BOM") { json _; CHECK_THROWS_WITH_AS(_ = json::parse(bom.substr(0, 1)), "[json.exception.parse_error.101] parse error at line 1, column 2: syntax error while parsing value - invalid BOM; must be 0xEF 0xBB 0xBF if given; last read: '\xEF'", json::parse_error&); CHECK_THROWS_WITH_AS(_ = json::parse(std::istringstream(bom.substr(0, 1))), "[json.exception.parse_error.101] parse error at line 1, column 2: syntax error while parsing value - invalid BOM; must be 0xEF 0xBB 0xBF if given; last read: '\xEF'", json::parse_error&); SaxEventLogger l1; SaxEventLogger l2; CHECK(!json::sax_parse(std::istringstream(bom.substr(0, 1)), &l1)); CHECK(!json::sax_parse(bom.substr(0, 1), &l2)); CHECK(l1.events.size() == 1); CHECK(l1.events == std::vector<std::string>( { "parse_error(2)" })); CHECK(l2.events.size() == 1); CHECK(l2.events == std::vector<std::string>( { "parse_error(2)" })); } ``` - `cpp-test: [deserialization;ignoring byte-order marks;variations] (tests/src/unit-deserialization.cpp)` ```cpp SECTION("variations") { // calculate variations of each byte of the BOM to make sure // that the BOM and only the BOM is skipped for (int i0 = -1; i0 < 2; ++i0) { for (int i1 = -1; i1 < 2; ++i1) { for (int i2 = -1; i2 < 2; ++i2) { // debug output for the variations CAPTURE(i0) CAPTURE(i1) CAPTURE(i2) std::string s; s.push_back(static_cast<char>(bom[0] + i0)); s.push_back(static_cast<char>(bom[1] + i1)); s.push_back(static_cast<char>(bom[2] + i2)); if (i0 == 0 && i1 == 0 && i2 == 0) { // without any variation, we skip the BOM CHECK(json::parse(s + "null") == json()); CHECK(json::parse(std::istringstream(s + "null")) == json()); SaxEventLogger l; CHECK(json::sax_parse(s + "null", &l)); CHECK(l.events.size() == 1); CHECK(l.events == std::vector<std::string>( { "null()" })); } else { // any variation is an error json _; CHECK_THROWS_AS(_ = json::parse(s + "null"), json::parse_error&); CHECK_THROWS_AS(_ = json::parse(std::istringstream(s + "null")), json::parse_error&); SaxEventLogger l; CHECK(!json::sax_parse(s + "null", &l)); CHECK(l.events.size() == 1); if (i0 != 0) { CHECK(l.events == std::vector<std::string>( { "parse_error(1)" })); } else if (i1 != 0) { CHECK(l.events == std::vector<std::string>( { "parse_error(2)" })); } else { CHECK(l.events == std::vector<std::string>( { "parse_error(3)" })); } } } } } } ``` - `cpp-test: [Unicode (1/5);error for incomplete/wrong BOM] (tests/src/unit-unicode1.cpp)` ```cpp SECTION("error for incomplete/wrong BOM") { json _; CHECK_THROWS_AS(_ = json::parse("\xef\xbb"), json::parse_error&); CHECK_THROWS_AS(_ = json::parse("\xef\xbb\xbb"), json::parse_error&); } ``` **Fallacies:** _None_ **Graph:** _No Historic Data Found_ --- ### NPF-02 The service parses numbers according to RFC8259. **Supported Requests:** - [PJD-03](PJD.md#pjd-03) **Supporting Items:** - [NPF-02.1](NPF.md#npf-02.1) - [NPF-02.2](NPF.md#npf-02.2) - [NPF-02.3](NPF.md#npf-02.3) - [NPF-02.4](NPF.md#npf-02.4) - [NPF-02.5](NPF.md#npf-02.5) - [NPF-02.6](NPF.md#npf-02.6) - [NPF-02.7](NPF.md#npf-02.7) - [NPF-02.8](NPF.md#npf-02.8) - [AOU-22](AOU.md#aou-22) - [NPF-02.9](NPF.md#npf-02.9) - [NPF-02.10](NPF.md#npf-02.10) - [NPF-02.11](NPF.md#npf-02.11) - [NPF-02.12](NPF.md#npf-02.12) **References:** - `function: [lexer::scan_number] (include/nlohmann/detail/input/lexer.hpp)` - Description: function, which parses numbers into C++ number-types and verifies *en passant* that these numbers are in accordance with RFC8259 ```cpp token_type scan_number() // lgtm [cpp/use-of-goto] `goto` is used in this function to implement the number-parsing state machine described above. By design, any finite input will eventually reach the "done" state or return token_type::parse_error. In each intermediate state, 1 byte of the input is appended to the token_buffer vector, and only the already initialized variables token_buffer, number_type, and error_message are manipulated. { // reset token_buffer to store the number's bytes reset(); // the type of the parsed number; initially set to unsigned; will be // changed if minus sign, decimal point or exponent is read token_type number_type = token_type::value_unsigned; // state (init): we just found out we need to scan a number switch (current) { case '-': { add(current); goto scan_number_minus; } case '0': { add(current); goto scan_number_zero; } case '1': case '2': case '3': case '4': case '5': case '6': case '7': case '8': case '9': { add(current); goto scan_number_any1; } // all other characters are rejected outside scan_number() default: // LCOV_EXCL_LINE JSON_ASSERT(false); // NOLINT(cert-dcl03-c,hicpp-static-assert,misc-static-assert) LCOV_EXCL_LINE } scan_number_minus: // state: we just parsed a leading minus sign number_type = token_type::value_integer; switch (get()) { case '0': { add(current); goto scan_number_zero; } case '1': case '2': case '3': case '4': case '5': case '6': case '7': case '8': case '9': { add(current); goto scan_number_any1; } default: { error_message = "invalid number; expected digit after '-'"; return token_type::parse_error; } } scan_number_zero: // state: we just parse a zero (maybe with a leading minus sign) switch (get()) { case '.': { add(decimal_point_char); decimal_point_position = token_buffer.size() - 1; goto scan_number_decimal1; } case 'e': case 'E': { add(current); goto scan_number_exponent; } default: goto scan_number_done; } scan_number_any1: // state: we just parsed a number 0-9 (maybe with a leading minus sign) switch (get()) { case '0': case '1': case '2': case '3': case '4': case '5': case '6': case '7': case '8': case '9': { add(current); goto scan_number_any1; } case '.': { add(decimal_point_char); decimal_point_position = token_buffer.size() - 1; goto scan_number_decimal1; } case 'e': case 'E': { add(current); goto scan_number_exponent; } default: goto scan_number_done; } scan_number_decimal1: // state: we just parsed a decimal point number_type = token_type::value_float; switch (get()) { case '0': case '1': case '2': case '3': case '4': case '5': case '6': case '7': case '8': case '9': { add(current); goto scan_number_decimal2; } default: { error_message = "invalid number; expected digit after '.'"; return token_type::parse_error; } } scan_number_decimal2: // we just parsed at least one number after a decimal point switch (get()) { case '0': case '1': case '2': case '3': case '4': case '5': case '6': case '7': case '8': case '9': { add(current); goto scan_number_decimal2; } case 'e': case 'E': { add(current); goto scan_number_exponent; } default: goto scan_number_done; } scan_number_exponent: // we just parsed an exponent number_type = token_type::value_float; switch (get()) { case '+': case '-': { add(current); goto scan_number_sign; } case '0': case '1': case '2': case '3': case '4': case '5': case '6': case '7': case '8': case '9': { add(current); goto scan_number_any2; } default: { error_message = "invalid number; expected '+', '-', or digit after exponent"; return token_type::parse_error; } } scan_number_sign: // we just parsed an exponent sign switch (get()) { case '0': case '1': case '2': case '3': case '4': case '5': case '6': case '7': case '8': case '9': { add(current); goto scan_number_any2; } default: { error_message = "invalid number; expected digit after exponent sign"; return token_type::parse_error; } } scan_number_any2: // we just parsed a number after the exponent or exponent sign switch (get()) { case '0': case '1': case '2': case '3': case '4': case '5': case '6': case '7': case '8': case '9': { add(current); goto scan_number_any2; } default: goto scan_number_done; } scan_number_done: // unget the character after the number (we only read it to know that // we are done scanning a number) unget(); char* endptr = nullptr; // NOLINT(misc-const-correctness,cppcoreguidelines-pro-type-vararg,hicpp-vararg) errno = 0; // try to parse integers first and fall back to floats if (number_type == token_type::value_unsigned) { const auto x = std::strtoull(token_buffer.data(), &endptr, 10); // we checked the number format before JSON_ASSERT(endptr == token_buffer.data() + token_buffer.size()); if (errno != ERANGE) { value_unsigned = static_cast<number_unsigned_t>(x); if (value_unsigned == x) { return token_type::value_unsigned; } } } else if (number_type == token_type::value_integer) { const auto x = std::strtoll(token_buffer.data(), &endptr, 10); // we checked the number format before JSON_ASSERT(endptr == token_buffer.data() + token_buffer.size()); if (errno != ERANGE) { value_integer = static_cast<number_integer_t>(x); if (value_integer == x) { return token_type::value_integer; } } } // this code is reached if we parse a floating-point number or if an // integer conversion above failed strtof(value_float, token_buffer.data(), &endptr); // we checked the number format before JSON_ASSERT(endptr == token_buffer.data() + token_buffer.size()); return token_type::value_float; } ``` **Fallacies:** _None_ **Graph:** _No Historic Data Found_ --- ### NPF-02.1 The service parses integers without exponent within the precision of int64_t. **Supported Requests:** - [NPF-02](NPF.md#npf-02) **Supporting Items:** _None_ **References:** - `cpp-test: [parser class - core;parse;number;floating-point;without exponent] (TSF/tests/unit-class_parser_core.cpp)` ```cpp SECTION("without exponent") { CHECK(parser_helper("-128.5") == json(-128.5)); CHECK(parser_helper("0.999") == json(0.999)); CHECK(parser_helper("128.5") == json(128.5)); CHECK(parser_helper("-0.0") == json(-0.0)); } ``` - `cpp-test: [parser class - core;parse;number;integers;without exponent] (TSF/tests/unit-class_parser_core.cpp)` ```cpp SECTION("without exponent") { CHECK(parser_helper("-128") == json(-128)); CHECK(parser_helper("-0") == json(-0)); CHECK(parser_helper("0") == json(0)); CHECK(parser_helper("128") == json(128)); } ``` - `cpp-testsuite: [/nst_json_testsuite2/test_parsing/y_number_simple_int.json, /nst_json_testsuite2/test_parsing/y_number_simple_real.json, /nst_json_testsuite2/test_parsing/y_number_negative_int.json, /nst_json_testsuite2/test_parsing/y_number_negative_one.json, /nst_json_testsuite2/test_parsing/y_number_negative_zero.json]` - Description: Tests whether several numbers without exponent are parsed without throwing an exception. - JSON Testsuite: /nst_json_testsuite2/test_parsing/y_number_simple_int.json ```json [123] ``` - JSON Testsuite: /nst_json_testsuite2/test_parsing/y_number_simple_real.json ```json [123.456789] ``` - JSON Testsuite: /nst_json_testsuite2/test_parsing/y_number_negative_int.json ```json [-123] ``` - JSON Testsuite: /nst_json_testsuite2/test_parsing/y_number_negative_one.json ```json [-1] ``` - JSON Testsuite: /nst_json_testsuite2/test_parsing/y_number_negative_zero.json ```json [-0] ``` - cpp-test: [nst's JSONTestSuite (2);test_parsing;y] (tests/src/unit-testsuites.cpp) ```cpp SECTION("y") { for (const auto* filename : { TEST_DATA_DIRECTORY "/nst_json_testsuite2/test_parsing/y_number_negative_int.json", TEST_DATA_DIRECTORY "/nst_json_testsuite2/test_parsing/y_number_negative_one.json", TEST_DATA_DIRECTORY "/nst_json_testsuite2/test_parsing/y_number_negative_zero.json", TEST_DATA_DIRECTORY "/nst_json_testsuite2/test_parsing/y_number_simple_int.json", TEST_DATA_DIRECTORY "/nst_json_testsuite2/test_parsing/y_number_simple_real.json", } ) { CAPTURE(filename) std::ifstream f(filename); json _; CHECK_NOTHROW(_ = json::parse(f)); std::ifstream f2(filename); CHECK(json::accept(f2)); } } // Note: Other test data lines have been filtered out for conciseness. ``` **Fallacies:** _None_ **Graph:** _No Historic Data Found_ --- ### NPF-02.10 The service ignores trailing zeroes after the decimal point. **Supported Requests:** - [NPF-02](NPF.md#npf-02) **Supporting Items:** _None_ **References:** - `cpp-test: [regression tests 1;issue #379 - locale-independent str-to-num] (tests/src/unit-regression1.cpp)` ```cpp SECTION("issue #379 - locale-independent str-to-num") { static_cast<void>(setlocale(LC_NUMERIC, "de_DE.UTF-8")); // verify that parsed correctly despite using strtod internally CHECK(json::parse("3.14").get<double>() == 3.14); // check a different code path CHECK(json::parse("1.000000000000000000000000000000000000000000000000000000000000000000000000").get<double>() == 1.0); } ``` - `cpp-test: [parse;trailing zeroes] (TSF/tests/unit-numbers.cpp)` ```cpp SECTION("trailing zeroes") { // Trailing zeroes after the decimal point do not influence the parsing CHECK(json::parse("3.1415000000000000000000000")==json::parse("3.1415")); CHECK(json::parse("3.1415000000000\u004515")==json::parse("3.1415\u004515")); CHECK(json::parse("3.1415926000000000\u006515")==json::parse("3.1415926\u006515")); // This also works for numbers that are not parsed correctly anyway CHECK(json::parse("2.2250738585072011360574097967091319759348195463516456400000000e-308")==json::parse("2.22507385850720113605740979670913197593481954635164564e-308")); CHECK(json::parse("0.999999999999999944488848768742172978818416595458984374")==json::parse("0.999999999999999944488848768742172978818416595458984374000000")); } ``` **Fallacies:** _None_ **Graph:** _No Historic Data Found_ --- ### NPF-02.11 The service parses numbers within the 64-bit double range but outside of the double precision without throwing an exception. **Supported Requests:** - [NPF-02](NPF.md#npf-02) **Supporting Items:** _None_ **References:** - `cpp-test: [regression tests 1;issue #186 miloyip/nativejson-benchmark: floating-point parsing] (tests/src/unit-regression1.cpp)` ```cpp SECTION("issue #186 miloyip/nativejson-benchmark: floating-point parsing") { json j; j = json::parse("-0.0"); CHECK(j.get<double>() == -0.0); j = json::parse("2.22507385850720113605740979670913197593481954635164564e-308"); CHECK(j.get<double>() == 2.2250738585072009e-308); j = json::parse("0.999999999999999944488848768742172978818416595458984374"); CHECK(j.get<double>() == 0.99999999999999989); j = json::parse("1.00000000000000011102230246251565404236316680908203126"); CHECK(j.get<double>() == 1.00000000000000022); j = json::parse("7205759403792793199999e-5"); CHECK(j.get<double>() == 72057594037927928.0); j = json::parse("922337203685477529599999e-5"); CHECK(j.get<double>() == 9223372036854774784.0); j = json::parse("1014120480182583464902367222169599999e-5"); CHECK(j.get<double>() == 10141204801825834086073718800384.0); j = json::parse("5708990770823839207320493820740630171355185151999e-3"); CHECK(j.get<double>() == 5708990770823838890407843763683279797179383808.0); // create JSON class with nonstandard float number type // float nlohmann::basic_json<std::map, std::vector, std::string, bool, int32_t, uint32_t, float> const j_float = 1.23e25f; CHECK(j_float.get<float>() == 1.23e25f); // double nlohmann::basic_json<std::map, std::vector, std::string, bool, int64_t, uint64_t, double> const j_double = 1.23e35; CHECK(j_double.get<double>() == 1.23e35); // long double nlohmann::basic_json<std::map, std::vector, std::string, bool, int64_t, uint64_t, long double> const j_long_double = 1.23e45L; CHECK(j_long_double.get<long double>() == 1.23e45L); } ``` **Fallacies:** _None_ **Graph:** _No Historic Data Found_ --- ### NPF-02.12 The service ignores capitalisation of the exponent. **Supported Requests:** - [NPF-02](NPF.md#npf-02) **Supporting Items:** _None_ **References:** - `cpp-test: [parse;exponents;Capitalisation] (TSF/tests/unit-numbers.cpp)` ```cpp SECTION("Capitalisation") { CHECK(json::parse("3.1415\u00454")==json::parse("3.1415\u00654")); } ``` **Fallacies:** _None_ **Graph:** _No Historic Data Found_ --- ### NPF-02.2 The service parses integers with exponent within the precision of 64-bit double. **Supported Requests:** - [NPF-02](NPF.md#npf-02) **Supporting Items:** _None_ **References:** - `cpp-test: [parser class - core;parse;number;floating-point;with exponent] (TSF/tests/unit-class_parser_core.cpp)` ```cpp SECTION("with exponent") { CHECK(parser_helper("-128.5E3") == json(-128.5E3)); CHECK(parser_helper("-128.5E-3") == json(-128.5E-3)); CHECK(parser_helper("-0.0e1") == json(-0.0e1)); CHECK(parser_helper("-0.0E1") == json(-0.0e1)); } ``` - `cpp-test: [parser class - core;parse;number;integers;with exponent] (TSF/tests/unit-class_parser_core.cpp)` ```cpp SECTION("with exponent") { CHECK(parser_helper("0e1") == json(0e1)); CHECK(parser_helper("0E1") == json(0e1)); CHECK(parser_helper("10000E-4") == json(10000e-4)); CHECK(parser_helper("10000E-3") == json(10000e-3)); CHECK(parser_helper("10000E-2") == json(10000e-2)); CHECK(parser_helper("10000E-1") == json(10000e-1)); CHECK(parser_helper("10000E0") == json(10000e0)); CHECK(parser_helper("10000E1") == json(10000e1)); CHECK(parser_helper("10000E2") == json(10000e2)); CHECK(parser_helper("10000E3") == json(10000e3)); CHECK(parser_helper("10000E4") == json(10000e4)); CHECK(parser_helper("10000e-4") == json(10000e-4)); CHECK(parser_helper("10000e-3") == json(10000e-3)); CHECK(parser_helper("10000e-2") == json(10000e-2)); CHECK(parser_helper("10000e-1") == json(10000e-1)); CHECK(parser_helper("10000e0") == json(10000e0)); CHECK(parser_helper("10000e1") == json(10000e1)); CHECK(parser_helper("10000e2") == json(10000e2)); CHECK(parser_helper("10000e3") == json(10000e3)); CHECK(parser_helper("10000e4") == json(10000e4)); CHECK(parser_helper("-0e1") == json(-0e1)); CHECK(parser_helper("-0E1") == json(-0e1)); CHECK(parser_helper("-0E123") == json(-0e123)); // numbers after exponent CHECK(parser_helper("10E0") == json(10e0)); CHECK(parser_helper("10E1") == json(10e1)); CHECK(parser_helper("10E2") == json(10e2)); CHECK(parser_helper("10E3") == json(10e3)); CHECK(parser_helper("10E4") == json(10e4)); CHECK(parser_helper("10E5") == json(10e5)); CHECK(parser_helper("10E6") == json(10e6)); CHECK(parser_helper("10E7") == json(10e7)); CHECK(parser_helper("10E8") == json(10e8)); CHECK(parser_helper("10E9") == json(10e9)); CHECK(parser_helper("10E+0") == json(10e0)); CHECK(parser_helper("10E+1") == json(10e1)); CHECK(parser_helper("10E+2") == json(10e2)); CHECK(parser_helper("10E+3") == json(10e3)); CHECK(parser_helper("10E+4") == json(10e4)); CHECK(parser_helper("10E+5") == json(10e5)); CHECK(parser_helper("10E+6") == json(10e6)); CHECK(parser_helper("10E+7") == json(10e7)); CHECK(parser_helper("10E+8") == json(10e8)); CHECK(parser_helper("10E+9") == json(10e9)); CHECK(parser_helper("10E-1") == json(10e-1)); CHECK(parser_helper("10E-2") == json(10e-2)); CHECK(parser_helper("10E-3") == json(10e-3)); CHECK(parser_helper("10E-4") == json(10e-4)); CHECK(parser_helper("10E-5") == json(10e-5)); CHECK(parser_helper("10E-6") == json(10e-6)); CHECK(parser_helper("10E-7") == json(10e-7)); CHECK(parser_helper("10E-8") == json(10e-8)); CHECK(parser_helper("10E-9") == json(10e-9)); } ``` - `cpp-testsuite: [/nst_json_testsuite2/test_parsing/y_number_real_capital_e.json, /nst_json_testsuite2/test_parsing/y_number_real_capital_e_neg_exp.json, /nst_json_testsuite2/test_parsing/y_number_real_capital_e_pos_exp.json, /nst_json_testsuite2/test_parsing/y_number_real_exponent.json, /nst_json_testsuite2/test_parsing/y_number_real_fraction_exponent.json, /nst_json_testsuite2/test_parsing/y_number_real_neg_exp.json, /nst_json_testsuite2/test_parsing/y_number_real_pos_exponent.json]` - Description: Tests whether several numbers with exponent are parsed without throwing an exception. - JSON Testsuite: /nst_json_testsuite2/test_parsing/y_number_real_capital_e.json ```json [1E22] ``` - JSON Testsuite: /nst_json_testsuite2/test_parsing/y_number_real_capital_e_neg_exp.json ```json [1E-2] ``` - JSON Testsuite: /nst_json_testsuite2/test_parsing/y_number_real_capital_e_pos_exp.json ```json [1E+2] ``` - JSON Testsuite: /nst_json_testsuite2/test_parsing/y_number_real_exponent.json ```json [123e45] ``` - JSON Testsuite: /nst_json_testsuite2/test_parsing/y_number_real_fraction_exponent.json ```json [123.456e78] ``` - JSON Testsuite: /nst_json_testsuite2/test_parsing/y_number_real_neg_exp.json ```json [1e-2] ``` - JSON Testsuite: /nst_json_testsuite2/test_parsing/y_number_real_pos_exponent.json ```json [1e+2] ``` - cpp-test: [nst's JSONTestSuite (2);test_parsing;y] (tests/src/unit-testsuites.cpp) ```cpp SECTION("y") { for (const auto* filename : { TEST_DATA_DIRECTORY "/nst_json_testsuite2/test_parsing/y_number_real_capital_e.json", TEST_DATA_DIRECTORY "/nst_json_testsuite2/test_parsing/y_number_real_capital_e_neg_exp.json", TEST_DATA_DIRECTORY "/nst_json_testsuite2/test_parsing/y_number_real_capital_e_pos_exp.json", TEST_DATA_DIRECTORY "/nst_json_testsuite2/test_parsing/y_number_real_exponent.json", TEST_DATA_DIRECTORY "/nst_json_testsuite2/test_parsing/y_number_real_fraction_exponent.json", TEST_DATA_DIRECTORY "/nst_json_testsuite2/test_parsing/y_number_real_neg_exp.json", TEST_DATA_DIRECTORY "/nst_json_testsuite2/test_parsing/y_number_real_pos_exponent.json", } ) { CAPTURE(filename) std::ifstream f(filename); json _; CHECK_NOTHROW(_ = json::parse(f)); std::ifstream f2(filename); CHECK(json::accept(f2)); } } // Note: Other test data lines have been filtered out for conciseness. ``` - `cpp-test: [parse;Precision] (TSF/tests/unit-numbers.cpp)` ```cpp SECTION("Precision") { CHECK(json::parse("1.7976931348623158e308").dump()=="1.7976931348623157e+308"); // maximum double value CHECK(json::parse("-1.7976931348623158e308").dump()=="-1.7976931348623157e+308"); // minimum double value } ``` **Fallacies:** _None_ **Graph:** _No Historic Data Found_ --- ### NPF-02.3 The service parses floating point values without exponent within the precision of 64-bit double. **Supported Requests:** - [NPF-02](NPF.md#npf-02) **Supporting Items:** _None_ **References:** - `cpp-test: [parser class - core;parse;number;integers] (TSF/tests/unit-class_parser_core.cpp)` ```cpp SECTION("integers") { SECTION("without exponent") { CHECK(parser_helper("-128") == json(-128)); CHECK(parser_helper("-0") == json(-0)); CHECK(parser_helper("0") == json(0)); CHECK(parser_helper("128") == json(128)); } SECTION("with exponent") { CHECK(parser_helper("0e1") == json(0e1)); CHECK(parser_helper("0E1") == json(0e1)); CHECK(parser_helper("10000E-4") == json(10000e-4)); CHECK(parser_helper("10000E-3") == json(10000e-3)); CHECK(parser_helper("10000E-2") == json(10000e-2)); CHECK(parser_helper("10000E-1") == json(10000e-1)); CHECK(parser_helper("10000E0") == json(10000e0)); CHECK(parser_helper("10000E1") == json(10000e1)); CHECK(parser_helper("10000E2") == json(10000e2)); CHECK(parser_helper("10000E3") == json(10000e3)); CHECK(parser_helper("10000E4") == json(10000e4)); CHECK(parser_helper("10000e-4") == json(10000e-4)); CHECK(parser_helper("10000e-3") == json(10000e-3)); CHECK(parser_helper("10000e-2") == json(10000e-2)); CHECK(parser_helper("10000e-1") == json(10000e-1)); CHECK(parser_helper("10000e0") == json(10000e0)); CHECK(parser_helper("10000e1") == json(10000e1)); CHECK(parser_helper("10000e2") == json(10000e2)); CHECK(parser_helper("10000e3") == json(10000e3)); CHECK(parser_helper("10000e4") == json(10000e4)); CHECK(parser_helper("-0e1") == json(-0e1)); CHECK(parser_helper("-0E1") == json(-0e1)); CHECK(parser_helper("-0E123") == json(-0e123)); // numbers after exponent CHECK(parser_helper("10E0") == json(10e0)); CHECK(parser_helper("10E1") == json(10e1)); CHECK(parser_helper("10E2") == json(10e2)); CHECK(parser_helper("10E3") == json(10e3)); CHECK(parser_helper("10E4") == json(10e4)); CHECK(parser_helper("10E5") == json(10e5)); CHECK(parser_helper("10E6") == json(10e6)); CHECK(parser_helper("10E7") == json(10e7)); CHECK(parser_helper("10E8") == json(10e8)); CHECK(parser_helper("10E9") == json(10e9)); CHECK(parser_helper("10E+0") == json(10e0)); CHECK(parser_helper("10E+1") == json(10e1)); CHECK(parser_helper("10E+2") == json(10e2)); CHECK(parser_helper("10E+3") == json(10e3)); CHECK(parser_helper("10E+4") == json(10e4)); CHECK(parser_helper("10E+5") == json(10e5)); CHECK(parser_helper("10E+6") == json(10e6)); CHECK(parser_helper("10E+7") == json(10e7)); CHECK(parser_helper("10E+8") == json(10e8)); CHECK(parser_helper("10E+9") == json(10e9)); CHECK(parser_helper("10E-1") == json(10e-1)); CHECK(parser_helper("10E-2") == json(10e-2)); CHECK(parser_helper("10E-3") == json(10e-3)); CHECK(parser_helper("10E-4") == json(10e-4)); CHECK(parser_helper("10E-5") == json(10e-5)); CHECK(parser_helper("10E-6") == json(10e-6)); CHECK(parser_helper("10E-7") == json(10e-7)); CHECK(parser_helper("10E-8") == json(10e-8)); CHECK(parser_helper("10E-9") == json(10e-9)); } SECTION("edge cases") { // From RFC8259, Section 6: // Note that when such software is used, numbers that are // integers and are in the range [-(2**53)+1, (2**53)-1] // are interoperable in the sense that implementations will // agree exactly on their numeric values. // -(2**53)+1 CHECK(parser_helper("-9007199254740991").get<int64_t>() == -9007199254740991); // (2**53)-1 CHECK(parser_helper("9007199254740991").get<int64_t>() == 9007199254740991); } SECTION("over the edge cases") // issue #178 - Integer conversion to unsigned (incorrect handling of 64-bit integers) { // While RFC8259, Section 6 specifies a preference for support // for ranges in range of IEEE 754-2008 binary64 (double precision) // this does not accommodate 64-bit integers without loss of accuracy. // As 64-bit integers are now widely used in software, it is desirable // to expand support to the full 64 bit (signed and unsigned) range // i.e. -(2**63) -> (2**64)-1. // -(2**63) ** Note: compilers see negative literals as negated positive numbers (hence the -1)) CHECK(parser_helper("-9223372036854775808").get<int64_t>() == -9223372036854775807 - 1); // (2**63)-1 CHECK(parser_helper("9223372036854775807").get<int64_t>() == 9223372036854775807); // (2**64)-1 CHECK(parser_helper("18446744073709551615").get<uint64_t>() == 18446744073709551615u); } } ``` **Fallacies:** _None_ **Graph:** _No Historic Data Found_ --- ### NPF-02.4 The service parses floating point values with exponent within the precision of 64-bit double. **Supported Requests:** - [NPF-02](NPF.md#npf-02) **Supporting Items:** _None_ **References:** - `cpp-test: [parser class - core;parse;number;floating-point] (TSF/tests/unit-class_parser_core.cpp)` ```cpp SECTION("floating-point") { SECTION("without exponent") { CHECK(parser_helper("-128.5") == json(-128.5)); CHECK(parser_helper("0.999") == json(0.999)); CHECK(parser_helper("128.5") == json(128.5)); CHECK(parser_helper("-0.0") == json(-0.0)); } SECTION("with exponent") { CHECK(parser_helper("-128.5E3") == json(-128.5E3)); CHECK(parser_helper("-128.5E-3") == json(-128.5E-3)); CHECK(parser_helper("-0.0e1") == json(-0.0e1)); CHECK(parser_helper("-0.0E1") == json(-0.0e1)); } } ``` - `cpp-test: [regression tests 1;issue #360 - Loss of precision when serializing <double>] (tests/src/unit-regression1.cpp)` ```cpp SECTION("issue #360 - Loss of precision when serializing <double>") { auto check_roundtrip = [](double number) { CAPTURE(number) json j = number; CHECK(j.is_number_float()); std::stringstream ss; ss << j; CHECK_NOTHROW(ss >> j); CHECK(j.is_number_float()); CHECK(j.get<json::number_float_t>() == number); }; check_roundtrip(100000000000.1236); check_roundtrip((std::numeric_limits<json::number_float_t>::max)()); // Some more numbers which fail to roundtrip when serialized with digits10 significand digits (instead of max_digits10) check_roundtrip(1.541888611948064e-17); check_roundtrip(5.418771028591015e-16); check_roundtrip(9.398685592608595e-15); check_roundtrip(8.826843952762347e-14); check_roundtrip(8.143291313475335e-13); check_roundtrip(4.851328172762508e-12); check_roundtrip(6.677850998084358e-11); check_roundtrip(3.995398518174525e-10); check_roundtrip(1.960452605645124e-9); check_roundtrip(3.551812586302883e-8); check_roundtrip(2.947988411689261e-7); check_roundtrip(8.210166748056192e-6); check_roundtrip(6.104889704266753e-5); check_roundtrip(0.0008629954631330876); check_roundtrip(0.004936993881051611); check_roundtrip(0.08309725102608073); check_roundtrip(0.5210494268499783); check_roundtrip(6.382927930939767); check_roundtrip(59.94947245358671); check_roundtrip(361.0838651266122); check_roundtrip(4678.354596181877); check_roundtrip(61412.17658956043); check_roundtrip(725696.0799057782); check_roundtrip(2811732.583399828); check_roundtrip(30178351.07533605); check_roundtrip(689684880.3235844); check_roundtrip(5714887673.555147); check_roundtrip(84652038821.18808); check_roundtrip(156510583431.7721); check_roundtrip(5938450569021.732); check_roundtrip(83623297654460.33); check_roundtrip(701466573254773.6); check_roundtrip(1369013370304513); check_roundtrip(96963648023094720); // NOLINT(bugprone-narrowing-conversions,cppcoreguidelines-narrowing-conversions) check_roundtrip(3.478237409280108e+17); } ``` **Fallacies:** _None_ **Graph:** _No Historic Data Found_ --- ### NPF-02.5 The service ignores leading zeroes in the exponent. **Supported Requests:** - [NPF-02](NPF.md#npf-02) **Supporting Items:** _None_ **References:** - `cpp-test: [parse;exponents;leading zeroes] (TSF/tests/unit-numbers.cpp)` ```cpp SECTION("leading zeroes") { CHECK(json::parse("1\u00451")==json::parse("1\u004501")); CHECK(json::parse("0.1\u00451")==json::parse("0.1\u004501")); CHECK(json::parse("1\u004545")==json::parse("1\u004500000000000000000000000045")); CHECK(json::parse("12415\u004516")==json::parse("12415\u00450016")); CHECK(json::parse("12.415\u004516")==json::parse("12.415\u00450016")); CHECK(json::parse("1\u00651")==json::parse("1\u006501")); CHECK(json::parse("0.1\u00651")==json::parse("0.1\u006501")); CHECK(json::parse("1\u006545")==json::parse("1\u006500000000000000000000000045")); CHECK(json::parse("12415\u006516")==json::parse("12415\u00650016")); CHECK(json::parse("12.415\u006516")==json::parse("12.415\u00650016")); } ``` **Fallacies:** _None_ **Graph:** _No Historic Data Found_ --- ### NPF-02.6 The service parses integers within IEEE 754-2008 binary64. **Supported Requests:** - [NPF-02](NPF.md#npf-02) **Supporting Items:** _None_ **References:** - `cpp-test: [parser class - core;parse;number;integers;edge cases] (TSF/tests/unit-class_parser_core.cpp)` ```cpp SECTION("edge cases") { // From RFC8259, Section 6: // Note that when such software is used, numbers that are // integers and are in the range [-(2**53)+1, (2**53)-1] // are interoperable in the sense that implementations will // agree exactly on their numeric values. // -(2**53)+1 CHECK(parser_helper("-9007199254740991").get<int64_t>() == -9007199254740991); // (2**53)-1 CHECK(parser_helper("9007199254740991").get<int64_t>() == 9007199254740991); } ``` - `cpp-test: [parser class - core;parse;number;integers;over the edge cases] (TSF/tests/unit-class_parser_core.cpp)` ```cpp SECTION("over the edge cases") // issue #178 - Integer conversion to unsigned (incorrect handling of 64-bit integers) { // While RFC8259, Section 6 specifies a preference for support // for ranges in range of IEEE 754-2008 binary64 (double precision) // this does not accommodate 64-bit integers without loss of accuracy. // As 64-bit integers are now widely used in software, it is desirable // to expand support to the full 64 bit (signed and unsigned) range // i.e. -(2**63) -> (2**64)-1. // -(2**63) ** Note: compilers see negative literals as negated positive numbers (hence the -1)) CHECK(parser_helper("-9223372036854775808").get<int64_t>() == -9223372036854775807 - 1); // (2**63)-1 CHECK(parser_helper("9223372036854775807").get<int64_t>() == 9223372036854775807); // (2**64)-1 CHECK(parser_helper("18446744073709551615").get<uint64_t>() == 18446744073709551615u); } ``` **Fallacies:** _None_ **Graph:** _No Historic Data Found_ --- ### NPF-02.7 The service ignores leading and trailing whitespace. **Supported Requests:** - [NPF-02](NPF.md#npf-02) **Supporting Items:** _None_ **References:** - `cpp-test: [parse;whitespace] (TSF/tests/unit-numbers.cpp)` ```cpp SECTION("whitespace") { // Leading and trailing whitespace is ignored. CHECK(json::parse("\n\n\t 123\n\t\t \u000d")==json::parse("123")); CHECK(json::parse(" 123 ")==json::parse("123")); CHECK(json::parse(" 123\t")==json::parse("123")); CHECK(json::parse(" 123\n")==json::parse("123")); CHECK(json::parse(" 123\u000d")==json::parse("123")); CHECK(json::parse("\t123 ")==json::parse("123")); CHECK(json::parse("\t123\t")==json::parse("123")); CHECK(json::parse("\t123\n")==json::parse("123")); CHECK(json::parse("\t123\u000d")==json::parse("123")); CHECK(json::parse("\n123 ")==json::parse("123")); CHECK(json::parse("\n123\t")==json::parse("123")); CHECK(json::parse("\n123\n")==json::parse("123")); CHECK(json::parse("\n123\u000d")==json::parse("123")); CHECK(json::parse("\u000d123 ")==json::parse("123")); CHECK(json::parse("\u000d123\t")==json::parse("123")); CHECK(json::parse("\u000d123\n")==json::parse("123")); CHECK(json::parse("\u000d123\u000d")==json::parse("123")); } ``` - `function: [lexer::skip_whitespace] (include/nlohmann/detail/input/lexer.hpp)` - Description: function, which skips admissible whitespace during reading ```cpp void skip_whitespace() { do { get(); } while (current == ' ' || current == '\t' || current == '\n' || current == '\r'); } ``` **Fallacies:** _None_ **Graph:** _No Historic Data Found_ --- ### NPF-02.8 The service ignores one singular leading plus of the exponent. **Supported Requests:** - [NPF-02](NPF.md#npf-02) **Supporting Items:** _None_ **References:** - `cpp-test: [parse;exponents;leading plus] (TSF/tests/unit-numbers.cpp)` ```cpp SECTION("leading plus") { CHECK(json::parse("1\u0045+1")==json::parse("1\u00451")); CHECK(json::parse("1\u0065+1")==json::parse("1\u00651")); CHECK(json::parse("1.0034\u0045+23")==json::parse("1.0034\u004523")); CHECK(json::parse("1.0034\u0065+23")==json::parse("1.0034\u006523")); } ``` **Fallacies:** _None_ **Graph:** _No Historic Data Found_ --- ### NPF-02.9 The service parses floating point numbers within IEEE 754-2008 binary64 standard. **Supported Requests:** - [NPF-02](NPF.md#npf-02) **Supporting Items:** _None_ **References:** - `cpp-test: [compliance tests from nativejson-benchmark;doubles] (tests/src/unit-testsuites.cpp)` ```cpp SECTION("doubles") { auto TEST_DOUBLE = [](const std::string & json_string, const double expected) { CAPTURE(json_string) CAPTURE(expected) CHECK(json::parse(json_string)[0].get<double>() == Approx(expected)); }; TEST_DOUBLE("[0.0]", 0.0); TEST_DOUBLE("[-0.0]", -0.0); TEST_DOUBLE("[1.0]", 1.0); TEST_DOUBLE("[-1.0]", -1.0); TEST_DOUBLE("[1.5]", 1.5); TEST_DOUBLE("[-1.5]", -1.5); TEST_DOUBLE("[3.1416]", 3.1416); TEST_DOUBLE("[1E10]", 1E10); TEST_DOUBLE("[1e10]", 1e10); TEST_DOUBLE("[1E+10]", 1E+10); TEST_DOUBLE("[1E-10]", 1E-10); TEST_DOUBLE("[-1E10]", -1E10); TEST_DOUBLE("[-1e10]", -1e10); TEST_DOUBLE("[-1E+10]", -1E+10); TEST_DOUBLE("[-1E-10]", -1E-10); TEST_DOUBLE("[1.234E+10]", 1.234E+10); TEST_DOUBLE("[1.234E-10]", 1.234E-10); TEST_DOUBLE("[1.79769e+308]", 1.79769e+308); TEST_DOUBLE("[2.22507e-308]", 2.22507e-308); TEST_DOUBLE("[-1.79769e+308]", -1.79769e+308); TEST_DOUBLE("[-2.22507e-308]", -2.22507e-308); TEST_DOUBLE("[4.9406564584124654e-324]", 4.9406564584124654e-324); // minimum denormal TEST_DOUBLE("[2.2250738585072009e-308]", 2.2250738585072009e-308); // Max subnormal double TEST_DOUBLE("[2.2250738585072014e-308]", 2.2250738585072014e-308); // Min normal positive double TEST_DOUBLE("[1.7976931348623157e+308]", 1.7976931348623157e+308); // Max double TEST_DOUBLE("[1e-10000]", 0.0); // must underflow TEST_DOUBLE("[18446744073709551616]", 18446744073709551616.0); // 2^64 (max of uint64_t + 1, force to use double) TEST_DOUBLE("[-9223372036854775809]", -9223372036854775809.0); // -2^63 - 1(min of int64_t + 1, force to use double) TEST_DOUBLE("[0.9868011474609375]", 0.9868011474609375); // https://github.com/miloyip/rapidjson/issues/120 TEST_DOUBLE("[123e34]", 123e34); // Fast Path Cases In Disguise TEST_DOUBLE("[45913141877270640000.0]", 45913141877270640000.0); TEST_DOUBLE("[2.2250738585072011e-308]", 2.2250738585072011e-308); //TEST_DOUBLE("[1e-00011111111111]", 0.0); //TEST_DOUBLE("[-1e-00011111111111]", -0.0); TEST_DOUBLE("[1e-214748363]", 0.0); TEST_DOUBLE("[1e-214748364]", 0.0); //TEST_DOUBLE("[1e-21474836311]", 0.0); TEST_DOUBLE("[0.017976931348623157e+310]", 1.7976931348623157e+308); // Max double in another form // Since // abs((2^-1022 - 2^-1074) - 2.2250738585072012e-308) = 3.109754131239141401123495768877590405345064751974375599... ¡Á 10^-324 // abs((2^-1022) - 2.2250738585072012e-308) = 1.830902327173324040642192159804623318305533274168872044... ¡Á 10 ^ -324 // So 2.2250738585072012e-308 should round to 2^-1022 = 2.2250738585072014e-308 TEST_DOUBLE("[2.2250738585072012e-308]", 2.2250738585072014e-308); // Closer to normal/subnormal boundary // boundary = 2^-1022 - 2^-1075 = 2.225073858507201136057409796709131975934819546351645648... ¡Á 10^-308 TEST_DOUBLE("[2.22507385850720113605740979670913197593481954635164564e-308]", 2.2250738585072009e-308); TEST_DOUBLE("[2.22507385850720113605740979670913197593481954635164565e-308]", 2.2250738585072014e-308); // 1.0 is in (1.0 - 2^-54, 1.0 + 2^-53) // 1.0 - 2^-54 = 0.999999999999999944488848768742172978818416595458984375 TEST_DOUBLE("[0.999999999999999944488848768742172978818416595458984375]", 1.0); // round to even TEST_DOUBLE("[0.999999999999999944488848768742172978818416595458984374]", 0.99999999999999989); // previous double TEST_DOUBLE("[0.999999999999999944488848768742172978818416595458984376]", 1.0); // next double // 1.0 + 2^-53 = 1.00000000000000011102230246251565404236316680908203125 TEST_DOUBLE("[1.00000000000000011102230246251565404236316680908203125]", 1.0); // round to even TEST_DOUBLE("[1.00000000000000011102230246251565404236316680908203124]", 1.0); // previous double TEST_DOUBLE("[1.00000000000000011102230246251565404236316680908203126]", 1.00000000000000022); // next double // Numbers from https://github.com/floitsch/double-conversion/blob/master/test/cctest/test-strtod.cc TEST_DOUBLE("[72057594037927928.0]", 72057594037927928.0); TEST_DOUBLE("[72057594037927936.0]", 72057594037927936.0); TEST_DOUBLE("[72057594037927932.0]", 72057594037927936.0); TEST_DOUBLE("[7205759403792793199999e-5]", 72057594037927928.0); TEST_DOUBLE("[7205759403792793200001e-5]", 72057594037927936.0); TEST_DOUBLE("[9223372036854774784.0]", 9223372036854774784.0); TEST_DOUBLE("[9223372036854775808.0]", 9223372036854775808.0); TEST_DOUBLE("[9223372036854775296.0]", 9223372036854775808.0); TEST_DOUBLE("[922337203685477529599999e-5]", 9223372036854774784.0); TEST_DOUBLE("[922337203685477529600001e-5]", 9223372036854775808.0); TEST_DOUBLE("[10141204801825834086073718800384]", 10141204801825834086073718800384.0); TEST_DOUBLE("[10141204801825835211973625643008]", 10141204801825835211973625643008.0); TEST_DOUBLE("[10141204801825834649023672221696]", 10141204801825835211973625643008.0); TEST_DOUBLE("[1014120480182583464902367222169599999e-5]", 10141204801825834086073718800384.0); TEST_DOUBLE("[1014120480182583464902367222169600001e-5]", 10141204801825835211973625643008.0); TEST_DOUBLE("[5708990770823838890407843763683279797179383808]", 5708990770823838890407843763683279797179383808.0); TEST_DOUBLE("[5708990770823839524233143877797980545530986496]", 5708990770823839524233143877797980545530986496.0); TEST_DOUBLE("[5708990770823839207320493820740630171355185152]", 5708990770823839524233143877797980545530986496.0); TEST_DOUBLE("[5708990770823839207320493820740630171355185151999e-3]", 5708990770823838890407843763683279797179383808.0); TEST_DOUBLE("[5708990770823839207320493820740630171355185152001e-3]", 5708990770823839524233143877797980545530986496.0); { std::string n1e308(312, '0'); // '1' followed by 308 '0' n1e308[0] = '['; n1e308[1] = '1'; n1e308[310] = ']'; n1e308[311] = '\0'; TEST_DOUBLE(n1e308, 1E308); } // Cover trimming TEST_DOUBLE( "[2.22507385850720113605740979670913197593481954635164564802342610972482222202107694551652952390813508" "7914149158913039621106870086438694594645527657207407820621743379988141063267329253552286881372149012" "9811224514518898490572223072852551331557550159143974763979834118019993239625482890171070818506906306" "6665599493827577257201576306269066333264756530000924588831643303777979186961204949739037782970490505" "1080609940730262937128958950003583799967207254304360284078895771796150945516748243471030702609144621" "5722898802581825451803257070188608721131280795122334262883686223215037756666225039825343359745688844" "2390026549819838548794829220689472168983109969836584681402285424333066033985088644580400103493397042" "7567186443383770486037861622771738545623065874679014086723327636718751234567890123456789012345678901" "e-308]", 2.2250738585072014e-308); } ``` - `cpp-test: [regression tests 1;issue #360 - Loss of precision when serializing <double>] (tests/src/unit-regression1.cpp)` ```cpp SECTION("issue #360 - Loss of precision when serializing <double>") { auto check_roundtrip = [](double number) { CAPTURE(number) json j = number; CHECK(j.is_number_float()); std::stringstream ss; ss << j; CHECK_NOTHROW(ss >> j); CHECK(j.is_number_float()); CHECK(j.get<json::number_float_t>() == number); }; check_roundtrip(100000000000.1236); check_roundtrip((std::numeric_limits<json::number_float_t>::max)()); // Some more numbers which fail to roundtrip when serialized with digits10 significand digits (instead of max_digits10) check_roundtrip(1.541888611948064e-17); check_roundtrip(5.418771028591015e-16); check_roundtrip(9.398685592608595e-15); check_roundtrip(8.826843952762347e-14); check_roundtrip(8.143291313475335e-13); check_roundtrip(4.851328172762508e-12); check_roundtrip(6.677850998084358e-11); check_roundtrip(3.995398518174525e-10); check_roundtrip(1.960452605645124e-9); check_roundtrip(3.551812586302883e-8); check_roundtrip(2.947988411689261e-7); check_roundtrip(8.210166748056192e-6); check_roundtrip(6.104889704266753e-5); check_roundtrip(0.0008629954631330876); check_roundtrip(0.004936993881051611); check_roundtrip(0.08309725102608073); check_roundtrip(0.5210494268499783); check_roundtrip(6.382927930939767); check_roundtrip(59.94947245358671); check_roundtrip(361.0838651266122); check_roundtrip(4678.354596181877); check_roundtrip(61412.17658956043); check_roundtrip(725696.0799057782); check_roundtrip(2811732.583399828); check_roundtrip(30178351.07533605); check_roundtrip(689684880.3235844); check_roundtrip(5714887673.555147); check_roundtrip(84652038821.18808); check_roundtrip(156510583431.7721); check_roundtrip(5938450569021.732); check_roundtrip(83623297654460.33); check_roundtrip(701466573254773.6); check_roundtrip(1369013370304513); check_roundtrip(96963648023094720); // NOLINT(bugprone-narrowing-conversions,cppcoreguidelines-narrowing-conversions) check_roundtrip(3.478237409280108e+17); } ``` **Fallacies:** _None_ **Graph:** _No Historic Data Found_ --- ### NPF-03 The service parses strings according to RFC8259. **Supported Requests:** - [PJD-03](PJD.md#pjd-03) **Supporting Items:** - [NPF-03.1](NPF.md#npf-03.1) - [NPF-03.2](NPF.md#npf-03.2) - [NPF-03.3](NPF.md#npf-03.3) - [NPF-03.4](NPF.md#npf-03.4) - [NPF-03.5](NPF.md#npf-03.5) - [NPF-03.6](NPF.md#npf-03.6) - [NPF-03.7](NPF.md#npf-03.7) **References:** - `function: [lexer::scan_string] (include/nlohmann/detail/input/lexer.hpp)` - Description: function, which parses strings into C++ std::string and verifies *en passant* that these strings are in accordance with RFC8259 ```cpp token_type scan_string() { // reset token_buffer (ignore opening quote) reset(); // we entered the function by reading an open quote JSON_ASSERT(current == '\"'); while (true) { // get next character switch (get()) { // end of file while parsing string case char_traits<char_type>::eof(): { error_message = "invalid string: missing closing quote"; return token_type::parse_error; } // closing quote case '\"': { return token_type::value_string; } // escapes case '\\': { switch (get()) { // quotation mark case '\"': add('\"'); break; // reverse solidus case '\\': add('\\'); break; // solidus case '/': add('/'); break; // backspace case 'b': add('\b'); break; // form feed case 'f': add('\f'); break; // line feed case 'n': add('\n'); break; // carriage return case 'r': add('\r'); break; // tab case 't': add('\t'); break; // unicode escapes case 'u': { const int codepoint1 = get_codepoint(); int codepoint = codepoint1; // start with codepoint1 if (JSON_HEDLEY_UNLIKELY(codepoint1 == -1)) { error_message = "invalid string: '\\u' must be followed by 4 hex digits"; return token_type::parse_error; } // check if code point is a high surrogate if (0xD800 <= codepoint1 && codepoint1 <= 0xDBFF) { // expect next \uxxxx entry if (JSON_HEDLEY_LIKELY(get() == '\\' && get() == 'u')) { const int codepoint2 = get_codepoint(); if (JSON_HEDLEY_UNLIKELY(codepoint2 == -1)) { error_message = "invalid string: '\\u' must be followed by 4 hex digits"; return token_type::parse_error; } // check if codepoint2 is a low surrogate if (JSON_HEDLEY_LIKELY(0xDC00 <= codepoint2 && codepoint2 <= 0xDFFF)) { // overwrite codepoint codepoint = static_cast<int>( // high surrogate occupies the most significant 22 bits (static_cast<unsigned int>(codepoint1) << 10u) // low surrogate occupies the least significant 15 bits + static_cast<unsigned int>(codepoint2) // there is still the 0xD800, 0xDC00 and 0x10000 noise // in the result, so we have to subtract with: // (0xD800 << 10) + DC00 - 0x10000 = 0x35FDC00 - 0x35FDC00u); } else { error_message = "invalid string: surrogate U+D800..U+DBFF must be followed by U+DC00..U+DFFF"; return token_type::parse_error; } } else { error_message = "invalid string: surrogate U+D800..U+DBFF must be followed by U+DC00..U+DFFF"; return token_type::parse_error; } } else { if (JSON_HEDLEY_UNLIKELY(0xDC00 <= codepoint1 && codepoint1 <= 0xDFFF)) { error_message = "invalid string: surrogate U+DC00..U+DFFF must follow U+D800..U+DBFF"; return token_type::parse_error; } } // result of the above calculation yields a proper codepoint JSON_ASSERT(0x00 <= codepoint && codepoint <= 0x10FFFF); // translate codepoint into bytes if (codepoint < 0x80) { // 1-byte characters: 0xxxxxxx (ASCII) add(static_cast<char_int_type>(codepoint)); } else if (codepoint <= 0x7FF) { // 2-byte characters: 110xxxxx 10xxxxxx add(static_cast<char_int_type>(0xC0u | (static_cast<unsigned int>(codepoint) >> 6u))); add(static_cast<char_int_type>(0x80u | (static_cast<unsigned int>(codepoint) & 0x3Fu))); } else if (codepoint <= 0xFFFF) { // 3-byte characters: 1110xxxx 10xxxxxx 10xxxxxx add(static_cast<char_int_type>(0xE0u | (static_cast<unsigned int>(codepoint) >> 12u))); add(static_cast<char_int_type>(0x80u | ((static_cast<unsigned int>(codepoint) >> 6u) & 0x3Fu))); add(static_cast<char_int_type>(0x80u | (static_cast<unsigned int>(codepoint) & 0x3Fu))); } else { // 4-byte characters: 11110xxx 10xxxxxx 10xxxxxx 10xxxxxx add(static_cast<char_int_type>(0xF0u | (static_cast<unsigned int>(codepoint) >> 18u))); add(static_cast<char_int_type>(0x80u | ((static_cast<unsigned int>(codepoint) >> 12u) & 0x3Fu))); add(static_cast<char_int_type>(0x80u | ((static_cast<unsigned int>(codepoint) >> 6u) & 0x3Fu))); add(static_cast<char_int_type>(0x80u | (static_cast<unsigned int>(codepoint) & 0x3Fu))); } break; } // other characters after escape default: error_message = "invalid string: forbidden character after backslash"; return token_type::parse_error; } break; } // invalid control characters case 0x00: { error_message = "invalid string: control character U+0000 (NUL) must be escaped to \\u0000"; return token_type::parse_error; } case 0x01: { error_message = "invalid string: control character U+0001 (SOH) must be escaped to \\u0001"; return token_type::parse_error; } case 0x02: { error_message = "invalid string: control character U+0002 (STX) must be escaped to \\u0002"; return token_type::parse_error; } case 0x03: { error_message = "invalid string: control character U+0003 (ETX) must be escaped to \\u0003"; return token_type::parse_error; } case 0x04: { error_message = "invalid string: control character U+0004 (EOT) must be escaped to \\u0004"; return token_type::parse_error; } case 0x05: { error_message = "invalid string: control character U+0005 (ENQ) must be escaped to \\u0005"; return token_type::parse_error; } case 0x06: { error_message = "invalid string: control character U+0006 (ACK) must be escaped to \\u0006"; return token_type::parse_error; } case 0x07: { error_message = "invalid string: control character U+0007 (BEL) must be escaped to \\u0007"; return token_type::parse_error; } case 0x08: { error_message = "invalid string: control character U+0008 (BS) must be escaped to \\u0008 or \\b"; return token_type::parse_error; } case 0x09: { error_message = "invalid string: control character U+0009 (HT) must be escaped to \\u0009 or \\t"; return token_type::parse_error; } case 0x0A: { error_message = "invalid string: control character U+000A (LF) must be escaped to \\u000A or \\n"; return token_type::parse_error; } case 0x0B: { error_message = "invalid string: control character U+000B (VT) must be escaped to \\u000B"; return token_type::parse_error; } case 0x0C: { error_message = "invalid string: control character U+000C (FF) must be escaped to \\u000C or \\f"; return token_type::parse_error; } case 0x0D: { error_message = "invalid string: control character U+000D (CR) must be escaped to \\u000D or \\r"; return token_type::parse_error; } case 0x0E: { error_message = "invalid string: control character U+000E (SO) must be escaped to \\u000E"; return token_type::parse_error; } case 0x0F: { error_message = "invalid string: control character U+000F (SI) must be escaped to \\u000F"; return token_type::parse_error; } case 0x10: { error_message = "invalid string: control character U+0010 (DLE) must be escaped to \\u0010"; return token_type::parse_error; } case 0x11: { error_message = "invalid string: control character U+0011 (DC1) must be escaped to \\u0011"; return token_type::parse_error; } case 0x12: { error_message = "invalid string: control character U+0012 (DC2) must be escaped to \\u0012"; return token_type::parse_error; } case 0x13: { error_message = "invalid string: control character U+0013 (DC3) must be escaped to \\u0013"; return token_type::parse_error; } case 0x14: { error_message = "invalid string: control character U+0014 (DC4) must be escaped to \\u0014"; return token_type::parse_error; } case 0x15: { error_message = "invalid string: control character U+0015 (NAK) must be escaped to \\u0015"; return token_type::parse_error; } case 0x16: { error_message = "invalid string: control character U+0016 (SYN) must be escaped to \\u0016"; return token_type::parse_error; } case 0x17: { error_message = "invalid string: control character U+0017 (ETB) must be escaped to \\u0017"; return token_type::parse_error; } case 0x18: { error_message = "invalid string: control character U+0018 (CAN) must be escaped to \\u0018"; return token_type::parse_error; } case 0x19: { error_message = "invalid string: control character U+0019 (EM) must be escaped to \\u0019"; return token_type::parse_error; } case 0x1A: { error_message = "invalid string: control character U+001A (SUB) must be escaped to \\u001A"; return token_type::parse_error; } case 0x1B: { error_message = "invalid string: control character U+001B (ESC) must be escaped to \\u001B"; return token_type::parse_error; } case 0x1C: { error_message = "invalid string: control character U+001C (FS) must be escaped to \\u001C"; return token_type::parse_error; } case 0x1D: { error_message = "invalid string: control character U+001D (GS) must be escaped to \\u001D"; return token_type::parse_error; } case 0x1E: { error_message = "invalid string: control character U+001E (RS) must be escaped to \\u001E"; return token_type::parse_error; } case 0x1F: { error_message = "invalid string: control character U+001F (US) must be escaped to \\u001F"; return token_type::parse_error; } // U+0020..U+007F (except U+0022 (quote) and U+005C (backspace)) case 0x20: case 0x21: case 0x23: case 0x24: case 0x25: case 0x26: case 0x27: case 0x28: case 0x29: case 0x2A: case 0x2B: case 0x2C: case 0x2D: case 0x2E: case 0x2F: case 0x30: case 0x31: case 0x32: case 0x33: case 0x34: case 0x35: case 0x36: case 0x37: case 0x38: case 0x39: case 0x3A: case 0x3B: case 0x3C: case 0x3D: case 0x3E: case 0x3F: case 0x40: case 0x41: case 0x42: case 0x43: case 0x44: case 0x45: case 0x46: case 0x47: case 0x48: case 0x49: case 0x4A: case 0x4B: case 0x4C: case 0x4D: case 0x4E: case 0x4F: case 0x50: case 0x51: case 0x52: case 0x53: case 0x54: case 0x55: case 0x56: case 0x57: case 0x58: case 0x59: case 0x5A: case 0x5B: case 0x5D: case 0x5E: case 0x5F: case 0x60: case 0x61: case 0x62: case 0x63: case 0x64: case 0x65: case 0x66: case 0x67: case 0x68: case 0x69: case 0x6A: case 0x6B: case 0x6C: case 0x6D: case 0x6E: case 0x6F: case 0x70: case 0x71: case 0x72: case 0x73: case 0x74: case 0x75: case 0x76: case 0x77: case 0x78: case 0x79: case 0x7A: case 0x7B: case 0x7C: case 0x7D: case 0x7E: case 0x7F: { add(current); break; } // U+0080..U+07FF: bytes C2..DF 80..BF case 0xC2: case 0xC3: case 0xC4: case 0xC5: case 0xC6: case 0xC7: case 0xC8: case 0xC9: case 0xCA: case 0xCB: case 0xCC: case 0xCD: case 0xCE: case 0xCF: case 0xD0: case 0xD1: case 0xD2: case 0xD3: case 0xD4: case 0xD5: case 0xD6: case 0xD7: case 0xD8: case 0xD9: case 0xDA: case 0xDB: case 0xDC: case 0xDD: case 0xDE: case 0xDF: { if (JSON_HEDLEY_UNLIKELY(!next_byte_in_range({0x80, 0xBF}))) { return token_type::parse_error; } break; } // U+0800..U+0FFF: bytes E0 A0..BF 80..BF case 0xE0: { if (JSON_HEDLEY_UNLIKELY(!(next_byte_in_range({0xA0, 0xBF, 0x80, 0xBF})))) { return token_type::parse_error; } break; } // U+1000..U+CFFF: bytes E1..EC 80..BF 80..BF // U+E000..U+FFFF: bytes EE..EF 80..BF 80..BF case 0xE1: case 0xE2: case 0xE3: case 0xE4: case 0xE5: case 0xE6: case 0xE7: case 0xE8: case 0xE9: case 0xEA: case 0xEB: case 0xEC: case 0xEE: case 0xEF: { if (JSON_HEDLEY_UNLIKELY(!(next_byte_in_range({0x80, 0xBF, 0x80, 0xBF})))) { return token_type::parse_error; } break; } // U+D000..U+D7FF: bytes ED 80..9F 80..BF case 0xED: { if (JSON_HEDLEY_UNLIKELY(!(next_byte_in_range({0x80, 0x9F, 0x80, 0xBF})))) { return token_type::parse_error; } break; } // U+10000..U+3FFFF F0 90..BF 80..BF 80..BF case 0xF0: { if (JSON_HEDLEY_UNLIKELY(!(next_byte_in_range({0x90, 0xBF, 0x80, 0xBF, 0x80, 0xBF})))) { return token_type::parse_error; } break; } // U+40000..U+FFFFF F1..F3 80..BF 80..BF 80..BF case 0xF1: case 0xF2: case 0xF3: { if (JSON_HEDLEY_UNLIKELY(!(next_byte_in_range({0x80, 0xBF, 0x80, 0xBF, 0x80, 0xBF})))) { return token_type::parse_error; } break; } // U+100000..U+10FFFF F4 80..8F 80..BF 80..BF case 0xF4: { if (JSON_HEDLEY_UNLIKELY(!(next_byte_in_range({0x80, 0x8F, 0x80, 0xBF, 0x80, 0xBF})))) { return token_type::parse_error; } break; } // remaining bytes (80..C1 and F5..FF) are ill-formed default: { error_message = "invalid string: ill-formed UTF-8 byte"; return token_type::parse_error; } } } } ``` **Fallacies:** _None_ **Graph:** _No Historic Data Found_ --- ### NPF-03.1 The service ignores leading and trailing whitespace. **Supported Requests:** - [NPF-03](NPF.md#npf-03) **Supporting Items:** _None_ **References:** - `cpp-test: [parse;whitespace] (TSF/tests/unit-strings.cpp)` ```cpp SECTION("whitespace") { // leading and trailing whitespace is ignored. CHECK(json::parse(" \"foo\" ")==json::parse("\"foo\"")); CHECK(json::parse(" \"foo\"\t")==json::parse("\"foo\"")); CHECK(json::parse(" \"foo\"\n")==json::parse("\"foo\"")); CHECK(json::parse(" \"foo\"\u000d")==json::parse("\"foo\"")); CHECK(json::parse("\t\"foo\" ")==json::parse("\"foo\"")); CHECK(json::parse("\t\"foo\"\t")==json::parse("\"foo\"")); CHECK(json::parse("\t\"foo\"\n")==json::parse("\"foo\"")); CHECK(json::parse("\t\"foo\"\u000d")==json::parse("\"foo\"")); CHECK(json::parse("\n\"foo\" ")==json::parse("\"foo\"")); CHECK(json::parse("\n\"foo\"\t")==json::parse("\"foo\"")); CHECK(json::parse("\n\"foo\"\n")==json::parse("\"foo\"")); CHECK(json::parse("\n\"foo\"\u000d")==json::parse("\"foo\"")); CHECK(json::parse("\u000d\"foo\" ")==json::parse("\"foo\"")); CHECK(json::parse("\u000d\"foo\"\t")==json::parse("\"foo\"")); CHECK(json::parse("\u000d\"foo\"\n")==json::parse("\"foo\"")); CHECK(json::parse("\u000d\"foo\"\u000d")==json::parse("\"foo\"")); } ``` - `function: [lexer::skip_whitespace] (include/nlohmann/detail/input/lexer.hpp)` - Description: function, which skips admissible whitespace during reading ```cpp void skip_whitespace() { do { get(); } while (current == ' ' || current == '\t' || current == '\n' || current == '\r'); } ``` **Fallacies:** _None_ **Graph:** _No Historic Data Found_ --- ### NPF-03.2 The service parses escaped characters in the basic multilingual plane. **Supported Requests:** - [NPF-03](NPF.md#npf-03) **Supporting Items:** _None_ **References:** - `cpp-test: [parser class - core;parse;string;escaped] (TSF/tests/unit-class_parser_core.cpp)` ```cpp SECTION("escaped") { // quotation mark "\"" auto r1 = R"("\"")"_json; CHECK(parser_helper("\"\\\"\"") == r1); // reverse solidus "\\" auto r2 = R"("\\")"_json; CHECK(parser_helper("\"\\\\\"") == r2); // solidus CHECK(parser_helper("\"\\/\"") == R"("/")"_json); // backspace CHECK(parser_helper("\"\\b\"") == json("\b")); // formfeed CHECK(parser_helper("\"\\f\"") == json("\f")); // newline CHECK(parser_helper("\"\\n\"") == json("\n")); // carriage return CHECK(parser_helper("\"\\r\"") == json("\r")); // horizontal tab CHECK(parser_helper("\"\\t\"") == json("\t")); CHECK(parser_helper("\"\\u0001\"").get<json::string_t>() == "\x01"); CHECK(parser_helper("\"\\u000a\"").get<json::string_t>() == "\n"); CHECK(parser_helper("\"\\u00b0\"").get<json::string_t>() == "°"); CHECK(parser_helper("\"\\u0c00\"").get<json::string_t>() == "ఀ"); CHECK(parser_helper("\"\\ud000\"").get<json::string_t>() == "퀀"); CHECK(parser_helper("\"\\u000E\"").get<json::string_t>() == "\x0E"); CHECK(parser_helper("\"\\u00F0\"").get<json::string_t>() == "ð"); CHECK(parser_helper("\"\\u0100\"").get<json::string_t>() == "Ā"); CHECK(parser_helper("\"\\u2000\"").get<json::string_t>() == " "); CHECK(parser_helper("\"\\uFFFF\"").get<json::string_t>() == "￿"); CHECK(parser_helper("\"\\u20AC\"").get<json::string_t>() == "€"); CHECK(parser_helper("\"€\"").get<json::string_t>() == "€"); CHECK(parser_helper("\"🎈\"").get<json::string_t>() == "🎈"); CHECK(parser_helper("\"\\ud80c\\udc60\"").get<json::string_t>() == "\xf0\x93\x81\xa0"); CHECK(parser_helper("\"\\ud83c\\udf1e\"").get<json::string_t>() == "🌞"); } ``` - `cpp-test: [compliance tests from nativejson-benchmark;strings] (tests/src/unit-testsuites.cpp)` ```cpp SECTION("strings") { auto TEST_STRING = [](const std::string & json_string, const std::string & expected) { CAPTURE(json_string) CAPTURE(expected) CHECK(json::parse(json_string)[0].get<std::string>() == expected); }; TEST_STRING("[\"\"]", ""); TEST_STRING("[\"Hello\"]", "Hello"); TEST_STRING(R"(["Hello\nWorld"])", "Hello\nWorld"); //TEST_STRING("[\"Hello\\u0000World\"]", "Hello\0World"); TEST_STRING(R"(["\"\\/\b\f\n\r\t"])", "\"\\/\b\f\n\r\t"); TEST_STRING(R"(["\u0024"])", "$"); // Dollar sign U+0024 TEST_STRING(R"(["\u00A2"])", "\xC2\xA2"); // Cents sign U+00A2 TEST_STRING(R"(["\u20AC"])", "\xE2\x82\xAC"); // Euro sign U+20AC TEST_STRING(R"(["\uD834\uDD1E"])", "\xF0\x9D\x84\x9E"); // G clef sign U+1D11E } ``` - `cpp-test: [Unicode (1/5);\\uxxxx sequences;correct sequences] (tests/src/unit-unicode1.cpp)` ```cpp SECTION("correct sequences") { // 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) { // string to store the code point as in \uxxxx format std::string json_text = "\""; // decide whether to use one or two \uxxxx sequences if (cp < 0x10000u) { // 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 && 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) json _; CHECK_NOTHROW(_ = json::parse(json_text)); } } ``` **Fallacies:** _None_ **Graph:** _No Historic Data Found_ --- ### NPF-03.3 The service ignores capitalisation in escaped hexadecimal unicode. **Supported Requests:** - [NPF-03](NPF.md#npf-03) **Supporting Items:** _None_ **References:** - `cpp-test: [Unicode;escaped unicode] (TSF/tests/unit-strings.cpp)` ```cpp SECTION("escaped unicode") { for (uint32_t i = 0x0000; i<=0xFFFF; i++) { std::ostringstream temp; std::ostringstream temp2; temp << "\"\\u" << std::hex << std::uppercase << std::setfill('0') << std::setw(4) << i << "\""; temp2 << "\"\\u" << std::hex << std::nouppercase << std::setfill('0') << std::setw(4) << i << "\""; if (i>=0xD800 && i<=0xDFFF) { // Unpaired utf-16 surrogates are illegal. // Observe that this verbatim not what RFC8259 §7 prescribes; // it appears, however, to be in the spirit of RFC8259, cf. §8.2 // Illegal characters are not parsed anyway. CHECK(!json::accept(temp.str())); CHECK(!json::accept(temp2.str())); CHECK_THROWS_AS(parser_helper(temp.str()),json::parse_error&); CHECK_THROWS_AS(parser_helper(temp2.str()),json::parse_error&); } else { // all other characters of the basic multilingual plane are accepted. CHECK(json::accept(temp.str())); CHECK(json::accept(temp2.str())); CHECK(json::parse(temp.str())==json::parse(temp2.str())); } } } ``` **Fallacies:** _None_ **Graph:** _No Historic Data Found_ --- ### NPF-03.4 The service parses all unescaped utf-8 characters except quotation mark, reverse solidus and the control characters. **Supported Requests:** - [NPF-03](NPF.md#npf-03) **Supporting Items:** _None_ **References:** - `cpp-test: [RFC 8259 examples;7. Strings] (tests/src/unit-testsuites.cpp)` ```cpp SECTION("7. Strings") { CHECK(json::parse("\"\\u005C\"") == json("\\")); CHECK(json::parse("\"\\uD834\\uDD1E\"") == json("𝄞")); CHECK(json::parse("\"𝄞\"") == json("𝄞")); } ``` - `cpp-testsuite: [/json_nlohmann_tests/all_unicode.json]` - JSON Testsuite: /json_nlohmann_tests/all_unicode.json [Link to file](https://raw.githubusercontent.com/eclipse-score/inc_nlohmann_json/refs/heads/json_test_data_version_3_1_0_mirror//json_nlohmann_tests/all_unicode.json) [Content too large - 1112068 lines] - cpp-test: [Unicode (1/5);read all unicode characters] (tests/src/unit-unicode1.cpp) ```cpp SECTION("read all unicode characters") { // read a file with all Unicode characters stored as single-character // strings in a JSON array std::ifstream f(TEST_DATA_DIRECTORY "/json_nlohmann_tests/all_unicode.json"); json j; CHECK_NOTHROW(f >> j); // the array has 1112064 + 1 elements (a terminating "null" value) // Note: 1112064 = 0x1FFFFF code points - 2048 invalid values between // 0xD800 and 0xDFFF. CHECK(j.size() == 1112065); SECTION("check JSON Pointers") { for (const auto& s : j) { // skip non-string JSON values if (!s.is_string()) { continue; } auto ptr = s.get<std::string>(); // tilde must be followed by 0 or 1 if (ptr == "~") { ptr += "0"; } // JSON Pointers must begin with "/" ptr.insert(0, "/"); CHECK_NOTHROW(json::json_pointer("/" + ptr)); // check escape/unescape roundtrip auto escaped = nlohmann::detail::escape(ptr); nlohmann::detail::unescape(escaped); CHECK(escaped == ptr); } } } ``` - `cpp-test: [Unicode;unescaped unicode] (TSF/tests/unit-strings.cpp)` ```cpp SECTION("unescaped unicode") { for (uint32_t i = 0x0000; i<=0x10FFFF; i++) { std::string temp = uint_to_utf8(i); if ((i>=0xD800 && i<=0xDFFF)) { // Unpaired utf-16 surrogates are illegal. // Observe that this verbatim not what RFC8259 §7 prescribes; // it appears, however, to be in the spirit of RFC8259, cf. §8.2 // The other characters are illegal if unescaped. CHECK(!json::accept(temp)); CHECK_THROWS_AS(parser_helper(temp),json::parse_error&); if (i<=0xDBFF){ for (uint32_t j = 0xDC00; j<=0xDFFF; j++){ temp += uint_to_utf8(j); CHECK(!json::accept(temp)); CHECK_THROWS_AS(parser_helper(temp),json::parse_error&); } } } else if (i<0x0020||i==0x0022||i==0x005c){ CHECK(!json::accept(temp)); CHECK_THROWS_AS(parser_helper(temp),json::parse_error&); } else { // All other characters are valid according to RFC8259 CHECK_NOTHROW(parser_helper(temp)); } } } ``` **Fallacies:** _None_ **Graph:** _No Historic Data Found_ --- ### NPF-03.5 The service parses \\, \\/, \\b,\\f, \\n, \\r, \\t and escaped quotation marks. **Supported Requests:** - [NPF-03](NPF.md#npf-03) **Supporting Items:** _None_ **References:** - `cpp-test: [compliance tests from nativejson-benchmark;strings] (tests/src/unit-testsuites.cpp)` ```cpp SECTION("strings") { auto TEST_STRING = [](const std::string & json_string, const std::string & expected) { CAPTURE(json_string) CAPTURE(expected) CHECK(json::parse(json_string)[0].get<std::string>() == expected); }; TEST_STRING("[\"\"]", ""); TEST_STRING("[\"Hello\"]", "Hello"); TEST_STRING(R"(["Hello\nWorld"])", "Hello\nWorld"); //TEST_STRING("[\"Hello\\u0000World\"]", "Hello\0World"); TEST_STRING(R"(["\"\\/\b\f\n\r\t"])", "\"\\/\b\f\n\r\t"); TEST_STRING(R"(["\u0024"])", "$"); // Dollar sign U+0024 TEST_STRING(R"(["\u00A2"])", "\xC2\xA2"); // Cents sign U+00A2 TEST_STRING(R"(["\u20AC"])", "\xE2\x82\xAC"); // Euro sign U+20AC TEST_STRING(R"(["\uD834\uDD1E"])", "\xF0\x9D\x84\x9E"); // G clef sign U+1D11E } ``` - `cpp-test: [parser class - core;parse;string;escaped] (TSF/tests/unit-class_parser_core.cpp)` ```cpp SECTION("escaped") { // quotation mark "\"" auto r1 = R"("\"")"_json; CHECK(parser_helper("\"\\\"\"") == r1); // reverse solidus "\\" auto r2 = R"("\\")"_json; CHECK(parser_helper("\"\\\\\"") == r2); // solidus CHECK(parser_helper("\"\\/\"") == R"("/")"_json); // backspace CHECK(parser_helper("\"\\b\"") == json("\b")); // formfeed CHECK(parser_helper("\"\\f\"") == json("\f")); // newline CHECK(parser_helper("\"\\n\"") == json("\n")); // carriage return CHECK(parser_helper("\"\\r\"") == json("\r")); // horizontal tab CHECK(parser_helper("\"\\t\"") == json("\t")); CHECK(parser_helper("\"\\u0001\"").get<json::string_t>() == "\x01"); CHECK(parser_helper("\"\\u000a\"").get<json::string_t>() == "\n"); CHECK(parser_helper("\"\\u00b0\"").get<json::string_t>() == "°"); CHECK(parser_helper("\"\\u0c00\"").get<json::string_t>() == "ఀ"); CHECK(parser_helper("\"\\ud000\"").get<json::string_t>() == "퀀"); CHECK(parser_helper("\"\\u000E\"").get<json::string_t>() == "\x0E"); CHECK(parser_helper("\"\\u00F0\"").get<json::string_t>() == "ð"); CHECK(parser_helper("\"\\u0100\"").get<json::string_t>() == "Ā"); CHECK(parser_helper("\"\\u2000\"").get<json::string_t>() == " "); CHECK(parser_helper("\"\\uFFFF\"").get<json::string_t>() == "￿"); CHECK(parser_helper("\"\\u20AC\"").get<json::string_t>() == "€"); CHECK(parser_helper("\"€\"").get<json::string_t>() == "€"); CHECK(parser_helper("\"🎈\"").get<json::string_t>() == "🎈"); CHECK(parser_helper("\"\\ud80c\\udc60\"").get<json::string_t>() == "\xf0\x93\x81\xa0"); CHECK(parser_helper("\"\\ud83c\\udf1e\"").get<json::string_t>() == "🌞"); } ``` **Fallacies:** _None_ **Graph:** _No Historic Data Found_ --- ### NPF-03.6 The service parses the empty string. **Supported Requests:** - [NPF-03](NPF.md#npf-03) **Supporting Items:** _None_ **References:** - `cpp-test: [parser class - core;parse;string] (TSF/tests/unit-class_parser_core.cpp)` ```cpp SECTION("string") { // empty string CHECK(parser_helper("\"\"") == json(json::value_t::string)); SECTION("errors") { // error: tab in string CHECK_THROWS_WITH_AS(parser_helper("\"\t\""), "[json.exception.parse_error.101] parse error at line 1, column 2: syntax error while parsing value - invalid string: control character U+0009 (HT) must be escaped to \\u0009 or \\t; last read: '\"<U+0009>'", json::parse_error&); // error: newline in string CHECK_THROWS_WITH_AS(parser_helper("\"\n\""), "[json.exception.parse_error.101] parse error at line 2, column 0: syntax error while parsing value - invalid string: control character U+000A (LF) must be escaped to \\u000A or \\n; last read: '\"<U+000A>'", json::parse_error&); CHECK_THROWS_WITH_AS(parser_helper("\"\r\""), "[json.exception.parse_error.101] parse error at line 1, column 2: syntax error while parsing value - invalid string: control character U+000D (CR) must be escaped to \\u000D or \\r; last read: '\"<U+000D>'", json::parse_error&); // error: backspace in string CHECK_THROWS_WITH_AS(parser_helper("\"\b\""), "[json.exception.parse_error.101] parse error at line 1, column 2: syntax error while parsing value - invalid string: control character U+0008 (BS) must be escaped to \\u0008 or \\b; last read: '\"<U+0008>'", json::parse_error&); // improve code coverage CHECK_THROWS_AS(parser_helper("\uFF01"), json::parse_error&); CHECK_THROWS_AS(parser_helper("[-4:1,]"), json::parse_error&); // unescaped control characters CHECK_THROWS_WITH_AS(parser_helper("\"\x00\""), "[json.exception.parse_error.101] parse error at line 1, column 2: syntax error while parsing value - invalid string: missing closing quote; last read: '\"'", json::parse_error&); // NOLINT(bugprone-string-literal-with-embedded-nul) CHECK_THROWS_WITH_AS(parser_helper("\"\x01\""), "[json.exception.parse_error.101] parse error at line 1, column 2: syntax error while parsing value - invalid string: control character U+0001 (SOH) must be escaped to \\u0001; last read: '\"<U+0001>'", json::parse_error&); CHECK_THROWS_WITH_AS(parser_helper("\"\x02\""), "[json.exception.parse_error.101] parse error at line 1, column 2: syntax error while parsing value - invalid string: control character U+0002 (STX) must be escaped to \\u0002; last read: '\"<U+0002>'", json::parse_error&); CHECK_THROWS_WITH_AS(parser_helper("\"\x03\""), "[json.exception.parse_error.101] parse error at line 1, column 2: syntax error while parsing value - invalid string: control character U+0003 (ETX) must be escaped to \\u0003; last read: '\"<U+0003>'", json::parse_error&); CHECK_THROWS_WITH_AS(parser_helper("\"\x04\""), "[json.exception.parse_error.101] parse error at line 1, column 2: syntax error while parsing value - invalid string: control character U+0004 (EOT) must be escaped to \\u0004; last read: '\"<U+0004>'", json::parse_error&); CHECK_THROWS_WITH_AS(parser_helper("\"\x05\""), "[json.exception.parse_error.101] parse error at line 1, column 2: syntax error while parsing value - invalid string: control character U+0005 (ENQ) must be escaped to \\u0005; last read: '\"<U+0005>'", json::parse_error&); CHECK_THROWS_WITH_AS(parser_helper("\"\x06\""), "[json.exception.parse_error.101] parse error at line 1, column 2: syntax error while parsing value - invalid string: control character U+0006 (ACK) must be escaped to \\u0006; last read: '\"<U+0006>'", json::parse_error&); CHECK_THROWS_WITH_AS(parser_helper("\"\x07\""), "[json.exception.parse_error.101] parse error at line 1, column 2: syntax error while parsing value - invalid string: control character U+0007 (BEL) must be escaped to \\u0007; last read: '\"<U+0007>'", json::parse_error&); CHECK_THROWS_WITH_AS(parser_helper("\"\x08\""), "[json.exception.parse_error.101] parse error at line 1, column 2: syntax error while parsing value - invalid string: control character U+0008 (BS) must be escaped to \\u0008 or \\b; last read: '\"<U+0008>'", json::parse_error&); CHECK_THROWS_WITH_AS(parser_helper("\"\x09\""), "[json.exception.parse_error.101] parse error at line 1, column 2: syntax error while parsing value - invalid string: control character U+0009 (HT) must be escaped to \\u0009 or \\t; last read: '\"<U+0009>'", json::parse_error&); CHECK_THROWS_WITH_AS(parser_helper("\"\x0a\""), "[json.exception.parse_error.101] parse error at line 2, column 0: syntax error while parsing value - invalid string: control character U+000A (LF) must be escaped to \\u000A or \\n; last read: '\"<U+000A>'", json::parse_error&); CHECK_THROWS_WITH_AS(parser_helper("\"\x0b\""), "[json.exception.parse_error.101] parse error at line 1, column 2: syntax error while parsing value - invalid string: control character U+000B (VT) must be escaped to \\u000B; last read: '\"<U+000B>'", json::parse_error&); CHECK_THROWS_WITH_AS(parser_helper("\"\x0c\""), "[json.exception.parse_error.101] parse error at line 1, column 2: syntax error while parsing value - invalid string: control character U+000C (FF) must be escaped to \\u000C or \\f; last read: '\"<U+000C>'", json::parse_error&); CHECK_THROWS_WITH_AS(parser_helper("\"\x0d\""), "[json.exception.parse_error.101] parse error at line 1, column 2: syntax error while parsing value - invalid string: control character U+000D (CR) must be escaped to \\u000D or \\r; last read: '\"<U+000D>'", json::parse_error&); CHECK_THROWS_WITH_AS(parser_helper("\"\x0e\""), "[json.exception.parse_error.101] parse error at line 1, column 2: syntax error while parsing value - invalid string: control character U+000E (SO) must be escaped to \\u000E; last read: '\"<U+000E>'", json::parse_error&); CHECK_THROWS_WITH_AS(parser_helper("\"\x0f\""), "[json.exception.parse_error.101] parse error at line 1, column 2: syntax error while parsing value - invalid string: control character U+000F (SI) must be escaped to \\u000F; last read: '\"<U+000F>'", json::parse_error&); CHECK_THROWS_WITH_AS(parser_helper("\"\x10\""), "[json.exception.parse_error.101] parse error at line 1, column 2: syntax error while parsing value - invalid string: control character U+0010 (DLE) must be escaped to \\u0010; last read: '\"<U+0010>'", json::parse_error&); CHECK_THROWS_WITH_AS(parser_helper("\"\x11\""), "[json.exception.parse_error.101] parse error at line 1, column 2: syntax error while parsing value - invalid string: control character U+0011 (DC1) must be escaped to \\u0011; last read: '\"<U+0011>'", json::parse_error&); CHECK_THROWS_WITH_AS(parser_helper("\"\x12\""), "[json.exception.parse_error.101] parse error at line 1, column 2: syntax error while parsing value - invalid string: control character U+0012 (DC2) must be escaped to \\u0012; last read: '\"<U+0012>'", json::parse_error&); CHECK_THROWS_WITH_AS(parser_helper("\"\x13\""), "[json.exception.parse_error.101] parse error at line 1, column 2: syntax error while parsing value - invalid string: control character U+0013 (DC3) must be escaped to \\u0013; last read: '\"<U+0013>'", json::parse_error&); CHECK_THROWS_WITH_AS(parser_helper("\"\x14\""), "[json.exception.parse_error.101] parse error at line 1, column 2: syntax error while parsing value - invalid string: control character U+0014 (DC4) must be escaped to \\u0014; last read: '\"<U+0014>'", json::parse_error&); CHECK_THROWS_WITH_AS(parser_helper("\"\x15\""), "[json.exception.parse_error.101] parse error at line 1, column 2: syntax error while parsing value - invalid string: control character U+0015 (NAK) must be escaped to \\u0015; last read: '\"<U+0015>'", json::parse_error&); CHECK_THROWS_WITH_AS(parser_helper("\"\x16\""), "[json.exception.parse_error.101] parse error at line 1, column 2: syntax error while parsing value - invalid string: control character U+0016 (SYN) must be escaped to \\u0016; last read: '\"<U+0016>'", json::parse_error&); CHECK_THROWS_WITH_AS(parser_helper("\"\x17\""), "[json.exception.parse_error.101] parse error at line 1, column 2: syntax error while parsing value - invalid string: control character U+0017 (ETB) must be escaped to \\u0017; last read: '\"<U+0017>'", json::parse_error&); CHECK_THROWS_WITH_AS(parser_helper("\"\x18\""), "[json.exception.parse_error.101] parse error at line 1, column 2: syntax error while parsing value - invalid string: control character U+0018 (CAN) must be escaped to \\u0018; last read: '\"<U+0018>'", json::parse_error&); CHECK_THROWS_WITH_AS(parser_helper("\"\x19\""), "[json.exception.parse_error.101] parse error at line 1, column 2: syntax error while parsing value - invalid string: control character U+0019 (EM) must be escaped to \\u0019; last read: '\"<U+0019>'", json::parse_error&); CHECK_THROWS_WITH_AS(parser_helper("\"\x1a\""), "[json.exception.parse_error.101] parse error at line 1, column 2: syntax error while parsing value - invalid string: control character U+001A (SUB) must be escaped to \\u001A; last read: '\"<U+001A>'", json::parse_error&); CHECK_THROWS_WITH_AS(parser_helper("\"\x1b\""), "[json.exception.parse_error.101] parse error at line 1, column 2: syntax error while parsing value - invalid string: control character U+001B (ESC) must be escaped to \\u001B; last read: '\"<U+001B>'", json::parse_error&); CHECK_THROWS_WITH_AS(parser_helper("\"\x1c\""), "[json.exception.parse_error.101] parse error at line 1, column 2: syntax error while parsing value - invalid string: control character U+001C (FS) must be escaped to \\u001C; last read: '\"<U+001C>'", json::parse_error&); CHECK_THROWS_WITH_AS(parser_helper("\"\x1d\""), "[json.exception.parse_error.101] parse error at line 1, column 2: syntax error while parsing value - invalid string: control character U+001D (GS) must be escaped to \\u001D; last read: '\"<U+001D>'", json::parse_error&); CHECK_THROWS_WITH_AS(parser_helper("\"\x1e\""), "[json.exception.parse_error.101] parse error at line 1, column 2: syntax error while parsing value - invalid string: control character U+001E (RS) must be escaped to \\u001E; last read: '\"<U+001E>'", json::parse_error&); CHECK_THROWS_WITH_AS(parser_helper("\"\x1f\""), "[json.exception.parse_error.101] parse error at line 1, column 2: syntax error while parsing value - invalid string: control character U+001F (US) must be escaped to \\u001F; last read: '\"<U+001F>'", json::parse_error&); SECTION("additional test for null byte") { // The test above for the null byte is wrong, because passing // a string to the parser only reads int until it encounters // a null byte. This test inserts the null byte later on and // uses an iterator range. std::string s = "\"1\""; s[1] = '\0'; json _; CHECK_THROWS_WITH_AS(_ = json::parse(s.begin(), s.end()), "[json.exception.parse_error.101] parse error at line 1, column 2: syntax error while parsing value - invalid string: control character U+0000 (NUL) must be escaped to \\u0000; last read: '\"<U+0000>'", json::parse_error&); } } SECTION("escaped") { // quotation mark "\"" auto r1 = R"("\"")"_json; CHECK(parser_helper("\"\\\"\"") == r1); // reverse solidus "\\" auto r2 = R"("\\")"_json; CHECK(parser_helper("\"\\\\\"") == r2); // solidus CHECK(parser_helper("\"\\/\"") == R"("/")"_json); // backspace CHECK(parser_helper("\"\\b\"") == json("\b")); // formfeed CHECK(parser_helper("\"\\f\"") == json("\f")); // newline CHECK(parser_helper("\"\\n\"") == json("\n")); // carriage return CHECK(parser_helper("\"\\r\"") == json("\r")); // horizontal tab CHECK(parser_helper("\"\\t\"") == json("\t")); CHECK(parser_helper("\"\\u0001\"").get<json::string_t>() == "\x01"); CHECK(parser_helper("\"\\u000a\"").get<json::string_t>() == "\n"); CHECK(parser_helper("\"\\u00b0\"").get<json::string_t>() == "°"); CHECK(parser_helper("\"\\u0c00\"").get<json::string_t>() == "ఀ"); CHECK(parser_helper("\"\\ud000\"").get<json::string_t>() == "퀀"); CHECK(parser_helper("\"\\u000E\"").get<json::string_t>() == "\x0E"); CHECK(parser_helper("\"\\u00F0\"").get<json::string_t>() == "ð"); CHECK(parser_helper("\"\\u0100\"").get<json::string_t>() == "Ā"); CHECK(parser_helper("\"\\u2000\"").get<json::string_t>() == " "); CHECK(parser_helper("\"\\uFFFF\"").get<json::string_t>() == "￿"); CHECK(parser_helper("\"\\u20AC\"").get<json::string_t>() == "€"); CHECK(parser_helper("\"€\"").get<json::string_t>() == "€"); CHECK(parser_helper("\"🎈\"").get<json::string_t>() == "🎈"); CHECK(parser_helper("\"\\ud80c\\udc60\"").get<json::string_t>() == "\xf0\x93\x81\xa0"); CHECK(parser_helper("\"\\ud83c\\udf1e\"").get<json::string_t>() == "🌞"); } } ``` **Fallacies:** _None_ **Graph:** _No Historic Data Found_ --- ### NPF-03.7 The service parses non-empty strings. **Supported Requests:** - [NPF-03](NPF.md#npf-03) **Supporting Items:** _None_ **References:** - `cpp-test: [parser class - core;parse;string;escaped] (TSF/tests/unit-class_parser_core.cpp)` ```cpp SECTION("escaped") { // quotation mark "\"" auto r1 = R"("\"")"_json; CHECK(parser_helper("\"\\\"\"") == r1); // reverse solidus "\\" auto r2 = R"("\\")"_json; CHECK(parser_helper("\"\\\\\"") == r2); // solidus CHECK(parser_helper("\"\\/\"") == R"("/")"_json); // backspace CHECK(parser_helper("\"\\b\"") == json("\b")); // formfeed CHECK(parser_helper("\"\\f\"") == json("\f")); // newline CHECK(parser_helper("\"\\n\"") == json("\n")); // carriage return CHECK(parser_helper("\"\\r\"") == json("\r")); // horizontal tab CHECK(parser_helper("\"\\t\"") == json("\t")); CHECK(parser_helper("\"\\u0001\"").get<json::string_t>() == "\x01"); CHECK(parser_helper("\"\\u000a\"").get<json::string_t>() == "\n"); CHECK(parser_helper("\"\\u00b0\"").get<json::string_t>() == "°"); CHECK(parser_helper("\"\\u0c00\"").get<json::string_t>() == "ఀ"); CHECK(parser_helper("\"\\ud000\"").get<json::string_t>() == "퀀"); CHECK(parser_helper("\"\\u000E\"").get<json::string_t>() == "\x0E"); CHECK(parser_helper("\"\\u00F0\"").get<json::string_t>() == "ð"); CHECK(parser_helper("\"\\u0100\"").get<json::string_t>() == "Ā"); CHECK(parser_helper("\"\\u2000\"").get<json::string_t>() == " "); CHECK(parser_helper("\"\\uFFFF\"").get<json::string_t>() == "￿"); CHECK(parser_helper("\"\\u20AC\"").get<json::string_t>() == "€"); CHECK(parser_helper("\"€\"").get<json::string_t>() == "€"); CHECK(parser_helper("\"🎈\"").get<json::string_t>() == "🎈"); CHECK(parser_helper("\"\\ud80c\\udc60\"").get<json::string_t>() == "\xf0\x93\x81\xa0"); CHECK(parser_helper("\"\\ud83c\\udf1e\"").get<json::string_t>() == "🌞"); } ``` - `cpp-test: [compliance tests from nativejson-benchmark;strings] (tests/src/unit-testsuites.cpp)` ```cpp SECTION("strings") { auto TEST_STRING = [](const std::string & json_string, const std::string & expected) { CAPTURE(json_string) CAPTURE(expected) CHECK(json::parse(json_string)[0].get<std::string>() == expected); }; TEST_STRING("[\"\"]", ""); TEST_STRING("[\"Hello\"]", "Hello"); TEST_STRING(R"(["Hello\nWorld"])", "Hello\nWorld"); //TEST_STRING("[\"Hello\\u0000World\"]", "Hello\0World"); TEST_STRING(R"(["\"\\/\b\f\n\r\t"])", "\"\\/\b\f\n\r\t"); TEST_STRING(R"(["\u0024"])", "$"); // Dollar sign U+0024 TEST_STRING(R"(["\u00A2"])", "\xC2\xA2"); // Cents sign U+00A2 TEST_STRING(R"(["\u20AC"])", "\xE2\x82\xAC"); // Euro sign U+20AC TEST_STRING(R"(["\uD834\uDD1E"])", "\xF0\x9D\x84\x9E"); // G clef sign U+1D11E } ``` - `cpp-test: [RFC 8259 examples;7. Strings] (tests/src/unit-testsuites.cpp)` ```cpp SECTION("7. Strings") { CHECK(json::parse("\"\\u005C\"") == json("\\")); CHECK(json::parse("\"\\uD834\\uDD1E\"") == json("𝄞")); CHECK(json::parse("\"𝄞\"") == json("𝄞")); } ``` - `cpp-testsuite: [/nst_json_testsuite2/test_parsing/y_string_1_2_3_bytes_UTF-8_sequences.json, /nst_json_testsuite2/test_parsing/y_string_accepted_surrogate_pair.json, /nst_json_testsuite2/test_parsing/y_string_accepted_surrogate_pairs.json, /nst_json_testsuite2/test_parsing/y_string_allowed_escapes.json, /nst_json_testsuite2/test_parsing/y_string_backslash_and_u_escaped_zero.json, /nst_json_testsuite2/test_parsing/y_string_backslash_doublequotes.json, /nst_json_testsuite2/test_parsing/y_string_comments.json, /nst_json_testsuite2/test_parsing/y_string_double_escape_a.json, /nst_json_testsuite2/test_parsing/y_string_double_escape_n.json, /nst_json_testsuite2/test_parsing/y_string_escaped_control_character.json, /nst_json_testsuite2/test_parsing/y_string_escaped_noncharacter.json, /nst_json_testsuite2/test_parsing/y_string_in_array.json, /nst_json_testsuite2/test_parsing/y_string_in_array_with_leading_space.json, /nst_json_testsuite2/test_parsing/y_string_last_surrogates_1_and_2.json, /nst_json_testsuite2/test_parsing/y_string_nbsp_uescaped.json, /nst_json_testsuite2/test_parsing/y_string_nonCharacterInUTF-8_U+10FFFF.json, /nst_json_testsuite2/test_parsing/y_string_nonCharacterInUTF-8_U+FFFF.json, /nst_json_testsuite2/test_parsing/y_string_null_escape.json, /nst_json_testsuite2/test_parsing/y_string_one-byte-utf-8.json, /nst_json_testsuite2/test_parsing/y_string_pi.json, /nst_json_testsuite2/test_parsing/y_string_reservedCharacterInUTF-8_U+1BFFF.json, /nst_json_testsuite2/test_parsing/y_string_simple_ascii.json, /nst_json_testsuite2/test_parsing/y_string_space.json, /nst_json_testsuite2/test_parsing/y_string_surrogates_U+1D11E_MUSICAL_SYMBOL_G_CLEF.json, /nst_json_testsuite2/test_parsing/y_string_three-byte-utf-8.json, /nst_json_testsuite2/test_parsing/y_string_two-byte-utf-8.json, /nst_json_testsuite2/test_parsing/y_string_u+2028_line_sep.json, /nst_json_testsuite2/test_parsing/y_string_u+2029_par_sep.json, /nst_json_testsuite2/test_parsing/y_string_uEscape.json, /nst_json_testsuite2/test_parsing/y_string_uescaped_newline.json, /nst_json_testsuite2/test_parsing/y_string_unescaped_char_delete.json, /nst_json_testsuite2/test_parsing/y_string_unicode.json, /nst_json_testsuite2/test_parsing/y_string_unicodeEscapedBackslash.json, /nst_json_testsuite2/test_parsing/y_string_unicode_2.json, /nst_json_testsuite2/test_parsing/y_string_unicode_U+10FFFE_nonchar.json, /nst_json_testsuite2/test_parsing/y_string_unicode_U+1FFFE_nonchar.json, /nst_json_testsuite2/test_parsing/y_string_unicode_U+200B_ZERO_WIDTH_SPACE.json, /nst_json_testsuite2/test_parsing/y_string_unicode_U+2064_invisible_plus.json, /nst_json_testsuite2/test_parsing/y_string_unicode_U+FDD0_nonchar.json, /nst_json_testsuite2/test_parsing/y_string_unicode_U+FFFE_nonchar.json, /nst_json_testsuite2/test_parsing/y_string_unicode_escaped_double_quote.json, /nst_json_testsuite2/test_parsing/y_string_utf8.json, /nst_json_testsuite2/test_parsing/y_string_with_del_character.json]` - Description: Tests whether several non-empty strings are parsed without throwing an exception. - JSON Testsuite: /nst_json_testsuite2/test_parsing/y_string_1_2_3_bytes_UTF-8_sequences.json ```json ["\u0060\u012a\u12AB"] ``` - JSON Testsuite: /nst_json_testsuite2/test_parsing/y_string_accepted_surrogate_pair.json ```json ["\uD801\udc37"] ``` - JSON Testsuite: /nst_json_testsuite2/test_parsing/y_string_accepted_surrogate_pairs.json ```json ["\ud83d\ude39\ud83d\udc8d"] ``` - JSON Testsuite: /nst_json_testsuite2/test_parsing/y_string_allowed_escapes.json ```json ["\"\\\/\b\f\n\r\t"] ``` - JSON Testsuite: /nst_json_testsuite2/test_parsing/y_string_backslash_and_u_escaped_zero.json ```json ["\\u0000"] ``` - JSON Testsuite: /nst_json_testsuite2/test_parsing/y_string_backslash_doublequotes.json ```json ["\""] ``` - JSON Testsuite: /nst_json_testsuite2/test_parsing/y_string_comments.json ```json ["a/*b*/c/*d//e"] ``` - JSON Testsuite: /nst_json_testsuite2/test_parsing/y_string_double_escape_a.json ```json ["\\a"] ``` - JSON Testsuite: /nst_json_testsuite2/test_parsing/y_string_double_escape_n.json ```json ["\\n"] ``` - JSON Testsuite: /nst_json_testsuite2/test_parsing/y_string_escaped_control_character.json ```json ["\u0012"] ``` - JSON Testsuite: /nst_json_testsuite2/test_parsing/y_string_escaped_noncharacter.json ```json ["\uFFFF"] ``` - JSON Testsuite: /nst_json_testsuite2/test_parsing/y_string_in_array.json ```json ["asd"] ``` - JSON Testsuite: /nst_json_testsuite2/test_parsing/y_string_in_array_with_leading_space.json ```json [ "asd"] ``` - JSON Testsuite: /nst_json_testsuite2/test_parsing/y_string_last_surrogates_1_and_2.json ```json ["\uDBFF\uDFFF"] ``` - JSON Testsuite: /nst_json_testsuite2/test_parsing/y_string_nbsp_uescaped.json ```json ["new\u00A0line"] ``` - JSON Testsuite: /nst_json_testsuite2/test_parsing/y_string_nonCharacterInUTF-8_U+10FFFF.json ```json ["􏿿"] ``` - JSON Testsuite: /nst_json_testsuite2/test_parsing/y_string_nonCharacterInUTF-8_U+FFFF.json ```json ["￿"] ``` - JSON Testsuite: /nst_json_testsuite2/test_parsing/y_string_null_escape.json ```json ["\u0000"] ``` - JSON Testsuite: /nst_json_testsuite2/test_parsing/y_string_one-byte-utf-8.json ```json ["\u002c"] ``` - JSON Testsuite: /nst_json_testsuite2/test_parsing/y_string_pi.json ```json ["π"] ``` - JSON Testsuite: /nst_json_testsuite2/test_parsing/y_string_reservedCharacterInUTF-8_U+1BFFF.json ```json ["𛿿"] ``` - JSON Testsuite: /nst_json_testsuite2/test_parsing/y_string_simple_ascii.json ```json ["asd "] ``` - JSON Testsuite: /nst_json_testsuite2/test_parsing/y_string_space.json ```json " " ``` - JSON Testsuite: /nst_json_testsuite2/test_parsing/y_string_surrogates_U+1D11E_MUSICAL_SYMBOL_G_CLEF.json ```json ["\uD834\uDd1e"] ``` - JSON Testsuite: /nst_json_testsuite2/test_parsing/y_string_three-byte-utf-8.json ```json ["\u0821"] ``` - JSON Testsuite: /nst_json_testsuite2/test_parsing/y_string_two-byte-utf-8.json ```json ["\u0123"] ``` - JSON Testsuite: /nst_json_testsuite2/test_parsing/y_string_u+2028_line_sep.json ```json ["
 "] ``` - JSON Testsuite: /nst_json_testsuite2/test_parsing/y_string_u+2029_par_sep.json ```json ["
 "] ``` - JSON Testsuite: /nst_json_testsuite2/test_parsing/y_string_uEscape.json ```json ["\u0061\u30af\u30EA\u30b9"] ``` - JSON Testsuite: /nst_json_testsuite2/test_parsing/y_string_uescaped_newline.json ```json ["new\u000Aline"] ``` - JSON Testsuite: /nst_json_testsuite2/test_parsing/y_string_unescaped_char_delete.json ```json [""] ``` - JSON Testsuite: /nst_json_testsuite2/test_parsing/y_string_unicode.json ```json ["\uA66D"] ``` - JSON Testsuite: /nst_json_testsuite2/test_parsing/y_string_unicodeEscapedBackslash.json ```json ["\u005C"] ``` - JSON Testsuite: /nst_json_testsuite2/test_parsing/y_string_unicode_2.json ```json ["⍂㈴⍂"] ``` - JSON Testsuite: /nst_json_testsuite2/test_parsing/y_string_unicode_U+10FFFE_nonchar.json ```json ["\uDBFF\uDFFE"] ``` - JSON Testsuite: /nst_json_testsuite2/test_parsing/y_string_unicode_U+1FFFE_nonchar.json ```json ["\uD83F\uDFFE"] ``` - JSON Testsuite: /nst_json_testsuite2/test_parsing/y_string_unicode_U+200B_ZERO_WIDTH_SPACE.json ```json ["\u200B"] ``` - JSON Testsuite: /nst_json_testsuite2/test_parsing/y_string_unicode_U+2064_invisible_plus.json ```json ["\u2064"] ``` - JSON Testsuite: /nst_json_testsuite2/test_parsing/y_string_unicode_U+FDD0_nonchar.json ```json ["\uFDD0"] ``` - JSON Testsuite: /nst_json_testsuite2/test_parsing/y_string_unicode_U+FFFE_nonchar.json ```json ["\uFFFE"] ``` - JSON Testsuite: /nst_json_testsuite2/test_parsing/y_string_unicode_escaped_double_quote.json ```json ["\u0022"] ``` - JSON Testsuite: /nst_json_testsuite2/test_parsing/y_string_utf8.json ```json ["€𝄞"] ``` - JSON Testsuite: /nst_json_testsuite2/test_parsing/y_string_with_del_character.json ```json ["aa"] ``` - cpp-test: [nst's JSONTestSuite (2);test_parsing;y] (tests/src/unit-testsuites.cpp) ```cpp SECTION("y") { for (const auto* filename : { TEST_DATA_DIRECTORY "/nst_json_testsuite2/test_parsing/y_string_1_2_3_bytes_UTF-8_sequences.json", TEST_DATA_DIRECTORY "/nst_json_testsuite2/test_parsing/y_string_accepted_surrogate_pair.json", TEST_DATA_DIRECTORY "/nst_json_testsuite2/test_parsing/y_string_accepted_surrogate_pairs.json", TEST_DATA_DIRECTORY "/nst_json_testsuite2/test_parsing/y_string_allowed_escapes.json", TEST_DATA_DIRECTORY "/nst_json_testsuite2/test_parsing/y_string_backslash_and_u_escaped_zero.json", TEST_DATA_DIRECTORY "/nst_json_testsuite2/test_parsing/y_string_backslash_doublequotes.json", TEST_DATA_DIRECTORY "/nst_json_testsuite2/test_parsing/y_string_comments.json", TEST_DATA_DIRECTORY "/nst_json_testsuite2/test_parsing/y_string_double_escape_a.json", TEST_DATA_DIRECTORY "/nst_json_testsuite2/test_parsing/y_string_double_escape_n.json", TEST_DATA_DIRECTORY "/nst_json_testsuite2/test_parsing/y_string_escaped_control_character.json", TEST_DATA_DIRECTORY "/nst_json_testsuite2/test_parsing/y_string_escaped_noncharacter.json", TEST_DATA_DIRECTORY "/nst_json_testsuite2/test_parsing/y_string_in_array.json", TEST_DATA_DIRECTORY "/nst_json_testsuite2/test_parsing/y_string_in_array_with_leading_space.json", TEST_DATA_DIRECTORY "/nst_json_testsuite2/test_parsing/y_string_last_surrogates_1_and_2.json", TEST_DATA_DIRECTORY "/nst_json_testsuite2/test_parsing/y_string_nbsp_uescaped.json", TEST_DATA_DIRECTORY "/nst_json_testsuite2/test_parsing/y_string_nonCharacterInUTF-8_U+10FFFF.json", TEST_DATA_DIRECTORY "/nst_json_testsuite2/test_parsing/y_string_nonCharacterInUTF-8_U+FFFF.json", TEST_DATA_DIRECTORY "/nst_json_testsuite2/test_parsing/y_string_null_escape.json", TEST_DATA_DIRECTORY "/nst_json_testsuite2/test_parsing/y_string_one-byte-utf-8.json", TEST_DATA_DIRECTORY "/nst_json_testsuite2/test_parsing/y_string_pi.json", TEST_DATA_DIRECTORY "/nst_json_testsuite2/test_parsing/y_string_reservedCharacterInUTF-8_U+1BFFF.json", TEST_DATA_DIRECTORY "/nst_json_testsuite2/test_parsing/y_string_simple_ascii.json", TEST_DATA_DIRECTORY "/nst_json_testsuite2/test_parsing/y_string_space.json", TEST_DATA_DIRECTORY "/nst_json_testsuite2/test_parsing/y_string_surrogates_U+1D11E_MUSICAL_SYMBOL_G_CLEF.json", TEST_DATA_DIRECTORY "/nst_json_testsuite2/test_parsing/y_string_three-byte-utf-8.json", TEST_DATA_DIRECTORY "/nst_json_testsuite2/test_parsing/y_string_two-byte-utf-8.json", TEST_DATA_DIRECTORY "/nst_json_testsuite2/test_parsing/y_string_u+2028_line_sep.json", TEST_DATA_DIRECTORY "/nst_json_testsuite2/test_parsing/y_string_u+2029_par_sep.json", TEST_DATA_DIRECTORY "/nst_json_testsuite2/test_parsing/y_string_uEscape.json", TEST_DATA_DIRECTORY "/nst_json_testsuite2/test_parsing/y_string_uescaped_newline.json", TEST_DATA_DIRECTORY "/nst_json_testsuite2/test_parsing/y_string_unescaped_char_delete.json", TEST_DATA_DIRECTORY "/nst_json_testsuite2/test_parsing/y_string_unicode.json", TEST_DATA_DIRECTORY "/nst_json_testsuite2/test_parsing/y_string_unicodeEscapedBackslash.json", TEST_DATA_DIRECTORY "/nst_json_testsuite2/test_parsing/y_string_unicode_2.json", TEST_DATA_DIRECTORY "/nst_json_testsuite2/test_parsing/y_string_unicode_U+10FFFE_nonchar.json", TEST_DATA_DIRECTORY "/nst_json_testsuite2/test_parsing/y_string_unicode_U+1FFFE_nonchar.json", TEST_DATA_DIRECTORY "/nst_json_testsuite2/test_parsing/y_string_unicode_U+200B_ZERO_WIDTH_SPACE.json", TEST_DATA_DIRECTORY "/nst_json_testsuite2/test_parsing/y_string_unicode_U+2064_invisible_plus.json", TEST_DATA_DIRECTORY "/nst_json_testsuite2/test_parsing/y_string_unicode_U+FDD0_nonchar.json", TEST_DATA_DIRECTORY "/nst_json_testsuite2/test_parsing/y_string_unicode_U+FFFE_nonchar.json", TEST_DATA_DIRECTORY "/nst_json_testsuite2/test_parsing/y_string_unicode_escaped_double_quote.json", TEST_DATA_DIRECTORY "/nst_json_testsuite2/test_parsing/y_string_utf8.json", TEST_DATA_DIRECTORY "/nst_json_testsuite2/test_parsing/y_string_with_del_character.json", } ) { CAPTURE(filename) std::ifstream f(filename); json _; CHECK_NOTHROW(_ = json::parse(f)); std::ifstream f2(filename); CHECK(json::accept(f2)); } } // Note: Other test data lines have been filtered out for conciseness. ``` **Fallacies:** _None_ **Graph:** _No Historic Data Found_ --- ### NPF-04 The service parses literal names "true", "false" and "null" according to RFC8259. **Supported Requests:** - [PJD-03](PJD.md#pjd-03) **Supporting Items:** - [NPF-04.1](NPF.md#npf-04.1) - [NPF-04.2](NPF.md#npf-04.2) - [NPF-04.3](NPF.md#npf-04.3) - [NPF-04.4](NPF.md#npf-04.4) **References:** - `function: [lexer::scan_literal] (include/nlohmann/detail/input/lexer.hpp)` - Description: function to scan a literal candidate, compare it to its expected value and return the corresponding C++ literal ```cpp token_type scan_literal(const char_type* literal_text, const std::size_t length, token_type return_type) { JSON_ASSERT(char_traits<char_type>::to_char_type(current) == literal_text[0]); for (std::size_t i = 1; i < length; ++i) { if (JSON_HEDLEY_UNLIKELY(char_traits<char_type>::to_char_type(get()) != literal_text[i])) { error_message = "invalid literal"; return token_type::parse_error; } } return return_type; } ``` **Fallacies:** _None_ **Graph:** _No Historic Data Found_ --- ### NPF-04.1 The service ignores leading and trailing whitespace. **Supported Requests:** - [NPF-04](NPF.md#npf-04) **Supporting Items:** _None_ **References:** - `cpp-test: [parse;whitespace] (TSF/tests/unit-literals.cpp)` ```cpp SECTION("whitespace") { CHECK(json::parse(" false ")==json::parse("false")); CHECK(json::parse(" false\t")==json::parse("false")); CHECK(json::parse(" false\n")==json::parse("false")); CHECK(json::parse(" false\u000d")==json::parse("false")); CHECK(json::parse("\tfalse ")==json::parse("false")); CHECK(json::parse("\tfalse\t")==json::parse("false")); CHECK(json::parse("\tfalse\n")==json::parse("false")); CHECK(json::parse("\tfalse\u000d")==json::parse("false")); CHECK(json::parse("\nfalse ")==json::parse("false")); CHECK(json::parse("\nfalse\t")==json::parse("false")); CHECK(json::parse("\nfalse\n")==json::parse("false")); CHECK(json::parse("\nfalse\u000d")==json::parse("false")); CHECK(json::parse("\u000dfalse ")==json::parse("false")); CHECK(json::parse("\u000dfalse\t")==json::parse("false")); CHECK(json::parse("\u000dfalse\n")==json::parse("false")); CHECK(json::parse("\u000dfalse\u000d")==json::parse("false")); CHECK(json::parse(" null ")==json::parse("null")); CHECK(json::parse(" null\t")==json::parse("null")); CHECK(json::parse(" null\n")==json::parse("null")); CHECK(json::parse(" null\u000d")==json::parse("null")); CHECK(json::parse("\tnull ")==json::parse("null")); CHECK(json::parse("\tnull\t")==json::parse("null")); CHECK(json::parse("\tnull\n")==json::parse("null")); CHECK(json::parse("\tnull\u000d")==json::parse("null")); CHECK(json::parse("\nnull ")==json::parse("null")); CHECK(json::parse("\nnull\t")==json::parse("null")); CHECK(json::parse("\nnull\n")==json::parse("null")); CHECK(json::parse("\nnull\u000d")==json::parse("null")); CHECK(json::parse("\u000dnull ")==json::parse("null")); CHECK(json::parse("\u000dnull\t")==json::parse("null")); CHECK(json::parse("\u000dnull\n")==json::parse("null")); CHECK(json::parse("\u000dnull\u000d")==json::parse("null")); CHECK(json::parse(" true ")==json::parse("true")); CHECK(json::parse(" true\t")==json::parse("true")); CHECK(json::parse(" true\n")==json::parse("true")); CHECK(json::parse(" true\u000d")==json::parse("true")); CHECK(json::parse("\ttrue ")==json::parse("true")); CHECK(json::parse("\ttrue\t")==json::parse("true")); CHECK(json::parse("\ttrue\n")==json::parse("true")); CHECK(json::parse("\ttrue\u000d")==json::parse("true")); CHECK(json::parse("\ntrue ")==json::parse("true")); CHECK(json::parse("\ntrue\t")==json::parse("true")); CHECK(json::parse("\ntrue\n")==json::parse("true")); CHECK(json::parse("\ntrue\u000d")==json::parse("true")); CHECK(json::parse("\u000dtrue ")==json::parse("true")); CHECK(json::parse("\u000dtrue\t")==json::parse("true")); CHECK(json::parse("\u000dtrue\n")==json::parse("true")); CHECK(json::parse("\u000dtrue\u000d")==json::parse("true")); } ``` - `function: [lexer::skip_whitespace] (include/nlohmann/detail/input/lexer.hpp)` - Description: function, which skips admissible whitespace during reading ```cpp void skip_whitespace() { do { get(); } while (current == ' ' || current == '\t' || current == '\n' || current == '\r'); } ``` **Fallacies:** _None_ **Graph:** _No Historic Data Found_ --- ### NPF-04.2 The service parses the literal name true. **Supported Requests:** - [NPF-04](NPF.md#npf-04) **Supporting Items:** _None_ **References:** - `cpp-test: [parser class - core;parse;true] (TSF/tests/unit-class_parser_core.cpp)` ```cpp SECTION("true") { CHECK(parser_helper("true") == json(true)); } ``` **Fallacies:** _None_ **Graph:** _No Historic Data Found_ --- ### NPF-04.3 The service parses the literal name false. **Supported Requests:** - [NPF-04](NPF.md#npf-04) **Supporting Items:** _None_ **References:** - `cpp-test: [parser class - core;parse;false] (TSF/tests/unit-class_parser_core.cpp)` ```cpp SECTION("false") { CHECK(parser_helper("false") == json(false)); } ``` **Fallacies:** _None_ **Graph:** _No Historic Data Found_ --- ### NPF-04.4 The service parses the literal name null. **Supported Requests:** - [NPF-04](NPF.md#npf-04) **Supporting Items:** _None_ **References:** - `cpp-test: [parser class - core;parse;null] (TSF/tests/unit-class_parser_core.cpp)` ```cpp SECTION("null") { CHECK(parser_helper("null") == json(nullptr)); } ``` **Fallacies:** _None_ **Graph:** _No Historic Data Found_ --- ### NPF-05 The service parses arrays according to RFC8259. **Supported Requests:** - [PJD-03](PJD.md#pjd-03) **Supporting Items:** - [NPF-05.1](NPF.md#npf-05.1) - [NPF-05.2](NPF.md#npf-05.2) - [NPF-05.3](NPF.md#npf-05.3) **References:** _None_ **Fallacies:** _None_ **Graph:** _No Historic Data Found_ --- ### NPF-05.1 The service ignores leading and trailing whitespace for each value. **Supported Requests:** - [NPF-05](NPF.md#npf-05) **Supporting Items:** _None_ **References:** - `cpp-test: [parser class - core;parse;array;empty array] (TSF/tests/unit-class_parser_core.cpp)` ```cpp SECTION("empty array") { CHECK(parser_helper("[]") == json(json::value_t::array)); CHECK(parser_helper("[ ]") == json(json::value_t::array)); } ``` - `cpp-test: [parse;whitespace] (TSF/tests/unit-arrays.cpp)` ```cpp SECTION("whitespace") { json j = json::parse(R"(["1","2","test","foo","bar"])"); CHECK(parser_helper("[ \"1\" , \"2\" , \"test\" , \"foo\" , \"bar\" ]")==j); CHECK(parser_helper("[ \"1\"\t, \"2\"\t, \"test\"\t, \"foo\"\t, \"bar\"\t]")==j); CHECK(parser_helper("[ \"1\"\n, \"2\"\n, \"test\"\n, \"foo\"\n, \"bar\"\n]")==j); CHECK(parser_helper("[ \"1\"\u000d, \"2\"\u000d, \"test\"\u000d, \"foo\"\u000d, \"bar\"\u000d]")==j); CHECK(parser_helper("[\t\"1\" ,\t\"2\" ,\t\"test\" ,\t\"foo\" ,\t\"bar\" ]")==j); CHECK(parser_helper("[\t\"1\"\t,\t\"2\"\t,\t\"test\"\t,\t\"foo\"\t,\t\"bar\"\t]")==j); CHECK(parser_helper("[\t\"1\"\n,\t\"2\"\n,\t\"test\"\n,\t\"foo\"\n,\t\"bar\"\n]")==j); CHECK(parser_helper("[\t\"1\"\u000d,\t\"2\"\u000d,\t\"test\"\u000d,\t\"foo\"\u000d,\t\"bar\"\u000d]")==j); CHECK(parser_helper("[\n\"1\" ,\n\"2\" ,\n\"test\" ,\n\"foo\" ,\n\"bar\" ]")==j); CHECK(parser_helper("[\n\"1\"\t,\n\"2\"\t,\n\"test\"\t,\n\"foo\"\t,\n\"bar\"\t]")==j); CHECK(parser_helper("[\n\"1\"\n,\n\"2\"\n,\n\"test\"\n,\n\"foo\"\n,\n\"bar\"\n]")==j); CHECK(parser_helper("[\n\"1\"\u000d,\n\"2\"\u000d,\n\"test\"\u000d,\n\"foo\"\u000d,\n\"bar\"\u000d]")==j); CHECK(parser_helper("[\u000d\"1\" ,\u000d\"2\" ,\u000d\"test\" ,\u000d\"foo\" ,\u000d\"bar\" ]")==j); CHECK(parser_helper("[\u000d\"1\"\t,\u000d\"2\"\t,\u000d\"test\"\t,\u000d\"foo\"\t,\u000d\"bar\"\t]")==j); CHECK(parser_helper("[\u000d\"1\"\n,\u000d\"2\"\n,\u000d\"test\"\n,\u000d\"foo\"\n,\u000d\"bar\"\n]")==j); CHECK(parser_helper("[\u000d\"1\"\u000d,\u000d\"2\"\u000d,\u000d\"test\"\u000d,\u000d\"foo\"\u000d,\u000d\"bar\"\u000d]")==j); } ``` - `function: [lexer::skip_whitespace] (include/nlohmann/detail/input/lexer.hpp)` - Description: function, which skips admissible whitespace during reading ```cpp void skip_whitespace() { do { get(); } while (current == ' ' || current == '\t' || current == '\n' || current == '\r'); } ``` **Fallacies:** _None_ **Graph:** _No Historic Data Found_ --- ### NPF-05.2 The service parses empty arrays. **Supported Requests:** - [NPF-05](NPF.md#npf-05) **Supporting Items:** _None_ **References:** - `cpp-testsuite: [/nst_json_testsuite2/test_parsing/y_array_empty.json]` - Description: Tests whether the empty array is parsed without exception. - JSON Testsuite: /nst_json_testsuite2/test_parsing/y_array_empty.json ```json [] ``` - cpp-test: [nst's JSONTestSuite (2);test_parsing;y] (tests/src/unit-testsuites.cpp) ```cpp SECTION("y") { for (const auto* filename : { TEST_DATA_DIRECTORY "/nst_json_testsuite2/test_parsing/y_array_empty.json", } ) { CAPTURE(filename) std::ifstream f(filename); json _; CHECK_NOTHROW(_ = json::parse(f)); std::ifstream f2(filename); CHECK(json::accept(f2)); } } // Note: Other test data lines have been filtered out for conciseness. ``` - `cpp-test: [parser class - core;parse;array;empty array] (TSF/tests/unit-class_parser_core.cpp)` ```cpp SECTION("empty array") { CHECK(parser_helper("[]") == json(json::value_t::array)); CHECK(parser_helper("[ ]") == json(json::value_t::array)); } ``` **Fallacies:** _None_ **Graph:** _No Historic Data Found_ --- ### NPF-05.3 The service parses non-empty arrays. **Supported Requests:** - [NPF-05](NPF.md#npf-05) **Supporting Items:** _None_ **References:** - `cpp-test: [parser class - core;parse;array;nonempty array] (TSF/tests/unit-class_parser_core.cpp)` ```cpp SECTION("nonempty array") { CHECK(parser_helper("[true, false, null]") == json({true, false, nullptr})); } ``` - `cpp-testsuite: [/nst_json_testsuite2/test_parsing/y_array_arraysWithSpaces.json, /nst_json_testsuite2/test_parsing/y_array_empty-string.json, /nst_json_testsuite2/test_parsing/y_array_ending_with_newline.json, /nst_json_testsuite2/test_parsing/y_array_false.json, /nst_json_testsuite2/test_parsing/y_array_heterogeneous.json, /nst_json_testsuite2/test_parsing/y_array_null.json, /nst_json_testsuite2/test_parsing/y_array_with_1_and_newline.json, /nst_json_testsuite2/test_parsing/y_array_with_leading_space.json, /nst_json_testsuite2/test_parsing/y_array_with_several_null.json, /nst_json_testsuite2/test_parsing/y_array_with_trailing_space.json]` - Description: Tests whether several non-empty arrays are parsed without exception - JSON Testsuite: /nst_json_testsuite2/test_parsing/y_array_arraysWithSpaces.json ```json [[] ] ``` - JSON Testsuite: /nst_json_testsuite2/test_parsing/y_array_empty-string.json ```json [""] ``` - JSON Testsuite: /nst_json_testsuite2/test_parsing/y_array_ending_with_newline.json ```json ["a"] ``` - JSON Testsuite: /nst_json_testsuite2/test_parsing/y_array_false.json ```json [false] ``` - JSON Testsuite: /nst_json_testsuite2/test_parsing/y_array_heterogeneous.json ```json [null, 1, "1", {}] ``` - JSON Testsuite: /nst_json_testsuite2/test_parsing/y_array_null.json ```json [null] ``` - JSON Testsuite: /nst_json_testsuite2/test_parsing/y_array_with_1_and_newline.json ```json [1 ] ``` - JSON Testsuite: /nst_json_testsuite2/test_parsing/y_array_with_leading_space.json ```json [1] ``` - JSON Testsuite: /nst_json_testsuite2/test_parsing/y_array_with_several_null.json ```json [1,null,null,null,2] ``` - JSON Testsuite: /nst_json_testsuite2/test_parsing/y_array_with_trailing_space.json ```json [2] ``` - cpp-test: [nst's JSONTestSuite (2);test_parsing;y] (tests/src/unit-testsuites.cpp) ```cpp SECTION("y") { for (const auto* filename : { TEST_DATA_DIRECTORY "/nst_json_testsuite2/test_parsing/y_array_arraysWithSpaces.json", TEST_DATA_DIRECTORY "/nst_json_testsuite2/test_parsing/y_array_empty-string.json", TEST_DATA_DIRECTORY "/nst_json_testsuite2/test_parsing/y_array_ending_with_newline.json", TEST_DATA_DIRECTORY "/nst_json_testsuite2/test_parsing/y_array_false.json", TEST_DATA_DIRECTORY "/nst_json_testsuite2/test_parsing/y_array_heterogeneous.json", TEST_DATA_DIRECTORY "/nst_json_testsuite2/test_parsing/y_array_null.json", TEST_DATA_DIRECTORY "/nst_json_testsuite2/test_parsing/y_array_with_1_and_newline.json", TEST_DATA_DIRECTORY "/nst_json_testsuite2/test_parsing/y_array_with_leading_space.json", TEST_DATA_DIRECTORY "/nst_json_testsuite2/test_parsing/y_array_with_several_null.json", TEST_DATA_DIRECTORY "/nst_json_testsuite2/test_parsing/y_array_with_trailing_space.json", } ) { CAPTURE(filename) std::ifstream f(filename); json _; CHECK_NOTHROW(_ = json::parse(f)); std::ifstream f2(filename); CHECK(json::accept(f2)); } } // Note: Other test data lines have been filtered out for conciseness. ``` **Fallacies:** _None_ **Graph:** _No Historic Data Found_ --- ### NPF-06 The service parses objects according to RFC8259. **Supported Requests:** - [PJD-03](PJD.md#pjd-03) **Supporting Items:** - [NPF-06.1](NPF.md#npf-06.1) - [NPF-06.2](NPF.md#npf-06.2) - [NPF-06.3](NPF.md#npf-06.3) - [NPF-06.4](NPF.md#npf-06.4) **References:** _None_ **Fallacies:** _None_ **Graph:** _No Historic Data Found_ --- ### NPF-06.1 The service ignores leading and trailing whitespace for name and value of each member. **Supported Requests:** - [NPF-06](NPF.md#npf-06) **Supporting Items:** _None_ **References:** - `cpp-test: [parser class - core;parse;object;empty object] (TSF/tests/unit-class_parser_core.cpp)` ```cpp SECTION("empty object") { CHECK(parser_helper("{}") == json(json::value_t::object)); CHECK(parser_helper("{ }") == json(json::value_t::object)); } ``` - `cpp-test: [regression tests 1;example from #529] (tests/src/unit-regression1.cpp)` ```cpp SECTION("example from #529") { std::stringstream ss; ss << "{\n \"one\" : 1,\n \"two\" : 2\n}\n{\n \"three\" : 3\n}"; json j; CHECK_NOTHROW(ss >> j); CHECK(j == json({{"one", 1}, {"two", 2}})); CHECK_NOTHROW(ss >> j); CHECK(j == json({{"three", 3}})); CHECK_THROWS_WITH_AS(ss >> j, "[json.exception.parse_error.101] parse error at line 1, column 1: attempting to parse an empty input; check that your input string or stream contains the expected JSON", json::parse_error&); } ``` - `function: [lexer::skip_whitespace] (include/nlohmann/detail/input/lexer.hpp)` - Description: function, which skips admissible whitespace during reading ```cpp void skip_whitespace() { do { get(); } while (current == ' ' || current == '\t' || current == '\n' || current == '\r'); } ``` **Fallacies:** _None_ **Graph:** _No Historic Data Found_ --- ### NPF-06.2 The service parses duplicate names without error and reports the last member with that name only. **Supported Requests:** - [NPF-06](NPF.md#npf-06) **Supporting Items:** _None_ **References:** - `cpp-testsuite: [/nst_json_testsuite2/test_parsing/y_object_duplicated_key.json, /nst_json_testsuite2/test_parsing/y_object_duplicated_key_and_value.json]` - JSON Testsuite: /nst_json_testsuite2/test_parsing/y_object_duplicated_key.json ```json {"a":"b","a":"c"} ``` - JSON Testsuite: /nst_json_testsuite2/test_parsing/y_object_duplicated_key_and_value.json ```json {"a":"b","a":"b"} ``` - cpp-test: [nst's JSONTestSuite (2);test_parsing;y] (tests/src/unit-testsuites.cpp) ```cpp SECTION("y") { for (const auto* filename : { TEST_DATA_DIRECTORY "/nst_json_testsuite2/test_parsing/y_object_duplicated_key.json", TEST_DATA_DIRECTORY "/nst_json_testsuite2/test_parsing/y_object_duplicated_key_and_value.json", } ) { CAPTURE(filename) std::ifstream f(filename); json _; CHECK_NOTHROW(_ = json::parse(f)); std::ifstream f2(filename); CHECK(json::accept(f2)); } } // Note: Other test data lines have been filtered out for conciseness. ``` **Fallacies:** _None_ **Graph:** _No Historic Data Found_ --- ### NPF-06.3 The service parses empty objects. **Supported Requests:** - [NPF-06](NPF.md#npf-06) **Supporting Items:** _None_ **References:** - `cpp-test: [parser class - core;parse;object;empty object] (TSF/tests/unit-class_parser_core.cpp)` ```cpp SECTION("empty object") { CHECK(parser_helper("{}") == json(json::value_t::object)); CHECK(parser_helper("{ }") == json(json::value_t::object)); } ``` **Fallacies:** _None_ **Graph:** _No Historic Data Found_ --- ### NPF-06.4 The service parses non-empty objects. **Supported Requests:** - [NPF-06](NPF.md#npf-06) **Supporting Items:** _None_ **References:** - `cpp-test: [parser class - core;parse;object;nonempty object] (TSF/tests/unit-class_parser_core.cpp)` ```cpp SECTION("nonempty object") { CHECK(parser_helper("{\"\": true, \"one\": 1, \"two\": null}") == json({{"", true}, {"one", 1}, {"two", nullptr}})); } ``` **Fallacies:** _None_ **Graph:** _No Historic Data Found_ --- ### NPF-07 The service parses well-formed UTF-8 encoded data only. **Supported Requests:** - [PJD-03](PJD.md#pjd-03) **Supporting Items:** - [NPF-07.1](NPF.md#npf-07.1) - [NPF-07.2](NPF.md#npf-07.2) **References:** _None_ **Fallacies:** _None_ **Graph:** _No Historic Data Found_ --- ### NPF-07.1 The service parses UTF-8 encoded data. **Supported Requests:** - [NPF-07](NPF.md#npf-07) **Supporting Items:** _None_ **References:** - `cpp-test: [Unicode (2/5);RFC 3629;UTF8-1 (x00-x7F);well-formed] (tests/src/unit-unicode2.cpp)` ```cpp SECTION("well-formed") { for (int byte1 = 0x00; byte1 <= 0x7F; ++byte1) { // unescaped control characters are parse errors in JSON if (0x00 <= byte1 && 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); check_utf8dump(true, byte1); } } ``` - `cpp-test: [Unicode (2/5);RFC 3629;UTF8-2 (xC2-xDF UTF8-tail);well-formed] (tests/src/unit-unicode2.cpp)` ```cpp SECTION("well-formed") { for (int byte1 = 0xC2; byte1 <= 0xDF; ++byte1) { for (int byte2 = 0x80; byte2 <= 0xBF; ++byte2) { check_utf8string(true, byte1, byte2); check_utf8dump(true, byte1, byte2); } } } ``` - `cpp-test: [Unicode (2/5);RFC 3629;UTF8-3 (xE0 xA0-BF UTF8-tail);well-formed] (tests/src/unit-unicode2.cpp)` ```cpp 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_utf8dump(true, byte1, byte2, byte3); } } } } ``` - `cpp-test: [Unicode (2/5);RFC 3629;UTF8-3 (xE1-xEC UTF8-tail UTF8-tail);well-formed] (tests/src/unit-unicode2.cpp)` ```cpp 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); check_utf8dump(true, byte1, byte2, byte3); } } } } ``` - `cpp-test: [Unicode (2/5);RFC 3629;UTF8-3 (xED x80-9F UTF8-tail);well-formed] (tests/src/unit-unicode2.cpp)` ```cpp SECTION("well-formed") { for (int byte1 = 0xED; byte1 <= 0xED; ++byte1) { for (int byte2 = 0x80; byte2 <= 0x9F; ++byte2) { for (int byte3 = 0x80; byte3 <= 0xBF; ++byte3) { check_utf8string(true, byte1, byte2, byte3); check_utf8dump(true, byte1, byte2, byte3); } } } } ``` - `cpp-test: [Unicode (2/5);RFC 3629;UTF8-3 (xEE-xEF UTF8-tail UTF8-tail);well-formed] (tests/src/unit-unicode2.cpp)` ```cpp SECTION("well-formed") { for (int byte1 = 0xEE; byte1 <= 0xEF; ++byte1) { for (int byte2 = 0x80; byte2 <= 0xBF; ++byte2) { for (int byte3 = 0x80; byte3 <= 0xBF; ++byte3) { check_utf8string(true, byte1, byte2, byte3); check_utf8dump(true, byte1, byte2, byte3); } } } } ``` - `cpp-test: [Unicode (3/5);RFC 3629;UTF8-4 (xF0 x90-BF UTF8-tail UTF8-tail);well-formed] (tests/src/unit-unicode3.cpp)` ```cpp 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) { check_utf8string(true, byte1, byte2, byte3, byte4); check_utf8dump(true, byte1, byte2, byte3, byte4); } } } } } ``` - `cpp-test: [Unicode (4/5);RFC 3629;UTF8-4 (xF1-F3 UTF8-tail UTF8-tail UTF8-tail);well-formed] (tests/src/unit-unicode4.cpp)` ```cpp 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); check_utf8dump(true, byte1, byte2, byte3, byte4); } } } } } ``` - `cpp-test: [Unicode (5/5);RFC 3629;UTF8-4 (xF4 x80-8F UTF8-tail UTF8-tail);well-formed] (tests/src/unit-unicode5.cpp)` ```cpp SECTION("well-formed") { for (int byte1 = 0xF4; byte1 <= 0xF4; ++byte1) { for (int byte2 = 0x80; byte2 <= 0x8F; ++byte2) { for (int byte3 = 0x80; byte3 <= 0xBF; ++byte3) { for (int byte4 = 0x80; byte4 <= 0xBF; ++byte4) { check_utf8string(true, byte1, byte2, byte3, byte4); check_utf8dump(true, byte1, byte2, byte3, byte4); } } } } } ``` **Fallacies:** _None_ **Graph:** _No Historic Data Found_ --- ### NPF-07.2 The service throws an exception on ill-formed UTF-8 data. **Supported Requests:** - [JLS-24](JLS.md#jls-24) - [NPF-07](NPF.md#npf-07) **Supporting Items:** _None_ **References:** - `cpp-test: [Unicode (2/5);RFC 3629;ill-formed first byte] (tests/src/unit-unicode2.cpp)` ```cpp SECTION("ill-formed first byte") { for (int byte1 = 0x80; byte1 <= 0xC1; ++byte1) { check_utf8string(false, byte1); check_utf8dump(false, byte1); } for (int byte1 = 0xF5; byte1 <= 0xFF; ++byte1) { check_utf8string(false, byte1); check_utf8dump(false, byte1); } } ``` - `cpp-test: [Unicode (2/5);RFC 3629;UTF8-2 (xC2-xDF UTF8-tail);ill-formed: missing second byte] (tests/src/unit-unicode2.cpp)` ```cpp SECTION("ill-formed: missing second byte") { for (int byte1 = 0xC2; byte1 <= 0xDF; ++byte1) { check_utf8string(false, byte1); check_utf8dump(false, byte1); } } ``` - `cpp-test: [Unicode (2/5);RFC 3629;UTF8-2 (xC2-xDF UTF8-tail);ill-formed: wrong second byte] (tests/src/unit-unicode2.cpp)` ```cpp 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 && byte2 <= 0xBF) { continue; } check_utf8string(false, byte1, byte2); check_utf8dump(false, byte1, byte2); } } } ``` - `cpp-test: [Unicode (2/5);RFC 3629;UTF8-3 (xE0 xA0-BF UTF8-tail);ill-formed: missing second byte] (tests/src/unit-unicode2.cpp)` ```cpp SECTION("ill-formed: missing second byte") { for (int byte1 = 0xE0; byte1 <= 0xE0; ++byte1) { check_utf8string(false, byte1); check_utf8dump(false, byte1); } } ``` - `cpp-test: [Unicode (2/5);RFC 3629;UTF8-3 (xE0 xA0-BF UTF8-tail);ill-formed: missing third byte] (tests/src/unit-unicode2.cpp)` ```cpp 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); check_utf8dump(false, byte1, byte2); } } } ``` - `cpp-test: [Unicode (2/5);RFC 3629;UTF8-3 (xE0 xA0-BF UTF8-tail);ill-formed: wrong second byte] (tests/src/unit-unicode2.cpp)` ```cpp 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 && byte2 <= 0xBF) { continue; } for (int byte3 = 0x80; byte3 <= 0xBF; ++byte3) { check_utf8string(false, byte1, byte2, byte3); check_utf8dump(false, byte1, byte2, byte3); } } } } ``` - `cpp-test: [Unicode (2/5);RFC 3629;UTF8-3 (xE0 xA0-BF UTF8-tail);ill-formed: wrong third byte] (tests/src/unit-unicode2.cpp)` ```cpp 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 && byte3 <= 0xBF) { continue; } check_utf8string(false, byte1, byte2, byte3); check_utf8dump(false, byte1, byte2, byte3); } } } } ``` - `cpp-test: [Unicode (2/5);RFC 3629;UTF8-3 (xE1-xEC UTF8-tail UTF8-tail);ill-formed: missing second byte] (tests/src/unit-unicode2.cpp)` ```cpp SECTION("ill-formed: missing second byte") { for (int byte1 = 0xE1; byte1 <= 0xEC; ++byte1) { check_utf8string(false, byte1); check_utf8dump(false, byte1); } } ``` - `cpp-test: [Unicode (2/5);RFC 3629;UTF8-3 (xE1-xEC UTF8-tail UTF8-tail);ill-formed: missing third byte] (tests/src/unit-unicode2.cpp)` ```cpp SECTION("ill-formed: missing third byte") { for (int byte1 = 0xE1; byte1 <= 0xEC; ++byte1) { for (int byte2 = 0x80; byte2 <= 0xBF; ++byte2) { check_utf8string(false, byte1, byte2); check_utf8dump(false, byte1, byte2); } } } ``` - `cpp-test: [Unicode (2/5);RFC 3629;UTF8-3 (xE1-xEC UTF8-tail UTF8-tail);ill-formed: wrong second byte] (tests/src/unit-unicode2.cpp)` ```cpp 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 && byte2 <= 0xBF) { continue; } for (int byte3 = 0x80; byte3 <= 0xBF; ++byte3) { check_utf8string(false, byte1, byte2, byte3); check_utf8dump(false, byte1, byte2, byte3); } } } } ``` - `cpp-test: [Unicode (2/5);RFC 3629;UTF8-3 (xE1-xEC UTF8-tail UTF8-tail);ill-formed: wrong third byte] (tests/src/unit-unicode2.cpp)` ```cpp SECTION("ill-formed: wrong third byte") { for (int byte1 = 0xE1; byte1 <= 0xEC; ++byte1) { for (int byte2 = 0x80; byte2 <= 0xBF; ++byte2) { for (int byte3 = 0x00; byte3 <= 0xFF; ++byte3) { // skip correct third byte if (0x80 <= byte3 && byte3 <= 0xBF) { continue; } check_utf8string(false, byte1, byte2, byte3); check_utf8dump(false, byte1, byte2, byte3); } } } } ``` - `cpp-test: [Unicode (2/5);RFC 3629;UTF8-3 (xED x80-9F UTF8-tail);ill-formed: missing second byte] (tests/src/unit-unicode2.cpp)` ```cpp SECTION("ill-formed: missing second byte") { for (int byte1 = 0xED; byte1 <= 0xED; ++byte1) { check_utf8string(false, byte1); check_utf8dump(false, byte1); } } ``` - `cpp-test: [Unicode (2/5);RFC 3629;UTF8-3 (xED x80-9F UTF8-tail);ill-formed: missing third byte] (tests/src/unit-unicode2.cpp)` ```cpp SECTION("ill-formed: missing third byte") { for (int byte1 = 0xED; byte1 <= 0xED; ++byte1) { for (int byte2 = 0x80; byte2 <= 0x9F; ++byte2) { check_utf8string(false, byte1, byte2); check_utf8dump(false, byte1, byte2); } } } ``` - `cpp-test: [Unicode (2/5);RFC 3629;UTF8-3 (xED x80-9F UTF8-tail);ill-formed: wrong second byte] (tests/src/unit-unicode2.cpp)` ```cpp 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 && byte2 <= 0x9F) { continue; } for (int byte3 = 0x80; byte3 <= 0xBF; ++byte3) { check_utf8string(false, byte1, byte2, byte3); check_utf8dump(false, byte1, byte2, byte3); } } } } ``` - `cpp-test: [Unicode (2/5);RFC 3629;UTF8-3 (xED x80-9F UTF8-tail);ill-formed: wrong third byte] (tests/src/unit-unicode2.cpp)` ```cpp SECTION("ill-formed: wrong third byte") { for (int byte1 = 0xED; byte1 <= 0xED; ++byte1) { for (int byte2 = 0x80; byte2 <= 0x9F; ++byte2) { for (int byte3 = 0x00; byte3 <= 0xFF; ++byte3) { // skip correct third byte if (0x80 <= byte3 && byte3 <= 0xBF) { continue; } check_utf8string(false, byte1, byte2, byte3); check_utf8dump(false, byte1, byte2, byte3); } } } } ``` - `cpp-test: [Unicode (2/5);RFC 3629;UTF8-3 (xEE-xEF UTF8-tail UTF8-tail);ill-formed: missing second byte] (tests/src/unit-unicode2.cpp)` ```cpp SECTION("ill-formed: missing second byte") { for (int byte1 = 0xEE; byte1 <= 0xEF; ++byte1) { check_utf8string(false, byte1); check_utf8dump(false, byte1); } } ``` - `cpp-test: [Unicode (2/5);RFC 3629;UTF8-3 (xEE-xEF UTF8-tail UTF8-tail);ill-formed: missing third byte] (tests/src/unit-unicode2.cpp)` ```cpp SECTION("ill-formed: missing third byte") { for (int byte1 = 0xEE; byte1 <= 0xEF; ++byte1) { for (int byte2 = 0x80; byte2 <= 0xBF; ++byte2) { check_utf8string(false, byte1, byte2); check_utf8dump(false, byte1, byte2); } } } ``` - `cpp-test: [Unicode (2/5);RFC 3629;UTF8-3 (xEE-xEF UTF8-tail UTF8-tail);ill-formed: wrong second byte] (tests/src/unit-unicode2.cpp)` ```cpp 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 && byte2 <= 0xBF) { continue; } for (int byte3 = 0x80; byte3 <= 0xBF; ++byte3) { check_utf8string(false, byte1, byte2, byte3); check_utf8dump(false, byte1, byte2, byte3); } } } } ``` - `cpp-test: [Unicode (2/5);RFC 3629;UTF8-3 (xEE-xEF UTF8-tail UTF8-tail);ill-formed: wrong third byte] (tests/src/unit-unicode2.cpp)` ```cpp SECTION("ill-formed: wrong third byte") { for (int byte1 = 0xEE; byte1 <= 0xEF; ++byte1) { for (int byte2 = 0x80; byte2 <= 0xBF; ++byte2) { for (int byte3 = 0x00; byte3 <= 0xFF; ++byte3) { // skip correct third byte if (0x80 <= byte3 && byte3 <= 0xBF) { continue; } check_utf8string(false, byte1, byte2, byte3); check_utf8dump(false, byte1, byte2, byte3); } } } } ``` - `cpp-test: [Unicode (3/5);RFC 3629;UTF8-4 (xF0 x90-BF UTF8-tail UTF8-tail);ill-formed: missing second byte] (tests/src/unit-unicode3.cpp)` ```cpp SECTION("ill-formed: missing second byte") { for (int byte1 = 0xF0; byte1 <= 0xF0; ++byte1) { check_utf8string(false, byte1); check_utf8dump(false, byte1); } } ``` - `cpp-test: [Unicode (3/5);RFC 3629;UTF8-4 (xF0 x90-BF UTF8-tail UTF8-tail);ill-formed: missing third byte] (tests/src/unit-unicode3.cpp)` ```cpp SECTION("ill-formed: missing third byte") { for (int byte1 = 0xF0; byte1 <= 0xF0; ++byte1) { for (int byte2 = 0x90; byte2 <= 0xBF; ++byte2) { check_utf8string(false, byte1, byte2); check_utf8dump(false, byte1, byte2); } } } ``` - `cpp-test: [Unicode (3/5);RFC 3629;UTF8-4 (xF0 x90-BF UTF8-tail UTF8-tail);ill-formed: missing fourth byte] (tests/src/unit-unicode3.cpp)` ```cpp 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); check_utf8dump(false, byte1, byte2, byte3); } } } } ``` - `cpp-test: [Unicode (3/5);RFC 3629;UTF8-4 (xF0 x90-BF UTF8-tail UTF8-tail);ill-formed: wrong second byte] (tests/src/unit-unicode3.cpp)` ```cpp 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 && byte2 <= 0xBF) { continue; } for (int byte3 = 0x80; byte3 <= 0xBF; ++byte3) { for (int byte4 = 0x80; byte4 <= 0xBF; ++byte4) { check_utf8string(false, byte1, byte2, byte3, byte4); check_utf8dump(false, byte1, byte2, byte3, byte4); } } } } } ``` - `cpp-test: [Unicode (3/5);RFC 3629;UTF8-4 (xF0 x90-BF UTF8-tail UTF8-tail);ill-formed: wrong third byte] (tests/src/unit-unicode3.cpp)` ```cpp SECTION("ill-formed: wrong third byte") { for (int byte1 = 0xF0; byte1 <= 0xF0; ++byte1) { for (int byte2 = 0x90; byte2 <= 0xBF; ++byte2) { for (int byte3 = 0x00; byte3 <= 0xFF; ++byte3) { // skip correct third byte if (0x80 <= byte3 && byte3 <= 0xBF) { continue; } for (int byte4 = 0x80; byte4 <= 0xBF; ++byte4) { check_utf8string(false, byte1, byte2, byte3, byte4); check_utf8dump(false, byte1, byte2, byte3, byte4); } } } } } ``` - `cpp-test: [Unicode (3/5);RFC 3629;UTF8-4 (xF0 x90-BF UTF8-tail UTF8-tail);ill-formed: wrong fourth byte] (tests/src/unit-unicode3.cpp)` ```cpp 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 if (0x80 <= byte3 && byte3 <= 0xBF) { continue; } check_utf8string(false, byte1, byte2, byte3, byte4); check_utf8dump(false, byte1, byte2, byte3, byte4); } } } } } ``` - `cpp-test: [Unicode (4/5);RFC 3629;UTF8-4 (xF1-F3 UTF8-tail UTF8-tail UTF8-tail);ill-formed: missing second byte] (tests/src/unit-unicode4.cpp)` ```cpp SECTION("ill-formed: missing second byte") { for (int byte1 = 0xF1; byte1 <= 0xF3; ++byte1) { check_utf8string(false, byte1); check_utf8dump(false, byte1); } } ``` - `cpp-test: [Unicode (4/5);RFC 3629;UTF8-4 (xF1-F3 UTF8-tail UTF8-tail UTF8-tail);ill-formed: missing third byte] (tests/src/unit-unicode4.cpp)` ```cpp SECTION("ill-formed: missing third byte") { for (int byte1 = 0xF1; byte1 <= 0xF3; ++byte1) { for (int byte2 = 0x80; byte2 <= 0xBF; ++byte2) { check_utf8string(false, byte1, byte2); check_utf8dump(false, byte1, byte2); } } } ``` - `cpp-test: [Unicode (4/5);RFC 3629;UTF8-4 (xF1-F3 UTF8-tail UTF8-tail UTF8-tail);ill-formed: missing fourth byte] (tests/src/unit-unicode4.cpp)` ```cpp 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); check_utf8dump(false, byte1, byte2, byte3); } } } } ``` - `cpp-test: [Unicode (4/5);RFC 3629;UTF8-4 (xF1-F3 UTF8-tail UTF8-tail UTF8-tail);ill-formed: wrong second byte] (tests/src/unit-unicode4.cpp)` ```cpp 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 && byte2 <= 0xBF) { continue; } for (int byte3 = 0x80; byte3 <= 0xBF; ++byte3) { for (int byte4 = 0x80; byte4 <= 0xBF; ++byte4) { check_utf8string(false, byte1, byte2, byte3, byte4); check_utf8dump(false, byte1, byte2, byte3, byte4); } } } } } ``` - `cpp-test: [Unicode (4/5);RFC 3629;UTF8-4 (xF1-F3 UTF8-tail UTF8-tail UTF8-tail);ill-formed: wrong third byte] (tests/src/unit-unicode4.cpp)` ```cpp SECTION("ill-formed: wrong third byte") { for (int byte1 = 0xF1; byte1 <= 0xF3; ++byte1) { for (int byte2 = 0x80; byte2 <= 0xBF; ++byte2) { for (int byte3 = 0x00; byte3 <= 0xFF; ++byte3) { // skip correct third byte if (0x80 <= byte3 && byte3 <= 0xBF) { continue; } for (int byte4 = 0x80; byte4 <= 0xBF; ++byte4) { check_utf8string(false, byte1, byte2, byte3, byte4); check_utf8dump(false, byte1, byte2, byte3, byte4); } } } } } ``` - `cpp-test: [Unicode (4/5);RFC 3629;UTF8-4 (xF1-F3 UTF8-tail UTF8-tail UTF8-tail);ill-formed: wrong fourth byte] (tests/src/unit-unicode4.cpp)` ```cpp SECTION("ill-formed: wrong 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 byte4 = 0x00; byte4 <= 0xFF; ++byte4) { // skip correct fourth byte if (0x80 <= byte3 && byte3 <= 0xBF) { continue; } check_utf8string(false, byte1, byte2, byte3, byte4); check_utf8dump(false, byte1, byte2, byte3, byte4); } } } } } ``` - `cpp-test: [Unicode (5/5);RFC 3629;UTF8-4 (xF4 x80-8F UTF8-tail UTF8-tail);ill-formed: missing second byte] (tests/src/unit-unicode5.cpp)` ```cpp SECTION("ill-formed: missing second byte") { for (int byte1 = 0xF4; byte1 <= 0xF4; ++byte1) { check_utf8string(false, byte1); check_utf8dump(false, byte1); } } ``` - `cpp-test: [Unicode (5/5);RFC 3629;UTF8-4 (xF4 x80-8F UTF8-tail UTF8-tail);ill-formed: missing third byte] (tests/src/unit-unicode5.cpp)` ```cpp SECTION("ill-formed: missing third byte") { for (int byte1 = 0xF4; byte1 <= 0xF4; ++byte1) { for (int byte2 = 0x80; byte2 <= 0x8F; ++byte2) { check_utf8string(false, byte1, byte2); check_utf8dump(false, byte1, byte2); } } } ``` - `cpp-test: [Unicode (5/5);RFC 3629;UTF8-4 (xF4 x80-8F UTF8-tail UTF8-tail);ill-formed: missing fourth byte] (tests/src/unit-unicode5.cpp)` ```cpp 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); check_utf8dump(false, byte1, byte2, byte3); } } } } ``` - `cpp-test: [Unicode (5/5);RFC 3629;UTF8-4 (xF4 x80-8F UTF8-tail UTF8-tail);ill-formed: wrong second byte] (tests/src/unit-unicode5.cpp)` ```cpp 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 && byte2 <= 0x8F) { continue; } for (int byte3 = 0x80; byte3 <= 0xBF; ++byte3) { for (int byte4 = 0x80; byte4 <= 0xBF; ++byte4) { check_utf8string(false, byte1, byte2, byte3, byte4); check_utf8dump(false, byte1, byte2, byte3, byte4); } } } } } ``` - `cpp-test: [Unicode (5/5);RFC 3629;UTF8-4 (xF4 x80-8F UTF8-tail UTF8-tail);ill-formed: wrong third byte] (tests/src/unit-unicode5.cpp)` ```cpp SECTION("ill-formed: wrong third byte") { for (int byte1 = 0xF4; byte1 <= 0xF4; ++byte1) { for (int byte2 = 0x80; byte2 <= 0x8F; ++byte2) { for (int byte3 = 0x00; byte3 <= 0xFF; ++byte3) { // skip correct third byte if (0x80 <= byte3 && byte3 <= 0xBF) { continue; } for (int byte4 = 0x80; byte4 <= 0xBF; ++byte4) { check_utf8string(false, byte1, byte2, byte3, byte4); check_utf8dump(false, byte1, byte2, byte3, byte4); } } } } } ``` - `cpp-test: [Unicode (5/5);RFC 3629;UTF8-4 (xF4 x80-8F UTF8-tail UTF8-tail);ill-formed: wrong fourth byte] (tests/src/unit-unicode5.cpp)` ```cpp 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 && byte3 <= 0xBF) { continue; } check_utf8string(false, byte1, byte2, byte3, byte4); check_utf8dump(false, byte1, byte2, byte3, byte4); } } } } } ``` **Fallacies:** _None_ **Graph:** _No Historic Data Found_