1// __ _____ _____ _____ 2// __| | __| | | | JSON for Modern C++ (supporting code) 3// | | |__ | | | | | | version 3.11.2 4// |_____|_____|_____|_|___| https://github.com/nlohmann/json 5// 6// SPDX-FileCopyrightText: 2013-2022 Niels Lohmann <https://nlohmann.me> 7// SPDX-License-Identifier: MIT 8 9#include "doctest_compatibility.h" 10 11#define JSON_TESTS_PRIVATE 12#include <nlohmann/json.hpp> 13using nlohmann::json; 14#ifdef JSON_TEST_NO_GLOBAL_UDLS 15 using namespace nlohmann::literals; // NOLINT(google-build-using-namespace) 16#endif 17 18#include <valarray> 19 20namespace 21{ 22class SaxEventLogger 23{ 24 public: 25 bool null() 26 { 27 events.emplace_back("null()"); 28 return true; 29 } 30 31 bool boolean(bool val) 32 { 33 events.emplace_back(val ? "boolean(true)" : "boolean(false)"); 34 return true; 35 } 36 37 bool number_integer(json::number_integer_t val) 38 { 39 events.push_back("number_integer(" + std::to_string(val) + ")"); 40 return true; 41 } 42 43 bool number_unsigned(json::number_unsigned_t val) 44 { 45 events.push_back("number_unsigned(" + std::to_string(val) + ")"); 46 return true; 47 } 48 49 bool number_float(json::number_float_t /*unused*/, const std::string& s) 50 { 51 events.push_back("number_float(" + s + ")"); 52 return true; 53 } 54 55 bool string(std::string& val) 56 { 57 events.push_back("string(" + val + ")"); 58 return true; 59 } 60 61 bool binary(json::binary_t& val) 62 { 63 std::string binary_contents = "binary("; 64 std::string comma_space; 65 for (auto b : val) 66 { 67 binary_contents.append(comma_space); 68 binary_contents.append(std::to_string(static_cast<int>(b))); 69 comma_space = ", "; 70 } 71 binary_contents.append(")"); 72 events.push_back(binary_contents); 73 return true; 74 } 75 76 bool start_object(std::size_t elements) 77 { 78 if (elements == static_cast<std::size_t>(-1)) 79 { 80 events.emplace_back("start_object()"); 81 } 82 else 83 { 84 events.push_back("start_object(" + std::to_string(elements) + ")"); 85 } 86 return true; 87 } 88 89 bool key(std::string& val) 90 { 91 events.push_back("key(" + val + ")"); 92 return true; 93 } 94 95 bool end_object() 96 { 97 events.emplace_back("end_object()"); 98 return true; 99 } 100 101 bool start_array(std::size_t elements) 102 { 103 if (elements == static_cast<std::size_t>(-1)) 104 { 105 events.emplace_back("start_array()"); 106 } 107 else 108 { 109 events.push_back("start_array(" + std::to_string(elements) + ")"); 110 } 111 return true; 112 } 113 114 bool end_array() 115 { 116 events.emplace_back("end_array()"); 117 return true; 118 } 119 120 bool parse_error(std::size_t position, const std::string& /*unused*/, const json::exception& /*unused*/) 121 { 122 errored = true; 123 events.push_back("parse_error(" + std::to_string(position) + ")"); 124 return false; 125 } 126 127 std::vector<std::string> events {}; 128 bool errored = false; 129}; 130 131class SaxCountdown : public nlohmann::json::json_sax_t 132{ 133 public: 134 explicit SaxCountdown(const int count) : events_left(count) 135 {} 136 137 bool null() override 138 { 139 return events_left-- > 0; 140 } 141 142 bool boolean(bool /*val*/) override 143 { 144 return events_left-- > 0; 145 } 146 147 bool number_integer(json::number_integer_t /*val*/) override 148 { 149 return events_left-- > 0; 150 } 151 152 bool number_unsigned(json::number_unsigned_t /*val*/) override 153 { 154 return events_left-- > 0; 155 } 156 157 bool number_float(json::number_float_t /*val*/, const std::string& /*s*/) override 158 { 159 return events_left-- > 0; 160 } 161 162 bool string(std::string& /*val*/) override 163 { 164 return events_left-- > 0; 165 } 166 167 bool binary(json::binary_t& /*val*/) override 168 { 169 return events_left-- > 0; 170 } 171 172 bool start_object(std::size_t /*elements*/) override 173 { 174 return events_left-- > 0; 175 } 176 177 bool key(std::string& /*val*/) override 178 { 179 return events_left-- > 0; 180 } 181 182 bool end_object() override 183 { 184 return events_left-- > 0; 185 } 186 187 bool start_array(std::size_t /*elements*/) override 188 { 189 return events_left-- > 0; 190 } 191 192 bool end_array() override 193 { 194 return events_left-- > 0; 195 } 196 197 bool parse_error(std::size_t /*position*/, const std::string& /*last_token*/, const json::exception& /*ex*/) override 198 { 199 return false; 200 } 201 202 private: 203 int events_left = 0; 204}; 205 206json parser_helper(const std::string& s); 207bool accept_helper(const std::string& s); 208void comments_helper(const std::string& s); 209 210json parser_helper(const std::string& s) 211{ 212 json j; 213 json::parser(nlohmann::detail::input_adapter(s)).parse(true, j); 214 215 // if this line was reached, no exception occurred 216 // -> check if result is the same without exceptions 217 json j_nothrow; 218 CHECK_NOTHROW(json::parser(nlohmann::detail::input_adapter(s), nullptr, false).parse(true, j_nothrow)); 219 CHECK(j_nothrow == j); 220 221 json j_sax; 222 nlohmann::detail::json_sax_dom_parser<json> sdp(j_sax); 223 json::sax_parse(s, &sdp); 224 CHECK(j_sax == j); 225 226 comments_helper(s); 227 228 return j; 229} 230 231bool accept_helper(const std::string& s) 232{ 233 CAPTURE(s) 234 235 // 1. parse s without exceptions 236 json j; 237 CHECK_NOTHROW(json::parser(nlohmann::detail::input_adapter(s), nullptr, false).parse(true, j)); 238 const bool ok_noexcept = !j.is_discarded(); 239 240 // 2. accept s 241 const bool ok_accept = json::parser(nlohmann::detail::input_adapter(s)).accept(true); 242 243 // 3. check if both approaches come to the same result 244 CHECK(ok_noexcept == ok_accept); 245 246 // 4. parse with SAX (compare with relaxed accept result) 247 SaxEventLogger el; 248 CHECK_NOTHROW(json::sax_parse(s, &el, json::input_format_t::json, false)); 249 CHECK(json::parser(nlohmann::detail::input_adapter(s)).accept(false) == !el.errored); 250 251 // 5. parse with simple callback 252 json::parser_callback_t cb = [](int /*unused*/, json::parse_event_t /*unused*/, json& /*unused*/) noexcept 253 { 254 return true; 255 }; 256 json j_cb = json::parse(s, cb, false); 257 const bool ok_noexcept_cb = !j_cb.is_discarded(); 258 259 // 6. check if this approach came to the same result 260 CHECK(ok_noexcept == ok_noexcept_cb); 261 262 // 7. check if comments are properly ignored 263 if (ok_accept) 264 { 265 comments_helper(s); 266 } 267 268 // 8. return result 269 return ok_accept; 270} 271 272void comments_helper(const std::string& s) 273{ 274 json _; 275 276 // parse/accept with default parser 277 CHECK_NOTHROW(_ = json::parse(s)); 278 CHECK(json::accept(s)); 279 280 // parse/accept while skipping comments 281 CHECK_NOTHROW(_ = json::parse(s, nullptr, false, true)); 282 CHECK(json::accept(s, true)); 283 284 std::vector<std::string> json_with_comments; 285 286 // start with a comment 287 json_with_comments.push_back(std::string("// this is a comment\n") + s); 288 json_with_comments.push_back(std::string("/* this is a comment */") + s); 289 // end with a comment 290 json_with_comments.push_back(s + "// this is a comment"); 291 json_with_comments.push_back(s + "/* this is a comment */"); 292 293 // check all strings 294 for (const auto& json_with_comment : json_with_comments) 295 { 296 CAPTURE(json_with_comment) 297 CHECK_THROWS_AS(_ = json::parse(json_with_comment), json::parse_error); 298 CHECK(!json::accept(json_with_comment)); 299 300 CHECK_NOTHROW(_ = json::parse(json_with_comment, nullptr, true, true)); 301 CHECK(json::accept(json_with_comment, true)); 302 } 303} 304 305} // namespace 306 307TEST_CASE("parser class") 308{ 309 SECTION("parse") 310 { 311 SECTION("null") 312 { 313 CHECK(parser_helper("null") == json(nullptr)); 314 } 315 316 SECTION("true") 317 { 318 CHECK(parser_helper("true") == json(true)); 319 } 320 321 SECTION("false") 322 { 323 CHECK(parser_helper("false") == json(false)); 324 } 325 326 SECTION("array") 327 { 328 SECTION("empty array") 329 { 330 CHECK(parser_helper("[]") == json(json::value_t::array)); 331 CHECK(parser_helper("[ ]") == json(json::value_t::array)); 332 } 333 334 SECTION("nonempty array") 335 { 336 CHECK(parser_helper("[true, false, null]") == json({true, false, nullptr})); 337 } 338 } 339 340 SECTION("object") 341 { 342 SECTION("empty object") 343 { 344 CHECK(parser_helper("{}") == json(json::value_t::object)); 345 CHECK(parser_helper("{ }") == json(json::value_t::object)); 346 } 347 348 SECTION("nonempty object") 349 { 350 CHECK(parser_helper("{\"\": true, \"one\": 1, \"two\": null}") == json({{"", true}, {"one", 1}, {"two", nullptr}})); 351 } 352 } 353 354 SECTION("string") 355 { 356 // empty string 357 CHECK(parser_helper("\"\"") == json(json::value_t::string)); 358 359 SECTION("errors") 360 { 361 // error: tab in string 362 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&); 363 // error: newline in string 364 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&); 365 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&); 366 // error: backspace in string 367 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&); 368 // improve code coverage 369 CHECK_THROWS_AS(parser_helper("\uFF01"), json::parse_error&); 370 CHECK_THROWS_AS(parser_helper("[-4:1,]"), json::parse_error&); 371 // unescaped control characters 372 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) 373 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&); 374 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&); 375 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&); 376 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&); 377 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&); 378 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&); 379 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&); 380 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&); 381 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&); 382 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&); 383 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&); 384 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&); 385 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&); 386 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&); 387 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&); 388 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&); 389 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&); 390 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&); 391 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&); 392 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&); 393 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&); 394 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&); 395 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&); 396 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&); 397 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&); 398 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&); 399 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&); 400 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&); 401 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&); 402 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&); 403 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&); 404 405 SECTION("additional test for null byte") 406 { 407 // The test above for the null byte is wrong, because passing 408 // a string to the parser only reads int until it encounters 409 // a null byte. This test inserts the null byte later on and 410 // uses an iterator range. 411 std::string s = "\"1\""; 412 s[1] = '\0'; 413 json _; 414 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&); 415 } 416 } 417 418 SECTION("escaped") 419 { 420 // quotation mark "\"" 421 auto r1 = R"("\"")"_json; 422 CHECK(parser_helper("\"\\\"\"") == r1); 423 // reverse solidus "\\" 424 auto r2 = R"("\\")"_json; 425 CHECK(parser_helper("\"\\\\\"") == r2); 426 // solidus 427 CHECK(parser_helper("\"\\/\"") == R"("/")"_json); 428 // backspace 429 CHECK(parser_helper("\"\\b\"") == json("\b")); 430 // formfeed 431 CHECK(parser_helper("\"\\f\"") == json("\f")); 432 // newline 433 CHECK(parser_helper("\"\\n\"") == json("\n")); 434 // carriage return 435 CHECK(parser_helper("\"\\r\"") == json("\r")); 436 // horizontal tab 437 CHECK(parser_helper("\"\\t\"") == json("\t")); 438 439 CHECK(parser_helper("\"\\u0001\"").get<json::string_t>() == "\x01"); 440 CHECK(parser_helper("\"\\u000a\"").get<json::string_t>() == "\n"); 441 CHECK(parser_helper("\"\\u00b0\"").get<json::string_t>() == "°"); 442 CHECK(parser_helper("\"\\u0c00\"").get<json::string_t>() == "ఀ"); 443 CHECK(parser_helper("\"\\ud000\"").get<json::string_t>() == "퀀"); 444 CHECK(parser_helper("\"\\u000E\"").get<json::string_t>() == "\x0E"); 445 CHECK(parser_helper("\"\\u00F0\"").get<json::string_t>() == "ð"); 446 CHECK(parser_helper("\"\\u0100\"").get<json::string_t>() == "Ā"); 447 CHECK(parser_helper("\"\\u2000\"").get<json::string_t>() == " "); 448 CHECK(parser_helper("\"\\uFFFF\"").get<json::string_t>() == ""); 449 CHECK(parser_helper("\"\\u20AC\"").get<json::string_t>() == "€"); 450 CHECK(parser_helper("\"€\"").get<json::string_t>() == "€"); 451 CHECK(parser_helper("\"\"").get<json::string_t>() == ""); 452 453 CHECK(parser_helper("\"\\ud80c\\udc60\"").get<json::string_t>() == "\xf0\x93\x81\xa0"); 454 CHECK(parser_helper("\"\\ud83c\\udf1e\"").get<json::string_t>() == ""); 455 } 456 } 457 458 SECTION("number") 459 { 460 SECTION("integers") 461 { 462 SECTION("without exponent") 463 { 464 CHECK(parser_helper("-128") == json(-128)); 465 CHECK(parser_helper("-0") == json(-0)); 466 CHECK(parser_helper("0") == json(0)); 467 CHECK(parser_helper("128") == json(128)); 468 } 469 470 SECTION("with exponent") 471 { 472 CHECK(parser_helper("0e1") == json(0e1)); 473 CHECK(parser_helper("0E1") == json(0e1)); 474 475 CHECK(parser_helper("10000E-4") == json(10000e-4)); 476 CHECK(parser_helper("10000E-3") == json(10000e-3)); 477 CHECK(parser_helper("10000E-2") == json(10000e-2)); 478 CHECK(parser_helper("10000E-1") == json(10000e-1)); 479 CHECK(parser_helper("10000E0") == json(10000e0)); 480 CHECK(parser_helper("10000E1") == json(10000e1)); 481 CHECK(parser_helper("10000E2") == json(10000e2)); 482 CHECK(parser_helper("10000E3") == json(10000e3)); 483 CHECK(parser_helper("10000E4") == json(10000e4)); 484 485 CHECK(parser_helper("10000e-4") == json(10000e-4)); 486 CHECK(parser_helper("10000e-3") == json(10000e-3)); 487 CHECK(parser_helper("10000e-2") == json(10000e-2)); 488 CHECK(parser_helper("10000e-1") == json(10000e-1)); 489 CHECK(parser_helper("10000e0") == json(10000e0)); 490 CHECK(parser_helper("10000e1") == json(10000e1)); 491 CHECK(parser_helper("10000e2") == json(10000e2)); 492 CHECK(parser_helper("10000e3") == json(10000e3)); 493 CHECK(parser_helper("10000e4") == json(10000e4)); 494 495 CHECK(parser_helper("-0e1") == json(-0e1)); 496 CHECK(parser_helper("-0E1") == json(-0e1)); 497 CHECK(parser_helper("-0E123") == json(-0e123)); 498 499 // numbers after exponent 500 CHECK(parser_helper("10E0") == json(10e0)); 501 CHECK(parser_helper("10E1") == json(10e1)); 502 CHECK(parser_helper("10E2") == json(10e2)); 503 CHECK(parser_helper("10E3") == json(10e3)); 504 CHECK(parser_helper("10E4") == json(10e4)); 505 CHECK(parser_helper("10E5") == json(10e5)); 506 CHECK(parser_helper("10E6") == json(10e6)); 507 CHECK(parser_helper("10E7") == json(10e7)); 508 CHECK(parser_helper("10E8") == json(10e8)); 509 CHECK(parser_helper("10E9") == json(10e9)); 510 CHECK(parser_helper("10E+0") == json(10e0)); 511 CHECK(parser_helper("10E+1") == json(10e1)); 512 CHECK(parser_helper("10E+2") == json(10e2)); 513 CHECK(parser_helper("10E+3") == json(10e3)); 514 CHECK(parser_helper("10E+4") == json(10e4)); 515 CHECK(parser_helper("10E+5") == json(10e5)); 516 CHECK(parser_helper("10E+6") == json(10e6)); 517 CHECK(parser_helper("10E+7") == json(10e7)); 518 CHECK(parser_helper("10E+8") == json(10e8)); 519 CHECK(parser_helper("10E+9") == json(10e9)); 520 CHECK(parser_helper("10E-1") == json(10e-1)); 521 CHECK(parser_helper("10E-2") == json(10e-2)); 522 CHECK(parser_helper("10E-3") == json(10e-3)); 523 CHECK(parser_helper("10E-4") == json(10e-4)); 524 CHECK(parser_helper("10E-5") == json(10e-5)); 525 CHECK(parser_helper("10E-6") == json(10e-6)); 526 CHECK(parser_helper("10E-7") == json(10e-7)); 527 CHECK(parser_helper("10E-8") == json(10e-8)); 528 CHECK(parser_helper("10E-9") == json(10e-9)); 529 } 530 531 SECTION("edge cases") 532 { 533 // From RFC8259, Section 6: 534 // Note that when such software is used, numbers that are 535 // integers and are in the range [-(2**53)+1, (2**53)-1] 536 // are interoperable in the sense that implementations will 537 // agree exactly on their numeric values. 538 539 // -(2**53)+1 540 CHECK(parser_helper("-9007199254740991").get<int64_t>() == -9007199254740991); 541 // (2**53)-1 542 CHECK(parser_helper("9007199254740991").get<int64_t>() == 9007199254740991); 543 } 544 545 SECTION("over the edge cases") // issue #178 - Integer conversion to unsigned (incorrect handling of 64 bit integers) 546 { 547 // While RFC8259, Section 6 specifies a preference for support 548 // for ranges in range of IEEE 754-2008 binary64 (double precision) 549 // this does not accommodate 64 bit integers without loss of accuracy. 550 // As 64 bit integers are now widely used in software, it is desirable 551 // to expand support to to the full 64 bit (signed and unsigned) range 552 // i.e. -(2**63) -> (2**64)-1. 553 554 // -(2**63) ** Note: compilers see negative literals as negated positive numbers (hence the -1)) 555 CHECK(parser_helper("-9223372036854775808").get<int64_t>() == -9223372036854775807 - 1); 556 // (2**63)-1 557 CHECK(parser_helper("9223372036854775807").get<int64_t>() == 9223372036854775807); 558 // (2**64)-1 559 CHECK(parser_helper("18446744073709551615").get<uint64_t>() == 18446744073709551615u); 560 } 561 } 562 563 SECTION("floating-point") 564 { 565 SECTION("without exponent") 566 { 567 CHECK(parser_helper("-128.5") == json(-128.5)); 568 CHECK(parser_helper("0.999") == json(0.999)); 569 CHECK(parser_helper("128.5") == json(128.5)); 570 CHECK(parser_helper("-0.0") == json(-0.0)); 571 } 572 573 SECTION("with exponent") 574 { 575 CHECK(parser_helper("-128.5E3") == json(-128.5E3)); 576 CHECK(parser_helper("-128.5E-3") == json(-128.5E-3)); 577 CHECK(parser_helper("-0.0e1") == json(-0.0e1)); 578 CHECK(parser_helper("-0.0E1") == json(-0.0e1)); 579 } 580 } 581 582 SECTION("overflow") 583 { 584 // overflows during parsing yield an exception 585 CHECK_THROWS_WITH_AS(parser_helper("1.18973e+4932").empty(), "[json.exception.out_of_range.406] number overflow parsing '1.18973e+4932'", json::out_of_range&); 586 } 587 588 SECTION("invalid numbers") 589 { 590 // numbers must not begin with "+" 591 CHECK_THROWS_AS(parser_helper("+1"), json::parse_error&); 592 CHECK_THROWS_AS(parser_helper("+0"), json::parse_error&); 593 594 CHECK_THROWS_WITH_AS(parser_helper("01"), 595 "[json.exception.parse_error.101] parse error at line 1, column 2: syntax error while parsing value - unexpected number literal; expected end of input", json::parse_error&); 596 CHECK_THROWS_WITH_AS(parser_helper("-01"), 597 "[json.exception.parse_error.101] parse error at line 1, column 3: syntax error while parsing value - unexpected number literal; expected end of input", json::parse_error&); 598 CHECK_THROWS_WITH_AS(parser_helper("--1"), 599 "[json.exception.parse_error.101] parse error at line 1, column 2: syntax error while parsing value - invalid number; expected digit after '-'; last read: '--'", json::parse_error&); 600 CHECK_THROWS_WITH_AS(parser_helper("1."), 601 "[json.exception.parse_error.101] parse error at line 1, column 3: syntax error while parsing value - invalid number; expected digit after '.'; last read: '1.'", json::parse_error&); 602 CHECK_THROWS_WITH_AS(parser_helper("1E"), 603 "[json.exception.parse_error.101] parse error at line 1, column 3: syntax error while parsing value - invalid number; expected '+', '-', or digit after exponent; last read: '1E'", json::parse_error&); 604 CHECK_THROWS_WITH_AS(parser_helper("1E-"), 605 "[json.exception.parse_error.101] parse error at line 1, column 4: syntax error while parsing value - invalid number; expected digit after exponent sign; last read: '1E-'", json::parse_error&); 606 CHECK_THROWS_WITH_AS(parser_helper("1.E1"), 607 "[json.exception.parse_error.101] parse error at line 1, column 3: syntax error while parsing value - invalid number; expected digit after '.'; last read: '1.E'", json::parse_error&); 608 CHECK_THROWS_WITH_AS(parser_helper("-1E"), 609 "[json.exception.parse_error.101] parse error at line 1, column 4: syntax error while parsing value - invalid number; expected '+', '-', or digit after exponent; last read: '-1E'", json::parse_error&); 610 CHECK_THROWS_WITH_AS(parser_helper("-0E#"), 611 "[json.exception.parse_error.101] parse error at line 1, column 4: syntax error while parsing value - invalid number; expected '+', '-', or digit after exponent; last read: '-0E#'", json::parse_error&); 612 CHECK_THROWS_WITH_AS(parser_helper("-0E-#"), 613 "[json.exception.parse_error.101] parse error at line 1, column 5: syntax error while parsing value - invalid number; expected digit after exponent sign; last read: '-0E-#'", json::parse_error&); 614 CHECK_THROWS_WITH_AS(parser_helper("-0#"), 615 "[json.exception.parse_error.101] parse error at line 1, column 3: syntax error while parsing value - invalid literal; last read: '-0#'; expected end of input", json::parse_error&); 616 CHECK_THROWS_WITH_AS(parser_helper("-0.0:"), 617 "[json.exception.parse_error.101] parse error at line 1, column 5: syntax error while parsing value - unexpected ':'; expected end of input", json::parse_error&); 618 CHECK_THROWS_WITH_AS(parser_helper("-0.0Z"), 619 "[json.exception.parse_error.101] parse error at line 1, column 5: syntax error while parsing value - invalid literal; last read: '-0.0Z'; expected end of input", json::parse_error&); 620 CHECK_THROWS_WITH_AS(parser_helper("-0E123:"), 621 "[json.exception.parse_error.101] parse error at line 1, column 7: syntax error while parsing value - unexpected ':'; expected end of input", json::parse_error&); 622 CHECK_THROWS_WITH_AS(parser_helper("-0e0-:"), 623 "[json.exception.parse_error.101] parse error at line 1, column 6: syntax error while parsing value - invalid number; expected digit after '-'; last read: '-:'; expected end of input", json::parse_error&); 624 CHECK_THROWS_WITH_AS(parser_helper("-0e-:"), 625 "[json.exception.parse_error.101] parse error at line 1, column 5: syntax error while parsing value - invalid number; expected digit after exponent sign; last read: '-0e-:'", json::parse_error&); 626 CHECK_THROWS_WITH_AS(parser_helper("-0f"), 627 "[json.exception.parse_error.101] parse error at line 1, column 4: syntax error while parsing value - invalid literal; last read: '-0f'; expected end of input", json::parse_error&); 628 } 629 } 630 } 631 632 SECTION("accept") 633 { 634 SECTION("null") 635 { 636 CHECK(accept_helper("null")); 637 } 638 639 SECTION("true") 640 { 641 CHECK(accept_helper("true")); 642 } 643 644 SECTION("false") 645 { 646 CHECK(accept_helper("false")); 647 } 648 649 SECTION("array") 650 { 651 SECTION("empty array") 652 { 653 CHECK(accept_helper("[]")); 654 CHECK(accept_helper("[ ]")); 655 } 656 657 SECTION("nonempty array") 658 { 659 CHECK(accept_helper("[true, false, null]")); 660 } 661 } 662 663 SECTION("object") 664 { 665 SECTION("empty object") 666 { 667 CHECK(accept_helper("{}")); 668 CHECK(accept_helper("{ }")); 669 } 670 671 SECTION("nonempty object") 672 { 673 CHECK(accept_helper("{\"\": true, \"one\": 1, \"two\": null}")); 674 } 675 } 676 677 SECTION("string") 678 { 679 // empty string 680 CHECK(accept_helper("\"\"")); 681 682 SECTION("errors") 683 { 684 // error: tab in string 685 CHECK(accept_helper("\"\t\"") == false); 686 // error: newline in string 687 CHECK(accept_helper("\"\n\"") == false); 688 CHECK(accept_helper("\"\r\"") == false); 689 // error: backspace in string 690 CHECK(accept_helper("\"\b\"") == false); 691 // improve code coverage 692 CHECK(accept_helper("\uFF01") == false); 693 CHECK(accept_helper("[-4:1,]") == false); 694 // unescaped control characters 695 CHECK(accept_helper("\"\x00\"") == false); // NOLINT(bugprone-string-literal-with-embedded-nul) 696 CHECK(accept_helper("\"\x01\"") == false); 697 CHECK(accept_helper("\"\x02\"") == false); 698 CHECK(accept_helper("\"\x03\"") == false); 699 CHECK(accept_helper("\"\x04\"") == false); 700 CHECK(accept_helper("\"\x05\"") == false); 701 CHECK(accept_helper("\"\x06\"") == false); 702 CHECK(accept_helper("\"\x07\"") == false); 703 CHECK(accept_helper("\"\x08\"") == false); 704 CHECK(accept_helper("\"\x09\"") == false); 705 CHECK(accept_helper("\"\x0a\"") == false); 706 CHECK(accept_helper("\"\x0b\"") == false); 707 CHECK(accept_helper("\"\x0c\"") == false); 708 CHECK(accept_helper("\"\x0d\"") == false); 709 CHECK(accept_helper("\"\x0e\"") == false); 710 CHECK(accept_helper("\"\x0f\"") == false); 711 CHECK(accept_helper("\"\x10\"") == false); 712 CHECK(accept_helper("\"\x11\"") == false); 713 CHECK(accept_helper("\"\x12\"") == false); 714 CHECK(accept_helper("\"\x13\"") == false); 715 CHECK(accept_helper("\"\x14\"") == false); 716 CHECK(accept_helper("\"\x15\"") == false); 717 CHECK(accept_helper("\"\x16\"") == false); 718 CHECK(accept_helper("\"\x17\"") == false); 719 CHECK(accept_helper("\"\x18\"") == false); 720 CHECK(accept_helper("\"\x19\"") == false); 721 CHECK(accept_helper("\"\x1a\"") == false); 722 CHECK(accept_helper("\"\x1b\"") == false); 723 CHECK(accept_helper("\"\x1c\"") == false); 724 CHECK(accept_helper("\"\x1d\"") == false); 725 CHECK(accept_helper("\"\x1e\"") == false); 726 CHECK(accept_helper("\"\x1f\"") == false); 727 } 728 729 SECTION("escaped") 730 { 731 // quotation mark "\"" 732 auto r1 = R"("\"")"_json; 733 CHECK(accept_helper("\"\\\"\"")); 734 // reverse solidus "\\" 735 auto r2 = R"("\\")"_json; 736 CHECK(accept_helper("\"\\\\\"")); 737 // solidus 738 CHECK(accept_helper("\"\\/\"")); 739 // backspace 740 CHECK(accept_helper("\"\\b\"")); 741 // formfeed 742 CHECK(accept_helper("\"\\f\"")); 743 // newline 744 CHECK(accept_helper("\"\\n\"")); 745 // carriage return 746 CHECK(accept_helper("\"\\r\"")); 747 // horizontal tab 748 CHECK(accept_helper("\"\\t\"")); 749 750 CHECK(accept_helper("\"\\u0001\"")); 751 CHECK(accept_helper("\"\\u000a\"")); 752 CHECK(accept_helper("\"\\u00b0\"")); 753 CHECK(accept_helper("\"\\u0c00\"")); 754 CHECK(accept_helper("\"\\ud000\"")); 755 CHECK(accept_helper("\"\\u000E\"")); 756 CHECK(accept_helper("\"\\u00F0\"")); 757 CHECK(accept_helper("\"\\u0100\"")); 758 CHECK(accept_helper("\"\\u2000\"")); 759 CHECK(accept_helper("\"\\uFFFF\"")); 760 CHECK(accept_helper("\"\\u20AC\"")); 761 CHECK(accept_helper("\"€\"")); 762 CHECK(accept_helper("\"\"")); 763 764 CHECK(accept_helper("\"\\ud80c\\udc60\"")); 765 CHECK(accept_helper("\"\\ud83c\\udf1e\"")); 766 } 767 } 768 769 SECTION("number") 770 { 771 SECTION("integers") 772 { 773 SECTION("without exponent") 774 { 775 CHECK(accept_helper("-128")); 776 CHECK(accept_helper("-0")); 777 CHECK(accept_helper("0")); 778 CHECK(accept_helper("128")); 779 } 780 781 SECTION("with exponent") 782 { 783 CHECK(accept_helper("0e1")); 784 CHECK(accept_helper("0E1")); 785 786 CHECK(accept_helper("10000E-4")); 787 CHECK(accept_helper("10000E-3")); 788 CHECK(accept_helper("10000E-2")); 789 CHECK(accept_helper("10000E-1")); 790 CHECK(accept_helper("10000E0")); 791 CHECK(accept_helper("10000E1")); 792 CHECK(accept_helper("10000E2")); 793 CHECK(accept_helper("10000E3")); 794 CHECK(accept_helper("10000E4")); 795 796 CHECK(accept_helper("10000e-4")); 797 CHECK(accept_helper("10000e-3")); 798 CHECK(accept_helper("10000e-2")); 799 CHECK(accept_helper("10000e-1")); 800 CHECK(accept_helper("10000e0")); 801 CHECK(accept_helper("10000e1")); 802 CHECK(accept_helper("10000e2")); 803 CHECK(accept_helper("10000e3")); 804 CHECK(accept_helper("10000e4")); 805 806 CHECK(accept_helper("-0e1")); 807 CHECK(accept_helper("-0E1")); 808 CHECK(accept_helper("-0E123")); 809 } 810 811 SECTION("edge cases") 812 { 813 // From RFC8259, Section 6: 814 // Note that when such software is used, numbers that are 815 // integers and are in the range [-(2**53)+1, (2**53)-1] 816 // are interoperable in the sense that implementations will 817 // agree exactly on their numeric values. 818 819 // -(2**53)+1 820 CHECK(accept_helper("-9007199254740991")); 821 // (2**53)-1 822 CHECK(accept_helper("9007199254740991")); 823 } 824 825 SECTION("over the edge cases") // issue #178 - Integer conversion to unsigned (incorrect handling of 64 bit integers) 826 { 827 // While RFC8259, Section 6 specifies a preference for support 828 // for ranges in range of IEEE 754-2008 binary64 (double precision) 829 // this does not accommodate 64 bit integers without loss of accuracy. 830 // As 64 bit integers are now widely used in software, it is desirable 831 // to expand support to to the full 64 bit (signed and unsigned) range 832 // i.e. -(2**63) -> (2**64)-1. 833 834 // -(2**63) ** Note: compilers see negative literals as negated positive numbers (hence the -1)) 835 CHECK(accept_helper("-9223372036854775808")); 836 // (2**63)-1 837 CHECK(accept_helper("9223372036854775807")); 838 // (2**64)-1 839 CHECK(accept_helper("18446744073709551615")); 840 } 841 } 842 843 SECTION("floating-point") 844 { 845 SECTION("without exponent") 846 { 847 CHECK(accept_helper("-128.5")); 848 CHECK(accept_helper("0.999")); 849 CHECK(accept_helper("128.5")); 850 CHECK(accept_helper("-0.0")); 851 } 852 853 SECTION("with exponent") 854 { 855 CHECK(accept_helper("-128.5E3")); 856 CHECK(accept_helper("-128.5E-3")); 857 CHECK(accept_helper("-0.0e1")); 858 CHECK(accept_helper("-0.0E1")); 859 } 860 } 861 862 SECTION("overflow") 863 { 864 // overflows during parsing 865 CHECK(!accept_helper("1.18973e+4932")); 866 } 867 868 SECTION("invalid numbers") 869 { 870 CHECK(accept_helper("01") == false); 871 CHECK(accept_helper("--1") == false); 872 CHECK(accept_helper("1.") == false); 873 CHECK(accept_helper("1E") == false); 874 CHECK(accept_helper("1E-") == false); 875 CHECK(accept_helper("1.E1") == false); 876 CHECK(accept_helper("-1E") == false); 877 CHECK(accept_helper("-0E#") == false); 878 CHECK(accept_helper("-0E-#") == false); 879 CHECK(accept_helper("-0#") == false); 880 CHECK(accept_helper("-0.0:") == false); 881 CHECK(accept_helper("-0.0Z") == false); 882 CHECK(accept_helper("-0E123:") == false); 883 CHECK(accept_helper("-0e0-:") == false); 884 CHECK(accept_helper("-0e-:") == false); 885 CHECK(accept_helper("-0f") == false); 886 887 // numbers must not begin with "+" 888 CHECK(accept_helper("+1") == false); 889 CHECK(accept_helper("+0") == false); 890 } 891 } 892 } 893 894 SECTION("parse errors") 895 { 896 // unexpected end of number 897 CHECK_THROWS_WITH_AS(parser_helper("0."), 898 "[json.exception.parse_error.101] parse error at line 1, column 3: syntax error while parsing value - invalid number; expected digit after '.'; last read: '0.'", json::parse_error&); 899 CHECK_THROWS_WITH_AS(parser_helper("-"), 900 "[json.exception.parse_error.101] parse error at line 1, column 2: syntax error while parsing value - invalid number; expected digit after '-'; last read: '-'", json::parse_error&); 901 CHECK_THROWS_WITH_AS(parser_helper("--"), 902 "[json.exception.parse_error.101] parse error at line 1, column 2: syntax error while parsing value - invalid number; expected digit after '-'; last read: '--'", json::parse_error&); 903 CHECK_THROWS_WITH_AS(parser_helper("-0."), 904 "[json.exception.parse_error.101] parse error at line 1, column 4: syntax error while parsing value - invalid number; expected digit after '.'; last read: '-0.'", json::parse_error&); 905 CHECK_THROWS_WITH_AS(parser_helper("-."), 906 "[json.exception.parse_error.101] parse error at line 1, column 2: syntax error while parsing value - invalid number; expected digit after '-'; last read: '-.'", json::parse_error&); 907 CHECK_THROWS_WITH_AS(parser_helper("-:"), 908 "[json.exception.parse_error.101] parse error at line 1, column 2: syntax error while parsing value - invalid number; expected digit after '-'; last read: '-:'", json::parse_error&); 909 CHECK_THROWS_WITH_AS(parser_helper("0.:"), 910 "[json.exception.parse_error.101] parse error at line 1, column 3: syntax error while parsing value - invalid number; expected digit after '.'; last read: '0.:'", json::parse_error&); 911 CHECK_THROWS_WITH_AS(parser_helper("e."), 912 "[json.exception.parse_error.101] parse error at line 1, column 1: syntax error while parsing value - invalid literal; last read: 'e'", json::parse_error&); 913 CHECK_THROWS_WITH_AS(parser_helper("1e."), 914 "[json.exception.parse_error.101] parse error at line 1, column 3: syntax error while parsing value - invalid number; expected '+', '-', or digit after exponent; last read: '1e.'", json::parse_error&); 915 CHECK_THROWS_WITH_AS(parser_helper("1e/"), 916 "[json.exception.parse_error.101] parse error at line 1, column 3: syntax error while parsing value - invalid number; expected '+', '-', or digit after exponent; last read: '1e/'", json::parse_error&); 917 CHECK_THROWS_WITH_AS(parser_helper("1e:"), 918 "[json.exception.parse_error.101] parse error at line 1, column 3: syntax error while parsing value - invalid number; expected '+', '-', or digit after exponent; last read: '1e:'", json::parse_error&); 919 CHECK_THROWS_WITH_AS(parser_helper("1E."), 920 "[json.exception.parse_error.101] parse error at line 1, column 3: syntax error while parsing value - invalid number; expected '+', '-', or digit after exponent; last read: '1E.'", json::parse_error&); 921 CHECK_THROWS_WITH_AS(parser_helper("1E/"), 922 "[json.exception.parse_error.101] parse error at line 1, column 3: syntax error while parsing value - invalid number; expected '+', '-', or digit after exponent; last read: '1E/'", json::parse_error&); 923 CHECK_THROWS_WITH_AS(parser_helper("1E:"), 924 "[json.exception.parse_error.101] parse error at line 1, column 3: syntax error while parsing value - invalid number; expected '+', '-', or digit after exponent; last read: '1E:'", json::parse_error&); 925 926 // unexpected end of null 927 CHECK_THROWS_WITH_AS(parser_helper("n"), 928 "[json.exception.parse_error.101] parse error at line 1, column 2: syntax error while parsing value - invalid literal; last read: 'n'", json::parse_error&); 929 CHECK_THROWS_WITH_AS(parser_helper("nu"), 930 "[json.exception.parse_error.101] parse error at line 1, column 3: syntax error while parsing value - invalid literal; last read: 'nu'", json::parse_error&); 931 CHECK_THROWS_WITH_AS(parser_helper("nul"), 932 "[json.exception.parse_error.101] parse error at line 1, column 4: syntax error while parsing value - invalid literal; last read: 'nul'", json::parse_error&); 933 CHECK_THROWS_WITH_AS(parser_helper("nulk"), 934 "[json.exception.parse_error.101] parse error at line 1, column 4: syntax error while parsing value - invalid literal; last read: 'nulk'", json::parse_error&); 935 CHECK_THROWS_WITH_AS(parser_helper("nulm"), 936 "[json.exception.parse_error.101] parse error at line 1, column 4: syntax error while parsing value - invalid literal; last read: 'nulm'", json::parse_error&); 937 938 // unexpected end of true 939 CHECK_THROWS_WITH_AS(parser_helper("t"), 940 "[json.exception.parse_error.101] parse error at line 1, column 2: syntax error while parsing value - invalid literal; last read: 't'", json::parse_error&); 941 CHECK_THROWS_WITH_AS(parser_helper("tr"), 942 "[json.exception.parse_error.101] parse error at line 1, column 3: syntax error while parsing value - invalid literal; last read: 'tr'", json::parse_error&); 943 CHECK_THROWS_WITH_AS(parser_helper("tru"), 944 "[json.exception.parse_error.101] parse error at line 1, column 4: syntax error while parsing value - invalid literal; last read: 'tru'", json::parse_error&); 945 CHECK_THROWS_WITH_AS(parser_helper("trud"), 946 "[json.exception.parse_error.101] parse error at line 1, column 4: syntax error while parsing value - invalid literal; last read: 'trud'", json::parse_error&); 947 CHECK_THROWS_WITH_AS(parser_helper("truf"), 948 "[json.exception.parse_error.101] parse error at line 1, column 4: syntax error while parsing value - invalid literal; last read: 'truf'", json::parse_error&); 949 950 // unexpected end of false 951 CHECK_THROWS_WITH_AS(parser_helper("f"), 952 "[json.exception.parse_error.101] parse error at line 1, column 2: syntax error while parsing value - invalid literal; last read: 'f'", json::parse_error&); 953 CHECK_THROWS_WITH_AS(parser_helper("fa"), 954 "[json.exception.parse_error.101] parse error at line 1, column 3: syntax error while parsing value - invalid literal; last read: 'fa'", json::parse_error&); 955 CHECK_THROWS_WITH_AS(parser_helper("fal"), 956 "[json.exception.parse_error.101] parse error at line 1, column 4: syntax error while parsing value - invalid literal; last read: 'fal'", json::parse_error&); 957 CHECK_THROWS_WITH_AS(parser_helper("fals"), 958 "[json.exception.parse_error.101] parse error at line 1, column 5: syntax error while parsing value - invalid literal; last read: 'fals'", json::parse_error&); 959 CHECK_THROWS_WITH_AS(parser_helper("falsd"), 960 "[json.exception.parse_error.101] parse error at line 1, column 5: syntax error while parsing value - invalid literal; last read: 'falsd'", json::parse_error&); 961 CHECK_THROWS_WITH_AS(parser_helper("falsf"), 962 "[json.exception.parse_error.101] parse error at line 1, column 5: syntax error while parsing value - invalid literal; last read: 'falsf'", json::parse_error&); 963 964 // missing/unexpected end of array 965 CHECK_THROWS_WITH_AS(parser_helper("["), 966 "[json.exception.parse_error.101] parse error at line 1, column 2: syntax error while parsing value - unexpected end of input; expected '[', '{', or a literal", json::parse_error&); 967 CHECK_THROWS_WITH_AS(parser_helper("[1"), 968 "[json.exception.parse_error.101] parse error at line 1, column 3: syntax error while parsing array - unexpected end of input; expected ']'", json::parse_error&); 969 CHECK_THROWS_WITH_AS(parser_helper("[1,"), 970 "[json.exception.parse_error.101] parse error at line 1, column 4: syntax error while parsing value - unexpected end of input; expected '[', '{', or a literal", json::parse_error&); 971 CHECK_THROWS_WITH_AS(parser_helper("[1,]"), 972 "[json.exception.parse_error.101] parse error at line 1, column 4: syntax error while parsing value - unexpected ']'; expected '[', '{', or a literal", json::parse_error&); 973 CHECK_THROWS_WITH_AS(parser_helper("]"), 974 "[json.exception.parse_error.101] parse error at line 1, column 1: syntax error while parsing value - unexpected ']'; expected '[', '{', or a literal", json::parse_error&); 975 976 // missing/unexpected end of object 977 CHECK_THROWS_WITH_AS(parser_helper("{"), 978 "[json.exception.parse_error.101] parse error at line 1, column 2: syntax error while parsing object key - unexpected end of input; expected string literal", json::parse_error&); 979 CHECK_THROWS_WITH_AS(parser_helper("{\"foo\""), 980 "[json.exception.parse_error.101] parse error at line 1, column 7: syntax error while parsing object separator - unexpected end of input; expected ':'", json::parse_error&); 981 CHECK_THROWS_WITH_AS(parser_helper("{\"foo\":"), 982 "[json.exception.parse_error.101] parse error at line 1, column 8: syntax error while parsing value - unexpected end of input; expected '[', '{', or a literal", json::parse_error&); 983 CHECK_THROWS_WITH_AS(parser_helper("{\"foo\":}"), 984 "[json.exception.parse_error.101] parse error at line 1, column 8: syntax error while parsing value - unexpected '}'; expected '[', '{', or a literal", json::parse_error&); 985 CHECK_THROWS_WITH_AS(parser_helper("{\"foo\":1,}"), 986 "[json.exception.parse_error.101] parse error at line 1, column 10: syntax error while parsing object key - unexpected '}'; expected string literal", json::parse_error&); 987 CHECK_THROWS_WITH_AS(parser_helper("}"), 988 "[json.exception.parse_error.101] parse error at line 1, column 1: syntax error while parsing value - unexpected '}'; expected '[', '{', or a literal", json::parse_error&); 989 990 // missing/unexpected end of string 991 CHECK_THROWS_WITH_AS(parser_helper("\""), 992 "[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&); 993 CHECK_THROWS_WITH_AS(parser_helper("\"\\\""), 994 "[json.exception.parse_error.101] parse error at line 1, column 4: syntax error while parsing value - invalid string: missing closing quote; last read: '\"\\\"'", json::parse_error&); 995 CHECK_THROWS_WITH_AS(parser_helper("\"\\u\""), 996 "[json.exception.parse_error.101] parse error at line 1, column 4: syntax error while parsing value - invalid string: '\\u' must be followed by 4 hex digits; last read: '\"\\u\"'", json::parse_error&); 997 CHECK_THROWS_WITH_AS(parser_helper("\"\\u0\""), 998 "[json.exception.parse_error.101] parse error at line 1, column 5: syntax error while parsing value - invalid string: '\\u' must be followed by 4 hex digits; last read: '\"\\u0\"'", json::parse_error&); 999 CHECK_THROWS_WITH_AS(parser_helper("\"\\u01\""), 1000 "[json.exception.parse_error.101] parse error at line 1, column 6: syntax error while parsing value - invalid string: '\\u' must be followed by 4 hex digits; last read: '\"\\u01\"'", json::parse_error&); 1001 CHECK_THROWS_WITH_AS(parser_helper("\"\\u012\""), 1002 "[json.exception.parse_error.101] parse error at line 1, column 7: syntax error while parsing value - invalid string: '\\u' must be followed by 4 hex digits; last read: '\"\\u012\"'", json::parse_error&); 1003 CHECK_THROWS_WITH_AS(parser_helper("\"\\u"), 1004 "[json.exception.parse_error.101] parse error at line 1, column 4: syntax error while parsing value - invalid string: '\\u' must be followed by 4 hex digits; last read: '\"\\u'", json::parse_error&); 1005 CHECK_THROWS_WITH_AS(parser_helper("\"\\u0"), 1006 "[json.exception.parse_error.101] parse error at line 1, column 5: syntax error while parsing value - invalid string: '\\u' must be followed by 4 hex digits; last read: '\"\\u0'", json::parse_error&); 1007 CHECK_THROWS_WITH_AS(parser_helper("\"\\u01"), 1008 "[json.exception.parse_error.101] parse error at line 1, column 6: syntax error while parsing value - invalid string: '\\u' must be followed by 4 hex digits; last read: '\"\\u01'", json::parse_error&); 1009 CHECK_THROWS_WITH_AS(parser_helper("\"\\u012"), 1010 "[json.exception.parse_error.101] parse error at line 1, column 7: syntax error while parsing value - invalid string: '\\u' must be followed by 4 hex digits; last read: '\"\\u012'", json::parse_error&); 1011 1012 // invalid escapes 1013 for (int c = 1; c < 128; ++c) 1014 { 1015 auto s = std::string("\"\\") + std::string(1, static_cast<char>(c)) + "\""; 1016 1017 switch (c) 1018 { 1019 // valid escapes 1020 case ('"'): 1021 case ('\\'): 1022 case ('/'): 1023 case ('b'): 1024 case ('f'): 1025 case ('n'): 1026 case ('r'): 1027 case ('t'): 1028 { 1029 CHECK_NOTHROW(parser_helper(s)); 1030 break; 1031 } 1032 1033 // \u must be followed with four numbers, so we skip it here 1034 case ('u'): 1035 { 1036 break; 1037 } 1038 1039 // any other combination of backslash and character is invalid 1040 default: 1041 { 1042 CHECK_THROWS_AS(parser_helper(s), json::parse_error&); 1043 // only check error message if c is not a control character 1044 if (c > 0x1f) 1045 { 1046 CHECK_THROWS_WITH_STD_STR(parser_helper(s), 1047 "[json.exception.parse_error.101] parse error at line 1, column 3: syntax error while parsing value - invalid string: forbidden character after backslash; last read: '\"\\" + std::string(1, static_cast<char>(c)) + "'"); 1048 } 1049 break; 1050 } 1051 } 1052 } 1053 1054 // invalid \uxxxx escapes 1055 { 1056 // check whether character is a valid hex character 1057 const auto valid = [](int c) 1058 { 1059 switch (c) 1060 { 1061 case ('0'): 1062 case ('1'): 1063 case ('2'): 1064 case ('3'): 1065 case ('4'): 1066 case ('5'): 1067 case ('6'): 1068 case ('7'): 1069 case ('8'): 1070 case ('9'): 1071 case ('a'): 1072 case ('b'): 1073 case ('c'): 1074 case ('d'): 1075 case ('e'): 1076 case ('f'): 1077 case ('A'): 1078 case ('B'): 1079 case ('C'): 1080 case ('D'): 1081 case ('E'): 1082 case ('F'): 1083 { 1084 return true; 1085 } 1086 1087 default: 1088 { 1089 return false; 1090 } 1091 } 1092 }; 1093 1094 for (int c = 1; c < 128; ++c) 1095 { 1096 std::string s = "\"\\u"; 1097 1098 // create a string with the iterated character at each position 1099 auto s1 = s + "000" + std::string(1, static_cast<char>(c)) + "\""; 1100 auto s2 = s + "00" + std::string(1, static_cast<char>(c)) + "0\""; 1101 auto s3 = s + "0" + std::string(1, static_cast<char>(c)) + "00\""; 1102 auto s4 = s + std::string(1, static_cast<char>(c)) + "000\""; 1103 1104 if (valid(c)) 1105 { 1106 CAPTURE(s1) 1107 CHECK_NOTHROW(parser_helper(s1)); 1108 CAPTURE(s2) 1109 CHECK_NOTHROW(parser_helper(s2)); 1110 CAPTURE(s3) 1111 CHECK_NOTHROW(parser_helper(s3)); 1112 CAPTURE(s4) 1113 CHECK_NOTHROW(parser_helper(s4)); 1114 } 1115 else 1116 { 1117 CAPTURE(s1) 1118 CHECK_THROWS_AS(parser_helper(s1), json::parse_error&); 1119 // only check error message if c is not a control character 1120 if (c > 0x1f) 1121 { 1122 CHECK_THROWS_WITH_STD_STR(parser_helper(s1), 1123 "[json.exception.parse_error.101] parse error at line 1, column 7: syntax error while parsing value - invalid string: '\\u' must be followed by 4 hex digits; last read: '" + s1.substr(0, 7) + "'"); 1124 } 1125 1126 CAPTURE(s2) 1127 CHECK_THROWS_AS(parser_helper(s2), json::parse_error&); 1128 // only check error message if c is not a control character 1129 if (c > 0x1f) 1130 { 1131 CHECK_THROWS_WITH_STD_STR(parser_helper(s2), 1132 "[json.exception.parse_error.101] parse error at line 1, column 6: syntax error while parsing value - invalid string: '\\u' must be followed by 4 hex digits; last read: '" + s2.substr(0, 6) + "'"); 1133 } 1134 1135 CAPTURE(s3) 1136 CHECK_THROWS_AS(parser_helper(s3), json::parse_error&); 1137 // only check error message if c is not a control character 1138 if (c > 0x1f) 1139 { 1140 CHECK_THROWS_WITH_STD_STR(parser_helper(s3), 1141 "[json.exception.parse_error.101] parse error at line 1, column 5: syntax error while parsing value - invalid string: '\\u' must be followed by 4 hex digits; last read: '" + s3.substr(0, 5) + "'"); 1142 } 1143 1144 CAPTURE(s4) 1145 CHECK_THROWS_AS(parser_helper(s4), json::parse_error&); 1146 // only check error message if c is not a control character 1147 if (c > 0x1f) 1148 { 1149 CHECK_THROWS_WITH_STD_STR(parser_helper(s4), 1150 "[json.exception.parse_error.101] parse error at line 1, column 4: syntax error while parsing value - invalid string: '\\u' must be followed by 4 hex digits; last read: '" + s4.substr(0, 4) + "'"); 1151 } 1152 } 1153 } 1154 } 1155 1156 json _; 1157 1158 // missing part of a surrogate pair 1159 CHECK_THROWS_WITH_AS(_ = json::parse("\"\\uD80C\""), "[json.exception.parse_error.101] parse error at line 1, column 8: syntax error while parsing value - invalid string: surrogate U+D800..U+DBFF must be followed by U+DC00..U+DFFF; last read: '\"\\uD80C\"'", json::parse_error&); 1160 // invalid surrogate pair 1161 CHECK_THROWS_WITH_AS(_ = json::parse("\"\\uD80C\\uD80C\""), 1162 "[json.exception.parse_error.101] parse error at line 1, column 13: syntax error while parsing value - invalid string: surrogate U+D800..U+DBFF must be followed by U+DC00..U+DFFF; last read: '\"\\uD80C\\uD80C'", json::parse_error&); 1163 CHECK_THROWS_WITH_AS(_ = json::parse("\"\\uD80C\\u0000\""), 1164 "[json.exception.parse_error.101] parse error at line 1, column 13: syntax error while parsing value - invalid string: surrogate U+D800..U+DBFF must be followed by U+DC00..U+DFFF; last read: '\"\\uD80C\\u0000'", json::parse_error&); 1165 CHECK_THROWS_WITH_AS(_ = json::parse("\"\\uD80C\\uFFFF\""), 1166 "[json.exception.parse_error.101] parse error at line 1, column 13: syntax error while parsing value - invalid string: surrogate U+D800..U+DBFF must be followed by U+DC00..U+DFFF; last read: '\"\\uD80C\\uFFFF'", json::parse_error&); 1167 } 1168 1169 SECTION("parse errors (accept)") 1170 { 1171 // unexpected end of number 1172 CHECK(accept_helper("0.") == false); 1173 CHECK(accept_helper("-") == false); 1174 CHECK(accept_helper("--") == false); 1175 CHECK(accept_helper("-0.") == false); 1176 CHECK(accept_helper("-.") == false); 1177 CHECK(accept_helper("-:") == false); 1178 CHECK(accept_helper("0.:") == false); 1179 CHECK(accept_helper("e.") == false); 1180 CHECK(accept_helper("1e.") == false); 1181 CHECK(accept_helper("1e/") == false); 1182 CHECK(accept_helper("1e:") == false); 1183 CHECK(accept_helper("1E.") == false); 1184 CHECK(accept_helper("1E/") == false); 1185 CHECK(accept_helper("1E:") == false); 1186 1187 // unexpected end of null 1188 CHECK(accept_helper("n") == false); 1189 CHECK(accept_helper("nu") == false); 1190 CHECK(accept_helper("nul") == false); 1191 1192 // unexpected end of true 1193 CHECK(accept_helper("t") == false); 1194 CHECK(accept_helper("tr") == false); 1195 CHECK(accept_helper("tru") == false); 1196 1197 // unexpected end of false 1198 CHECK(accept_helper("f") == false); 1199 CHECK(accept_helper("fa") == false); 1200 CHECK(accept_helper("fal") == false); 1201 CHECK(accept_helper("fals") == false); 1202 1203 // missing/unexpected end of array 1204 CHECK(accept_helper("[") == false); 1205 CHECK(accept_helper("[1") == false); 1206 CHECK(accept_helper("[1,") == false); 1207 CHECK(accept_helper("[1,]") == false); 1208 CHECK(accept_helper("]") == false); 1209 1210 // missing/unexpected end of object 1211 CHECK(accept_helper("{") == false); 1212 CHECK(accept_helper("{\"foo\"") == false); 1213 CHECK(accept_helper("{\"foo\":") == false); 1214 CHECK(accept_helper("{\"foo\":}") == false); 1215 CHECK(accept_helper("{\"foo\":1,}") == false); 1216 CHECK(accept_helper("}") == false); 1217 1218 // missing/unexpected end of string 1219 CHECK(accept_helper("\"") == false); 1220 CHECK(accept_helper("\"\\\"") == false); 1221 CHECK(accept_helper("\"\\u\"") == false); 1222 CHECK(accept_helper("\"\\u0\"") == false); 1223 CHECK(accept_helper("\"\\u01\"") == false); 1224 CHECK(accept_helper("\"\\u012\"") == false); 1225 CHECK(accept_helper("\"\\u") == false); 1226 CHECK(accept_helper("\"\\u0") == false); 1227 CHECK(accept_helper("\"\\u01") == false); 1228 CHECK(accept_helper("\"\\u012") == false); 1229 1230 // unget of newline 1231 CHECK(parser_helper("\n123\n") == 123); 1232 1233 // invalid escapes 1234 for (int c = 1; c < 128; ++c) 1235 { 1236 auto s = std::string("\"\\") + std::string(1, static_cast<char>(c)) + "\""; 1237 1238 switch (c) 1239 { 1240 // valid escapes 1241 case ('"'): 1242 case ('\\'): 1243 case ('/'): 1244 case ('b'): 1245 case ('f'): 1246 case ('n'): 1247 case ('r'): 1248 case ('t'): 1249 { 1250 CHECK(json::parser(nlohmann::detail::input_adapter(s)).accept()); 1251 break; 1252 } 1253 1254 // \u must be followed with four numbers, so we skip it here 1255 case ('u'): 1256 { 1257 break; 1258 } 1259 1260 // any other combination of backslash and character is invalid 1261 default: 1262 { 1263 CHECK(json::parser(nlohmann::detail::input_adapter(s)).accept() == false); 1264 break; 1265 } 1266 } 1267 } 1268 1269 // invalid \uxxxx escapes 1270 { 1271 // check whether character is a valid hex character 1272 const auto valid = [](int c) 1273 { 1274 switch (c) 1275 { 1276 case ('0'): 1277 case ('1'): 1278 case ('2'): 1279 case ('3'): 1280 case ('4'): 1281 case ('5'): 1282 case ('6'): 1283 case ('7'): 1284 case ('8'): 1285 case ('9'): 1286 case ('a'): 1287 case ('b'): 1288 case ('c'): 1289 case ('d'): 1290 case ('e'): 1291 case ('f'): 1292 case ('A'): 1293 case ('B'): 1294 case ('C'): 1295 case ('D'): 1296 case ('E'): 1297 case ('F'): 1298 { 1299 return true; 1300 } 1301 1302 default: 1303 { 1304 return false; 1305 } 1306 } 1307 }; 1308 1309 for (int c = 1; c < 128; ++c) 1310 { 1311 std::string s = "\"\\u"; 1312 1313 // create a string with the iterated character at each position 1314 const auto s1 = s + "000" + std::string(1, static_cast<char>(c)) + "\""; 1315 const auto s2 = s + "00" + std::string(1, static_cast<char>(c)) + "0\""; 1316 const auto s3 = s + "0" + std::string(1, static_cast<char>(c)) + "00\""; 1317 const auto s4 = s + std::string(1, static_cast<char>(c)) + "000\""; 1318 1319 if (valid(c)) 1320 { 1321 CAPTURE(s1) 1322 CHECK(json::parser(nlohmann::detail::input_adapter(s1)).accept()); 1323 CAPTURE(s2) 1324 CHECK(json::parser(nlohmann::detail::input_adapter(s2)).accept()); 1325 CAPTURE(s3) 1326 CHECK(json::parser(nlohmann::detail::input_adapter(s3)).accept()); 1327 CAPTURE(s4) 1328 CHECK(json::parser(nlohmann::detail::input_adapter(s4)).accept()); 1329 } 1330 else 1331 { 1332 CAPTURE(s1) 1333 CHECK(json::parser(nlohmann::detail::input_adapter(s1)).accept() == false); 1334 1335 CAPTURE(s2) 1336 CHECK(json::parser(nlohmann::detail::input_adapter(s2)).accept() == false); 1337 1338 CAPTURE(s3) 1339 CHECK(json::parser(nlohmann::detail::input_adapter(s3)).accept() == false); 1340 1341 CAPTURE(s4) 1342 CHECK(json::parser(nlohmann::detail::input_adapter(s4)).accept() == false); 1343 } 1344 } 1345 } 1346 1347 // missing part of a surrogate pair 1348 CHECK(accept_helper("\"\\uD80C\"") == false); 1349 // invalid surrogate pair 1350 CHECK(accept_helper("\"\\uD80C\\uD80C\"") == false); 1351 CHECK(accept_helper("\"\\uD80C\\u0000\"") == false); 1352 CHECK(accept_helper("\"\\uD80C\\uFFFF\"") == false); 1353 } 1354 1355 SECTION("tests found by mutate++") 1356 { 1357 // test case to make sure no comma precedes the first key 1358 CHECK_THROWS_WITH_AS(parser_helper("{,\"key\": false}"), "[json.exception.parse_error.101] parse error at line 1, column 2: syntax error while parsing object key - unexpected ','; expected string literal", json::parse_error&); 1359 // test case to make sure an object is properly closed 1360 CHECK_THROWS_WITH_AS(parser_helper("[{\"key\": false true]"), "[json.exception.parse_error.101] parse error at line 1, column 19: syntax error while parsing object - unexpected true literal; expected '}'", json::parse_error&); 1361 1362 // test case to make sure the callback is properly evaluated after reading a key 1363 { 1364 json::parser_callback_t cb = [](int /*unused*/, json::parse_event_t event, json& /*unused*/) noexcept 1365 { 1366 return event != json::parse_event_t::key; 1367 }; 1368 1369 json x = json::parse("{\"key\": false}", cb); 1370 CHECK(x == json::object()); 1371 } 1372 } 1373 1374 SECTION("callback function") 1375 { 1376 const auto* s_object = R"( 1377 { 1378 "foo": 2, 1379 "bar": { 1380 "baz": 1 1381 } 1382 } 1383 )"; 1384 1385 const auto* s_array = R"( 1386 [1,2,[3,4,5],4,5] 1387 )"; 1388 1389 const auto* structured_array = R"( 1390 [ 1391 1, 1392 { 1393 "foo": "bar" 1394 }, 1395 { 1396 "qux": "baz" 1397 } 1398 ] 1399 )"; 1400 1401 SECTION("filter nothing") 1402 { 1403 json j_object = json::parse(s_object, [](int /*unused*/, json::parse_event_t /*unused*/, const json& /*unused*/) noexcept 1404 { 1405 return true; 1406 }); 1407 1408 CHECK (j_object == json({{"foo", 2}, {"bar", {{"baz", 1}}}})); 1409 1410 json j_array = json::parse(s_array, [](int /*unused*/, json::parse_event_t /*unused*/, const json& /*unused*/) noexcept 1411 { 1412 return true; 1413 }); 1414 1415 CHECK (j_array == json({1, 2, {3, 4, 5}, 4, 5})); 1416 } 1417 1418 SECTION("filter everything") 1419 { 1420 json j_object = json::parse(s_object, [](int /*unused*/, json::parse_event_t /*unused*/, const json& /*unused*/) noexcept 1421 { 1422 return false; 1423 }); 1424 1425 // the top-level object will be discarded, leaving a null 1426 CHECK (j_object.is_null()); 1427 1428 json j_array = json::parse(s_array, [](int /*unused*/, json::parse_event_t /*unused*/, const json& /*unused*/) noexcept 1429 { 1430 return false; 1431 }); 1432 1433 // the top-level array will be discarded, leaving a null 1434 CHECK (j_array.is_null()); 1435 } 1436 1437 SECTION("filter specific element") 1438 { 1439 json j_object = json::parse(s_object, [](int /*unused*/, json::parse_event_t event, const json & j) noexcept 1440 { 1441 // filter all number(2) elements 1442 return event != json::parse_event_t::value || j != json(2); 1443 }); 1444 1445 CHECK (j_object == json({{"bar", {{"baz", 1}}}})); 1446 1447 json j_array = json::parse(s_array, [](int /*unused*/, json::parse_event_t event, const json & j) noexcept 1448 { 1449 return event != json::parse_event_t::value || j != json(2); 1450 }); 1451 1452 CHECK (j_array == json({1, {3, 4, 5}, 4, 5})); 1453 } 1454 1455 SECTION("filter object in array") 1456 { 1457 json j_filtered1 = json::parse(structured_array, [](int /*unused*/, json::parse_event_t e, const json & parsed) 1458 { 1459 return !(e == json::parse_event_t::object_end && parsed.contains("foo")); 1460 }); 1461 1462 // the specified object will be discarded, and removed. 1463 CHECK (j_filtered1.size() == 2); 1464 CHECK (j_filtered1 == json({1, {{"qux", "baz"}}})); 1465 1466 json j_filtered2 = json::parse(structured_array, [](int /*unused*/, json::parse_event_t e, const json& /*parsed*/) noexcept 1467 { 1468 return e != json::parse_event_t::object_end; 1469 }); 1470 1471 // removed all objects in array. 1472 CHECK (j_filtered2.size() == 1); 1473 CHECK (j_filtered2 == json({1})); 1474 } 1475 1476 SECTION("filter specific events") 1477 { 1478 SECTION("first closing event") 1479 { 1480 { 1481 json j_object = json::parse(s_object, [](int /*unused*/, json::parse_event_t e, const json& /*unused*/) noexcept 1482 { 1483 static bool first = true; 1484 if (e == json::parse_event_t::object_end && first) 1485 { 1486 first = false; 1487 return false; 1488 } 1489 1490 return true; 1491 }); 1492 1493 // the first completed object will be discarded 1494 CHECK (j_object == json({{"foo", 2}})); 1495 } 1496 1497 { 1498 json j_array = json::parse(s_array, [](int /*unused*/, json::parse_event_t e, const json& /*unused*/) noexcept 1499 { 1500 static bool first = true; 1501 if (e == json::parse_event_t::array_end && first) 1502 { 1503 first = false; 1504 return false; 1505 } 1506 1507 return true; 1508 }); 1509 1510 // the first completed array will be discarded 1511 CHECK (j_array == json({1, 2, 4, 5})); 1512 } 1513 } 1514 } 1515 1516 SECTION("special cases") 1517 { 1518 // the following test cases cover the situation in which an empty 1519 // object and array is discarded only after the closing character 1520 // has been read 1521 1522 json j_empty_object = json::parse("{}", [](int /*unused*/, json::parse_event_t e, const json& /*unused*/) noexcept 1523 { 1524 return e != json::parse_event_t::object_end; 1525 }); 1526 CHECK(j_empty_object == json()); 1527 1528 json j_empty_array = json::parse("[]", [](int /*unused*/, json::parse_event_t e, const json& /*unused*/) noexcept 1529 { 1530 return e != json::parse_event_t::array_end; 1531 }); 1532 CHECK(j_empty_array == json()); 1533 } 1534 } 1535 1536 SECTION("constructing from contiguous containers") 1537 { 1538 SECTION("from std::vector") 1539 { 1540 std::vector<uint8_t> v = {'t', 'r', 'u', 'e'}; 1541 json j; 1542 json::parser(nlohmann::detail::input_adapter(std::begin(v), std::end(v))).parse(true, j); 1543 CHECK(j == json(true)); 1544 } 1545 1546 SECTION("from std::array") 1547 { 1548 std::array<uint8_t, 5> v { {'t', 'r', 'u', 'e'} }; 1549 json j; 1550 json::parser(nlohmann::detail::input_adapter(std::begin(v), std::end(v))).parse(true, j); 1551 CHECK(j == json(true)); 1552 } 1553 1554 SECTION("from array") 1555 { 1556 uint8_t v[] = {'t', 'r', 'u', 'e'}; // NOLINT(cppcoreguidelines-avoid-c-arrays,hicpp-avoid-c-arrays,modernize-avoid-c-arrays) 1557 json j; 1558 json::parser(nlohmann::detail::input_adapter(std::begin(v), std::end(v))).parse(true, j); 1559 CHECK(j == json(true)); 1560 } 1561 1562 SECTION("from char literal") 1563 { 1564 CHECK(parser_helper("true") == json(true)); 1565 } 1566 1567 SECTION("from std::string") 1568 { 1569 std::string v = {'t', 'r', 'u', 'e'}; 1570 json j; 1571 json::parser(nlohmann::detail::input_adapter(std::begin(v), std::end(v))).parse(true, j); 1572 CHECK(j == json(true)); 1573 } 1574 1575 SECTION("from std::initializer_list") 1576 { 1577 std::initializer_list<uint8_t> v = {'t', 'r', 'u', 'e'}; 1578 json j; 1579 json::parser(nlohmann::detail::input_adapter(std::begin(v), std::end(v))).parse(true, j); 1580 CHECK(j == json(true)); 1581 } 1582 1583 SECTION("from std::valarray") 1584 { 1585 std::valarray<uint8_t> v = {'t', 'r', 'u', 'e'}; 1586 json j; 1587 json::parser(nlohmann::detail::input_adapter(std::begin(v), std::end(v))).parse(true, j); 1588 CHECK(j == json(true)); 1589 } 1590 } 1591 1592 SECTION("improve test coverage") 1593 { 1594 SECTION("parser with callback") 1595 { 1596 json::parser_callback_t cb = [](int /*unused*/, json::parse_event_t /*unused*/, json& /*unused*/) noexcept 1597 { 1598 return true; 1599 }; 1600 1601 CHECK(json::parse("{\"foo\": true:", cb, false).is_discarded()); 1602 1603 json _; 1604 CHECK_THROWS_WITH_AS(_ = json::parse("{\"foo\": true:", cb), "[json.exception.parse_error.101] parse error at line 1, column 13: syntax error while parsing object - unexpected ':'; expected '}'", json::parse_error&); 1605 1606 CHECK_THROWS_WITH_AS(_ = json::parse("1.18973e+4932", cb), "[json.exception.out_of_range.406] number overflow parsing '1.18973e+4932'", json::out_of_range&); 1607 } 1608 1609 SECTION("SAX parser") 1610 { 1611 SECTION("} without value") 1612 { 1613 SaxCountdown s(1); 1614 CHECK(json::sax_parse("{}", &s) == false); 1615 } 1616 1617 SECTION("} with value") 1618 { 1619 SaxCountdown s(3); 1620 CHECK(json::sax_parse("{\"k1\": true}", &s) == false); 1621 } 1622 1623 SECTION("second key") 1624 { 1625 SaxCountdown s(3); 1626 CHECK(json::sax_parse("{\"k1\": true, \"k2\": false}", &s) == false); 1627 } 1628 1629 SECTION("] without value") 1630 { 1631 SaxCountdown s(1); 1632 CHECK(json::sax_parse("[]", &s) == false); 1633 } 1634 1635 SECTION("] with value") 1636 { 1637 SaxCountdown s(2); 1638 CHECK(json::sax_parse("[1]", &s) == false); 1639 } 1640 1641 SECTION("float") 1642 { 1643 SaxCountdown s(0); 1644 CHECK(json::sax_parse("3.14", &s) == false); 1645 } 1646 1647 SECTION("false") 1648 { 1649 SaxCountdown s(0); 1650 CHECK(json::sax_parse("false", &s) == false); 1651 } 1652 1653 SECTION("null") 1654 { 1655 SaxCountdown s(0); 1656 CHECK(json::sax_parse("null", &s) == false); 1657 } 1658 1659 SECTION("true") 1660 { 1661 SaxCountdown s(0); 1662 CHECK(json::sax_parse("true", &s) == false); 1663 } 1664 1665 SECTION("unsigned") 1666 { 1667 SaxCountdown s(0); 1668 CHECK(json::sax_parse("12", &s) == false); 1669 } 1670 1671 SECTION("integer") 1672 { 1673 SaxCountdown s(0); 1674 CHECK(json::sax_parse("-12", &s) == false); 1675 } 1676 1677 SECTION("string") 1678 { 1679 SaxCountdown s(0); 1680 CHECK(json::sax_parse("\"foo\"", &s) == false); 1681 } 1682 } 1683 } 1684 1685 SECTION("error messages for comments") 1686 { 1687 json _; 1688 CHECK_THROWS_WITH_AS(_ = json::parse("/a", nullptr, true, true), "[json.exception.parse_error.101] parse error at line 1, column 2: syntax error while parsing value - invalid comment; expecting '/' or '*' after '/'; last read: '/a'", json::parse_error); 1689 CHECK_THROWS_WITH_AS(_ = json::parse("/*", nullptr, true, true), "[json.exception.parse_error.101] parse error at line 1, column 3: syntax error while parsing value - invalid comment; missing closing '*/'; last read: '/*<U+0000>'", json::parse_error); 1690 } 1691} 1692