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 #include <nlohmann/json.hpp> 12 using nlohmann::json; 13 14 #include <fstream> 15 #include <sstream> 16 #include "make_test_data_available.hpp" 17 #include "test_utils.hpp" 18 19 TEST_CASE("BSON") 20 { 21 SECTION("individual values not supported") 22 { 23 SECTION("null") 24 { 25 json j = nullptr; 26 CHECK_THROWS_WITH_AS(json::to_bson(j), "[json.exception.type_error.317] to serialize to BSON, top-level type must be object, but is null", json::type_error&); 27 } 28 29 SECTION("boolean") 30 { 31 SECTION("true") 32 { 33 json j = true; 34 CHECK_THROWS_WITH_AS(json::to_bson(j), "[json.exception.type_error.317] to serialize to BSON, top-level type must be object, but is boolean", json::type_error&); 35 } 36 37 SECTION("false") 38 { 39 json j = false; 40 CHECK_THROWS_WITH_AS(json::to_bson(j), "[json.exception.type_error.317] to serialize to BSON, top-level type must be object, but is boolean", json::type_error&); 41 } 42 } 43 44 SECTION("number") 45 { 46 json j = 42; 47 CHECK_THROWS_WITH_AS(json::to_bson(j), "[json.exception.type_error.317] to serialize to BSON, top-level type must be object, but is number", json::type_error&); 48 } 49 50 SECTION("float") 51 { 52 json j = 4.2; 53 CHECK_THROWS_WITH_AS(json::to_bson(j), "[json.exception.type_error.317] to serialize to BSON, top-level type must be object, but is number", json::type_error&); 54 } 55 56 SECTION("string") 57 { 58 json j = "not supported"; 59 CHECK_THROWS_WITH_AS(json::to_bson(j), "[json.exception.type_error.317] to serialize to BSON, top-level type must be object, but is string", json::type_error&); 60 } 61 62 SECTION("array") 63 { 64 json j = std::vector<int> {1, 2, 3, 4, 5, 6, 7}; 65 CHECK_THROWS_WITH_AS(json::to_bson(j), "[json.exception.type_error.317] to serialize to BSON, top-level type must be object, but is array", json::type_error&); 66 } 67 } 68 69 SECTION("keys containing code-point U+0000 cannot be serialized to BSON") 70 { 71 json j = 72 { 73 { std::string("en\0try", 6), true } 74 }; 75 #if JSON_DIAGNOSTICS 76 CHECK_THROWS_WITH_AS(json::to_bson(j), "[json.exception.out_of_range.409] (/en) BSON key cannot contain code point U+0000 (at byte 2)", json::out_of_range&); 77 #else 78 CHECK_THROWS_WITH_AS(json::to_bson(j), "[json.exception.out_of_range.409] BSON key cannot contain code point U+0000 (at byte 2)", json::out_of_range&); 79 #endif 80 } 81 82 SECTION("string length must be at least 1") 83 { 84 // from https://bugs.chromium.org/p/oss-fuzz/issues/detail?id=11175 85 std::vector<std::uint8_t> v = 86 { 87 0x20, 0x20, 0x20, 0x20, 88 0x02, 89 0x00, 90 0x00, 0x00, 0x00, 0x80 91 }; 92 json _; 93 CHECK_THROWS_WITH_AS(_ = json::from_bson(v), "[json.exception.parse_error.112] parse error at byte 10: syntax error while parsing BSON string: string length must be at least 1, is -2147483648", json::parse_error&); 94 } 95 96 SECTION("objects") 97 { 98 SECTION("empty object") 99 { 100 json j = json::object(); 101 std::vector<std::uint8_t> expected = 102 { 103 0x05, 0x00, 0x00, 0x00, // size (little endian) 104 // no entries 105 0x00 // end marker 106 }; 107 108 const auto result = json::to_bson(j); 109 CHECK(result == expected); 110 111 // roundtrip 112 CHECK(json::from_bson(result) == j); 113 CHECK(json::from_bson(result, true, false) == j); 114 } 115 116 SECTION("non-empty object with bool") 117 { 118 json j = 119 { 120 { "entry", true } 121 }; 122 123 std::vector<std::uint8_t> expected = 124 { 125 0x0D, 0x00, 0x00, 0x00, // size (little endian) 126 0x08, // entry: boolean 127 'e', 'n', 't', 'r', 'y', '\x00', 128 0x01, // value = true 129 0x00 // end marker 130 }; 131 132 const auto result = json::to_bson(j); 133 CHECK(result == expected); 134 135 // roundtrip 136 CHECK(json::from_bson(result) == j); 137 CHECK(json::from_bson(result, true, false) == j); 138 } 139 140 SECTION("non-empty object with bool") 141 { 142 json j = 143 { 144 { "entry", false } 145 }; 146 147 std::vector<std::uint8_t> expected = 148 { 149 0x0D, 0x00, 0x00, 0x00, // size (little endian) 150 0x08, // entry: boolean 151 'e', 'n', 't', 'r', 'y', '\x00', 152 0x00, // value = false 153 0x00 // end marker 154 }; 155 156 const auto result = json::to_bson(j); 157 CHECK(result == expected); 158 159 // roundtrip 160 CHECK(json::from_bson(result) == j); 161 CHECK(json::from_bson(result, true, false) == j); 162 } 163 164 SECTION("non-empty object with double") 165 { 166 json j = 167 { 168 { "entry", 4.2 } 169 }; 170 171 std::vector<std::uint8_t> expected = 172 { 173 0x14, 0x00, 0x00, 0x00, // size (little endian) 174 0x01, /// entry: double 175 'e', 'n', 't', 'r', 'y', '\x00', 176 0xcd, 0xcc, 0xcc, 0xcc, 0xcc, 0xcc, 0x10, 0x40, 177 0x00 // end marker 178 }; 179 180 const auto result = json::to_bson(j); 181 CHECK(result == expected); 182 183 // roundtrip 184 CHECK(json::from_bson(result) == j); 185 CHECK(json::from_bson(result, true, false) == j); 186 } 187 188 SECTION("non-empty object with string") 189 { 190 json j = 191 { 192 { "entry", "bsonstr" } 193 }; 194 195 std::vector<std::uint8_t> expected = 196 { 197 0x18, 0x00, 0x00, 0x00, // size (little endian) 198 0x02, /// entry: string (UTF-8) 199 'e', 'n', 't', 'r', 'y', '\x00', 200 0x08, 0x00, 0x00, 0x00, 'b', 's', 'o', 'n', 's', 't', 'r', '\x00', 201 0x00 // end marker 202 }; 203 204 const auto result = json::to_bson(j); 205 CHECK(result == expected); 206 207 // roundtrip 208 CHECK(json::from_bson(result) == j); 209 CHECK(json::from_bson(result, true, false) == j); 210 } 211 212 SECTION("non-empty object with null member") 213 { 214 json j = 215 { 216 { "entry", nullptr } 217 }; 218 219 std::vector<std::uint8_t> expected = 220 { 221 0x0C, 0x00, 0x00, 0x00, // size (little endian) 222 0x0A, /// entry: null 223 'e', 'n', 't', 'r', 'y', '\x00', 224 0x00 // end marker 225 }; 226 227 const auto result = json::to_bson(j); 228 CHECK(result == expected); 229 230 // roundtrip 231 CHECK(json::from_bson(result) == j); 232 CHECK(json::from_bson(result, true, false) == j); 233 } 234 235 SECTION("non-empty object with integer (32-bit) member") 236 { 237 json j = 238 { 239 { "entry", std::int32_t{0x12345678} } 240 }; 241 242 std::vector<std::uint8_t> expected = 243 { 244 0x10, 0x00, 0x00, 0x00, // size (little endian) 245 0x10, /// entry: int32 246 'e', 'n', 't', 'r', 'y', '\x00', 247 0x78, 0x56, 0x34, 0x12, 248 0x00 // end marker 249 }; 250 251 const auto result = json::to_bson(j); 252 CHECK(result == expected); 253 254 // roundtrip 255 CHECK(json::from_bson(result) == j); 256 CHECK(json::from_bson(result, true, false) == j); 257 } 258 259 SECTION("non-empty object with integer (64-bit) member") 260 { 261 json j = 262 { 263 { "entry", std::int64_t{0x1234567804030201} } 264 }; 265 266 std::vector<std::uint8_t> expected = 267 { 268 0x14, 0x00, 0x00, 0x00, // size (little endian) 269 0x12, /// entry: int64 270 'e', 'n', 't', 'r', 'y', '\x00', 271 0x01, 0x02, 0x03, 0x04, 0x78, 0x56, 0x34, 0x12, 272 0x00 // end marker 273 }; 274 275 const auto result = json::to_bson(j); 276 CHECK(result == expected); 277 278 // roundtrip 279 CHECK(json::from_bson(result) == j); 280 CHECK(json::from_bson(result, true, false) == j); 281 } 282 283 SECTION("non-empty object with negative integer (32-bit) member") 284 { 285 json j = 286 { 287 { "entry", std::int32_t{-1} } 288 }; 289 290 std::vector<std::uint8_t> expected = 291 { 292 0x10, 0x00, 0x00, 0x00, // size (little endian) 293 0x10, /// entry: int32 294 'e', 'n', 't', 'r', 'y', '\x00', 295 0xFF, 0xFF, 0xFF, 0xFF, 296 0x00 // end marker 297 }; 298 299 const auto result = json::to_bson(j); 300 CHECK(result == expected); 301 302 // roundtrip 303 CHECK(json::from_bson(result) == j); 304 CHECK(json::from_bson(result, true, false) == j); 305 } 306 307 SECTION("non-empty object with negative integer (64-bit) member") 308 { 309 json j = 310 { 311 { "entry", std::int64_t{-1} } 312 }; 313 314 std::vector<std::uint8_t> expected = 315 { 316 0x10, 0x00, 0x00, 0x00, // size (little endian) 317 0x10, /// entry: int32 318 'e', 'n', 't', 'r', 'y', '\x00', 319 0xFF, 0xFF, 0xFF, 0xFF, 320 0x00 // end marker 321 }; 322 323 const auto result = json::to_bson(j); 324 CHECK(result == expected); 325 326 // roundtrip 327 CHECK(json::from_bson(result) == j); 328 CHECK(json::from_bson(result, true, false) == j); 329 } 330 331 SECTION("non-empty object with unsigned integer (64-bit) member") 332 { 333 // directly encoding uint64 is not supported in bson (only for timestamp values) 334 json j = 335 { 336 { "entry", std::uint64_t{0x1234567804030201} } 337 }; 338 339 std::vector<std::uint8_t> expected = 340 { 341 0x14, 0x00, 0x00, 0x00, // size (little endian) 342 0x12, /// entry: int64 343 'e', 'n', 't', 'r', 'y', '\x00', 344 0x01, 0x02, 0x03, 0x04, 0x78, 0x56, 0x34, 0x12, 345 0x00 // end marker 346 }; 347 348 const auto result = json::to_bson(j); 349 CHECK(result == expected); 350 351 // roundtrip 352 CHECK(json::from_bson(result) == j); 353 CHECK(json::from_bson(result, true, false) == j); 354 } 355 356 SECTION("non-empty object with small unsigned integer member") 357 { 358 json j = 359 { 360 { "entry", std::uint64_t{0x42} } 361 }; 362 363 std::vector<std::uint8_t> expected = 364 { 365 0x10, 0x00, 0x00, 0x00, // size (little endian) 366 0x10, /// entry: int32 367 'e', 'n', 't', 'r', 'y', '\x00', 368 0x42, 0x00, 0x00, 0x00, 369 0x00 // end marker 370 }; 371 372 const auto result = json::to_bson(j); 373 CHECK(result == expected); 374 375 // roundtrip 376 CHECK(json::from_bson(result) == j); 377 CHECK(json::from_bson(result, true, false) == j); 378 } 379 380 SECTION("non-empty object with object member") 381 { 382 json j = 383 { 384 { "entry", json::object() } 385 }; 386 387 std::vector<std::uint8_t> expected = 388 { 389 0x11, 0x00, 0x00, 0x00, // size (little endian) 390 0x03, /// entry: embedded document 391 'e', 'n', 't', 'r', 'y', '\x00', 392 393 0x05, 0x00, 0x00, 0x00, // size (little endian) 394 // no entries 395 0x00, // end marker (embedded document) 396 397 0x00 // end marker 398 }; 399 400 const auto result = json::to_bson(j); 401 CHECK(result == expected); 402 403 // roundtrip 404 CHECK(json::from_bson(result) == j); 405 CHECK(json::from_bson(result, true, false) == j); 406 } 407 408 SECTION("non-empty object with array member") 409 { 410 json j = 411 { 412 { "entry", json::array() } 413 }; 414 415 std::vector<std::uint8_t> expected = 416 { 417 0x11, 0x00, 0x00, 0x00, // size (little endian) 418 0x04, /// entry: embedded document 419 'e', 'n', 't', 'r', 'y', '\x00', 420 421 0x05, 0x00, 0x00, 0x00, // size (little endian) 422 // no entries 423 0x00, // end marker (embedded document) 424 425 0x00 // end marker 426 }; 427 428 const auto result = json::to_bson(j); 429 CHECK(result == expected); 430 431 // roundtrip 432 CHECK(json::from_bson(result) == j); 433 CHECK(json::from_bson(result, true, false) == j); 434 } 435 436 SECTION("non-empty object with non-empty array member") 437 { 438 json j = 439 { 440 { "entry", json::array({1, 2, 3, 4, 5, 6, 7, 8}) } 441 }; 442 443 std::vector<std::uint8_t> expected = 444 { 445 0x49, 0x00, 0x00, 0x00, // size (little endian) 446 0x04, /// entry: embedded document 447 'e', 'n', 't', 'r', 'y', '\x00', 448 449 0x3D, 0x00, 0x00, 0x00, // size (little endian) 450 0x10, '0', 0x00, 0x01, 0x00, 0x00, 0x00, 451 0x10, '1', 0x00, 0x02, 0x00, 0x00, 0x00, 452 0x10, '2', 0x00, 0x03, 0x00, 0x00, 0x00, 453 0x10, '3', 0x00, 0x04, 0x00, 0x00, 0x00, 454 0x10, '4', 0x00, 0x05, 0x00, 0x00, 0x00, 455 0x10, '5', 0x00, 0x06, 0x00, 0x00, 0x00, 456 0x10, '6', 0x00, 0x07, 0x00, 0x00, 0x00, 457 0x10, '7', 0x00, 0x08, 0x00, 0x00, 0x00, 458 0x00, // end marker (embedded document) 459 460 0x00 // end marker 461 }; 462 463 const auto result = json::to_bson(j); 464 CHECK(result == expected); 465 466 // roundtrip 467 CHECK(json::from_bson(result) == j); 468 CHECK(json::from_bson(result, true, false) == j); 469 } 470 471 SECTION("non-empty object with binary member") 472 { 473 const size_t N = 10; 474 const auto s = std::vector<std::uint8_t>(N, 'x'); 475 json j = 476 { 477 { "entry", json::binary(s, 0) } 478 }; 479 480 std::vector<std::uint8_t> expected = 481 { 482 0x1B, 0x00, 0x00, 0x00, // size (little endian) 483 0x05, // entry: binary 484 'e', 'n', 't', 'r', 'y', '\x00', 485 486 0x0A, 0x00, 0x00, 0x00, // size of binary (little endian) 487 0x00, // Generic binary subtype 488 0x78, 0x78, 0x78, 0x78, 0x78, 0x78, 0x78, 0x78, 0x78, 0x78, 489 490 0x00 // end marker 491 }; 492 493 const auto result = json::to_bson(j); 494 CHECK(result == expected); 495 496 // roundtrip 497 CHECK(json::from_bson(result) == j); 498 CHECK(json::from_bson(result, true, false) == j); 499 } 500 501 SECTION("non-empty object with binary member with subtype") 502 { 503 // an MD5 hash 504 const std::vector<std::uint8_t> md5hash = {0xd7, 0x7e, 0x27, 0x54, 0xbe, 0x12, 0x37, 0xfe, 0xd6, 0x0c, 0x33, 0x98, 0x30, 0x3b, 0x8d, 0xc4}; 505 json j = 506 { 507 { "entry", json::binary(md5hash, 5) } 508 }; 509 510 std::vector<std::uint8_t> expected = 511 { 512 0x21, 0x00, 0x00, 0x00, // size (little endian) 513 0x05, // entry: binary 514 'e', 'n', 't', 'r', 'y', '\x00', 515 516 0x10, 0x00, 0x00, 0x00, // size of binary (little endian) 517 0x05, // MD5 binary subtype 518 0xd7, 0x7e, 0x27, 0x54, 0xbe, 0x12, 0x37, 0xfe, 0xd6, 0x0c, 0x33, 0x98, 0x30, 0x3b, 0x8d, 0xc4, 519 520 0x00 // end marker 521 }; 522 523 const auto result = json::to_bson(j); 524 CHECK(result == expected); 525 526 // roundtrip 527 CHECK(json::from_bson(result) == j); 528 CHECK(json::from_bson(result, true, false) == j); 529 } 530 531 SECTION("Some more complex document") 532 { 533 // directly encoding uint64 is not supported in bson (only for timestamp values) 534 json j = 535 { 536 {"double", 42.5}, 537 {"entry", 4.2}, 538 {"number", 12345}, 539 {"object", {{ "string", "value" }}} 540 }; 541 542 std::vector<std::uint8_t> expected = 543 { 544 /*size */ 0x4f, 0x00, 0x00, 0x00, 545 /*entry*/ 0x01, 'd', 'o', 'u', 'b', 'l', 'e', 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x40, 0x45, 0x40, 546 /*entry*/ 0x01, 'e', 'n', 't', 'r', 'y', 0x00, 0xcd, 0xcc, 0xcc, 0xcc, 0xcc, 0xcc, 0x10, 0x40, 547 /*entry*/ 0x10, 'n', 'u', 'm', 'b', 'e', 'r', 0x00, 0x39, 0x30, 0x00, 0x00, 548 /*entry*/ 0x03, 'o', 'b', 'j', 'e', 'c', 't', 0x00, 549 /*entry: obj-size */ 0x17, 0x00, 0x00, 0x00, 550 /*entry: obj-entry*/0x02, 's', 't', 'r', 'i', 'n', 'g', 0x00, 0x06, 0x00, 0x00, 0x00, 'v', 'a', 'l', 'u', 'e', 0, 551 /*entry: obj-term.*/0x00, 552 /*obj-term*/ 0x00 553 }; 554 555 const auto result = json::to_bson(j); 556 CHECK(result == expected); 557 558 // roundtrip 559 CHECK(json::from_bson(result) == j); 560 CHECK(json::from_bson(result, true, false) == j); 561 } 562 } 563 564 SECTION("Examples from http://bsonspec.org/faq.html") 565 { 566 SECTION("Example 1") 567 { 568 std::vector<std::uint8_t> input = {0x16, 0x00, 0x00, 0x00, 0x02, 'h', 'e', 'l', 'l', 'o', 0x00, 0x06, 0x00, 0x00, 0x00, 'w', 'o', 'r', 'l', 'd', 0x00, 0x00}; 569 json parsed = json::from_bson(input); 570 json expected = {{"hello", "world"}}; 571 CHECK(parsed == expected); 572 auto dumped = json::to_bson(parsed); 573 CHECK(dumped == input); 574 CHECK(json::from_bson(dumped) == expected); 575 } 576 577 SECTION("Example 2") 578 { 579 std::vector<std::uint8_t> input = {0x31, 0x00, 0x00, 0x00, 0x04, 'B', 'S', 'O', 'N', 0x00, 0x26, 0x00, 0x00, 0x00, 0x02, 0x30, 0x00, 0x08, 0x00, 0x00, 0x00, 'a', 'w', 'e', 's', 'o', 'm', 'e', 0x00, 0x01, 0x31, 0x00, 0x33, 0x33, 0x33, 0x33, 0x33, 0x33, 0x14, 0x40, 0x10, 0x32, 0x00, 0xc2, 0x07, 0x00, 0x00, 0x00, 0x00}; 580 json parsed = json::from_bson(input); 581 json expected = {{"BSON", {"awesome", 5.05, 1986}}}; 582 CHECK(parsed == expected); 583 auto dumped = json::to_bson(parsed); 584 CHECK(dumped == input); 585 CHECK(json::from_bson(dumped) == expected); 586 } 587 } 588 } 589 590 TEST_CASE("BSON input/output_adapters") 591 { 592 json json_representation = 593 { 594 {"double", 42.5}, 595 {"entry", 4.2}, 596 {"number", 12345}, 597 {"object", {{ "string", "value" }}} 598 }; 599 600 std::vector<std::uint8_t> bson_representation = 601 { 602 /*size */ 0x4f, 0x00, 0x00, 0x00, 603 /*entry*/ 0x01, 'd', 'o', 'u', 'b', 'l', 'e', 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x40, 0x45, 0x40, 604 /*entry*/ 0x01, 'e', 'n', 't', 'r', 'y', 0x00, 0xcd, 0xcc, 0xcc, 0xcc, 0xcc, 0xcc, 0x10, 0x40, 605 /*entry*/ 0x10, 'n', 'u', 'm', 'b', 'e', 'r', 0x00, 0x39, 0x30, 0x00, 0x00, 606 /*entry*/ 0x03, 'o', 'b', 'j', 'e', 'c', 't', 0x00, 607 /*entry: obj-size */ 0x17, 0x00, 0x00, 0x00, 608 /*entry: obj-entry*/0x02, 's', 't', 'r', 'i', 'n', 'g', 0x00, 0x06, 0x00, 0x00, 0x00, 'v', 'a', 'l', 'u', 'e', 0, 609 /*entry: obj-term.*/0x00, 610 /*obj-term*/ 0x00 611 }; 612 613 json j2; 614 CHECK_NOTHROW(j2 = json::from_bson(bson_representation)); 615 616 // compare parsed JSON values 617 CHECK(json_representation == j2); 618 619 SECTION("roundtrips") 620 { 621 SECTION("std::ostringstream") 622 { 623 std::basic_ostringstream<std::uint8_t> ss; 624 json::to_bson(json_representation, ss); 625 json j3 = json::from_bson(ss.str()); 626 CHECK(json_representation == j3); 627 } 628 629 SECTION("std::string") 630 { 631 std::string s; 632 json::to_bson(json_representation, s); 633 json j3 = json::from_bson(s); 634 CHECK(json_representation == j3); 635 } 636 637 SECTION("std::vector") 638 { 639 std::vector<std::uint8_t> v; 640 json::to_bson(json_representation, v); 641 json j3 = json::from_bson(v); 642 CHECK(json_representation == j3); 643 } 644 } 645 } 646 647 namespace 648 { 649 class SaxCountdown 650 { 651 public: SaxCountdown(const int count)652 explicit SaxCountdown(const int count) : events_left(count) 653 {} 654 null()655 bool null() 656 { 657 return events_left-- > 0; 658 } 659 boolean(bool )660 bool boolean(bool /*unused*/) 661 { 662 return events_left-- > 0; 663 } 664 number_integer(json::number_integer_t )665 bool number_integer(json::number_integer_t /*unused*/) 666 { 667 return events_left-- > 0; 668 } 669 number_unsigned(json::number_unsigned_t )670 bool number_unsigned(json::number_unsigned_t /*unused*/) 671 { 672 return events_left-- > 0; 673 } 674 number_float(json::number_float_t , const std::string& )675 bool number_float(json::number_float_t /*unused*/, const std::string& /*unused*/) 676 { 677 return events_left-- > 0; 678 } 679 string(std::string& )680 bool string(std::string& /*unused*/) 681 { 682 return events_left-- > 0; 683 } 684 binary(std::vector<std::uint8_t>& )685 bool binary(std::vector<std::uint8_t>& /*unused*/) 686 { 687 return events_left-- > 0; 688 } 689 start_object(std::size_t )690 bool start_object(std::size_t /*unused*/) 691 { 692 return events_left-- > 0; 693 } 694 key(std::string& )695 bool key(std::string& /*unused*/) 696 { 697 return events_left-- > 0; 698 } 699 end_object()700 bool end_object() 701 { 702 return events_left-- > 0; 703 } 704 start_array(std::size_t )705 bool start_array(std::size_t /*unused*/) 706 { 707 return events_left-- > 0; 708 } 709 end_array()710 bool end_array() 711 { 712 return events_left-- > 0; 713 } 714 parse_error(std::size_t , const std::string& , const json::exception& )715 bool parse_error(std::size_t /*unused*/, const std::string& /*unused*/, const json::exception& /*unused*/) // NOLINT(readability-convert-member-functions-to-static) 716 { 717 return false; 718 } 719 720 private: 721 int events_left = 0; 722 }; 723 } // namespace 724 725 TEST_CASE("Incomplete BSON Input") 726 { 727 SECTION("Incomplete BSON Input 1") 728 { 729 std::vector<std::uint8_t> incomplete_bson = 730 { 731 0x0D, 0x00, 0x00, 0x00, // size (little endian) 732 0x08, // entry: boolean 733 'e', 'n', 't' // unexpected EOF 734 }; 735 736 json _; 737 CHECK_THROWS_WITH_AS(_ = json::from_bson(incomplete_bson), "[json.exception.parse_error.110] parse error at byte 9: syntax error while parsing BSON cstring: unexpected end of input", json::parse_error&); 738 739 CHECK(json::from_bson(incomplete_bson, true, false).is_discarded()); 740 741 SaxCountdown scp(0); 742 CHECK(!json::sax_parse(incomplete_bson, &scp, json::input_format_t::bson)); 743 } 744 745 SECTION("Incomplete BSON Input 2") 746 { 747 std::vector<std::uint8_t> incomplete_bson = 748 { 749 0x0D, 0x00, 0x00, 0x00, // size (little endian) 750 0x08, // entry: boolean, unexpected EOF 751 }; 752 753 json _; 754 CHECK_THROWS_WITH_AS(_ = json::from_bson(incomplete_bson), "[json.exception.parse_error.110] parse error at byte 6: syntax error while parsing BSON cstring: unexpected end of input", json::parse_error&); 755 CHECK(json::from_bson(incomplete_bson, true, false).is_discarded()); 756 757 SaxCountdown scp(0); 758 CHECK(!json::sax_parse(incomplete_bson, &scp, json::input_format_t::bson)); 759 } 760 761 SECTION("Incomplete BSON Input 3") 762 { 763 std::vector<std::uint8_t> incomplete_bson = 764 { 765 0x41, 0x00, 0x00, 0x00, // size (little endian) 766 0x04, /// entry: embedded document 767 'e', 'n', 't', 'r', 'y', '\x00', 768 769 0x35, 0x00, 0x00, 0x00, // size (little endian) 770 0x10, 0x00, 0x01, 0x00, 0x00, 0x00, 771 0x10, 0x00, 0x02, 0x00, 0x00, 0x00 772 // missing input data... 773 }; 774 775 json _; 776 CHECK_THROWS_WITH_AS(_ = json::from_bson(incomplete_bson), "[json.exception.parse_error.110] parse error at byte 28: syntax error while parsing BSON element list: unexpected end of input", json::parse_error&); 777 CHECK(json::from_bson(incomplete_bson, true, false).is_discarded()); 778 779 SaxCountdown scp(1); 780 CHECK(!json::sax_parse(incomplete_bson, &scp, json::input_format_t::bson)); 781 } 782 783 SECTION("Incomplete BSON Input 4") 784 { 785 std::vector<std::uint8_t> incomplete_bson = 786 { 787 0x0D, 0x00, // size (incomplete), unexpected EOF 788 }; 789 790 json _; 791 CHECK_THROWS_WITH_AS(_ = json::from_bson(incomplete_bson), "[json.exception.parse_error.110] parse error at byte 3: syntax error while parsing BSON number: unexpected end of input", json::parse_error&); 792 CHECK(json::from_bson(incomplete_bson, true, false).is_discarded()); 793 794 SaxCountdown scp(0); 795 CHECK(!json::sax_parse(incomplete_bson, &scp, json::input_format_t::bson)); 796 } 797 798 SECTION("Improve coverage") 799 { 800 SECTION("key") 801 { 802 json j = {{"key", "value"}}; 803 auto bson_vec = json::to_bson(j); 804 SaxCountdown scp(2); 805 CHECK(!json::sax_parse(bson_vec, &scp, json::input_format_t::bson)); 806 } 807 808 SECTION("array") 809 { 810 json j = 811 { 812 { "entry", json::array() } 813 }; 814 auto bson_vec = json::to_bson(j); 815 SaxCountdown scp(2); 816 CHECK(!json::sax_parse(bson_vec, &scp, json::input_format_t::bson)); 817 } 818 } 819 } 820 821 TEST_CASE("Negative size of binary value") 822 { 823 // invalid BSON: the size of the binary value is -1 824 std::vector<std::uint8_t> input = 825 { 826 0x21, 0x00, 0x00, 0x00, // size (little endian) 827 0x05, // entry: binary 828 'e', 'n', 't', 'r', 'y', '\x00', 829 830 0xFF, 0xFF, 0xFF, 0xFF, // size of binary (little endian) 831 0x05, // MD5 binary subtype 832 0xd7, 0x7e, 0x27, 0x54, 0xbe, 0x12, 0x37, 0xfe, 0xd6, 0x0c, 0x33, 0x98, 0x30, 0x3b, 0x8d, 0xc4, 833 834 0x00 // end marker 835 }; 836 json _; 837 CHECK_THROWS_WITH_AS(_ = json::from_bson(input), "[json.exception.parse_error.112] parse error at byte 15: syntax error while parsing BSON binary: byte array length cannot be negative, is -1", json::parse_error); 838 } 839 840 TEST_CASE("Unsupported BSON input") 841 { 842 std::vector<std::uint8_t> bson = 843 { 844 0x0C, 0x00, 0x00, 0x00, // size (little endian) 845 0xFF, // entry type: Min key (not supported yet) 846 'e', 'n', 't', 'r', 'y', '\x00', 847 0x00 // end marker 848 }; 849 850 json _; 851 CHECK_THROWS_WITH_AS(_ = json::from_bson(bson), "[json.exception.parse_error.114] parse error at byte 5: Unsupported BSON record type 0xFF", json::parse_error&); 852 CHECK(json::from_bson(bson, true, false).is_discarded()); 853 854 SaxCountdown scp(0); 855 CHECK(!json::sax_parse(bson, &scp, json::input_format_t::bson)); 856 } 857 858 TEST_CASE("BSON numerical data") 859 { 860 SECTION("number") 861 { 862 SECTION("signed") 863 { 864 SECTION("std::int64_t: INT64_MIN .. INT32_MIN-1") 865 { 866 std::vector<int64_t> numbers 867 { 868 INT64_MIN, 869 -1000000000000000000LL, 870 -100000000000000000LL, 871 -10000000000000000LL, 872 -1000000000000000LL, 873 -100000000000000LL, 874 -10000000000000LL, 875 -1000000000000LL, 876 -100000000000LL, 877 -10000000000LL, 878 static_cast<std::int64_t>(INT32_MIN) - 1, 879 }; 880 881 for (auto i : numbers) 882 { 883 884 CAPTURE(i) 885 886 json j = 887 { 888 { "entry", i } 889 }; 890 CHECK(j.at("entry").is_number_integer()); 891 892 std::uint64_t iu = *reinterpret_cast<std::uint64_t*>(&i); 893 std::vector<std::uint8_t> expected_bson = 894 { 895 0x14u, 0x00u, 0x00u, 0x00u, // size (little endian) 896 0x12u, /// entry: int64 897 'e', 'n', 't', 'r', 'y', '\x00', 898 static_cast<std::uint8_t>((iu >> (8u * 0u)) & 0xffu), 899 static_cast<std::uint8_t>((iu >> (8u * 1u)) & 0xffu), 900 static_cast<std::uint8_t>((iu >> (8u * 2u)) & 0xffu), 901 static_cast<std::uint8_t>((iu >> (8u * 3u)) & 0xffu), 902 static_cast<std::uint8_t>((iu >> (8u * 4u)) & 0xffu), 903 static_cast<std::uint8_t>((iu >> (8u * 5u)) & 0xffu), 904 static_cast<std::uint8_t>((iu >> (8u * 6u)) & 0xffu), 905 static_cast<std::uint8_t>((iu >> (8u * 7u)) & 0xffu), 906 0x00u // end marker 907 }; 908 909 const auto bson = json::to_bson(j); 910 CHECK(bson == expected_bson); 911 912 auto j_roundtrip = json::from_bson(bson); 913 914 CHECK(j_roundtrip.at("entry").is_number_integer()); 915 CHECK(j_roundtrip == j); 916 CHECK(json::from_bson(bson, true, false) == j); 917 918 } 919 } 920 921 922 SECTION("signed std::int32_t: INT32_MIN .. INT32_MAX") 923 { 924 std::vector<int32_t> numbers 925 { 926 INT32_MIN, 927 -2147483647L, 928 -1000000000L, 929 -100000000L, 930 -10000000L, 931 -1000000L, 932 -100000L, 933 -10000L, 934 -1000L, 935 -100L, 936 -10L, 937 -1L, 938 0L, 939 1L, 940 10L, 941 100L, 942 1000L, 943 10000L, 944 100000L, 945 1000000L, 946 10000000L, 947 100000000L, 948 1000000000L, 949 2147483646L, 950 INT32_MAX 951 }; 952 953 for (auto i : numbers) 954 { 955 956 CAPTURE(i) 957 958 json j = 959 { 960 { "entry", i } 961 }; 962 CHECK(j.at("entry").is_number_integer()); 963 964 std::uint32_t iu = *reinterpret_cast<std::uint32_t*>(&i); 965 std::vector<std::uint8_t> expected_bson = 966 { 967 0x10u, 0x00u, 0x00u, 0x00u, // size (little endian) 968 0x10u, /// entry: int32 969 'e', 'n', 't', 'r', 'y', '\x00', 970 static_cast<std::uint8_t>((iu >> (8u * 0u)) & 0xffu), 971 static_cast<std::uint8_t>((iu >> (8u * 1u)) & 0xffu), 972 static_cast<std::uint8_t>((iu >> (8u * 2u)) & 0xffu), 973 static_cast<std::uint8_t>((iu >> (8u * 3u)) & 0xffu), 974 0x00u // end marker 975 }; 976 977 const auto bson = json::to_bson(j); 978 CHECK(bson == expected_bson); 979 980 auto j_roundtrip = json::from_bson(bson); 981 982 CHECK(j_roundtrip.at("entry").is_number_integer()); 983 CHECK(j_roundtrip == j); 984 CHECK(json::from_bson(bson, true, false) == j); 985 986 } 987 } 988 989 SECTION("signed std::int64_t: INT32_MAX+1 .. INT64_MAX") 990 { 991 std::vector<int64_t> numbers 992 { 993 INT64_MAX, 994 1000000000000000000LL, 995 100000000000000000LL, 996 10000000000000000LL, 997 1000000000000000LL, 998 100000000000000LL, 999 10000000000000LL, 1000 1000000000000LL, 1001 100000000000LL, 1002 10000000000LL, 1003 static_cast<std::int64_t>(INT32_MAX) + 1, 1004 }; 1005 1006 for (auto i : numbers) 1007 { 1008 1009 CAPTURE(i) 1010 1011 json j = 1012 { 1013 { "entry", i } 1014 }; 1015 CHECK(j.at("entry").is_number_integer()); 1016 1017 std::uint64_t iu = *reinterpret_cast<std::uint64_t*>(&i); 1018 std::vector<std::uint8_t> expected_bson = 1019 { 1020 0x14u, 0x00u, 0x00u, 0x00u, // size (little endian) 1021 0x12u, /// entry: int64 1022 'e', 'n', 't', 'r', 'y', '\x00', 1023 static_cast<std::uint8_t>((iu >> (8u * 0u)) & 0xffu), 1024 static_cast<std::uint8_t>((iu >> (8u * 1u)) & 0xffu), 1025 static_cast<std::uint8_t>((iu >> (8u * 2u)) & 0xffu), 1026 static_cast<std::uint8_t>((iu >> (8u * 3u)) & 0xffu), 1027 static_cast<std::uint8_t>((iu >> (8u * 4u)) & 0xffu), 1028 static_cast<std::uint8_t>((iu >> (8u * 5u)) & 0xffu), 1029 static_cast<std::uint8_t>((iu >> (8u * 6u)) & 0xffu), 1030 static_cast<std::uint8_t>((iu >> (8u * 7u)) & 0xffu), 1031 0x00u // end marker 1032 }; 1033 1034 const auto bson = json::to_bson(j); 1035 CHECK(bson == expected_bson); 1036 1037 auto j_roundtrip = json::from_bson(bson); 1038 1039 CHECK(j_roundtrip.at("entry").is_number_integer()); 1040 CHECK(j_roundtrip == j); 1041 CHECK(json::from_bson(bson, true, false) == j); 1042 1043 } 1044 } 1045 } 1046 1047 SECTION("unsigned") 1048 { 1049 SECTION("unsigned std::uint64_t: 0 .. INT32_MAX") 1050 { 1051 std::vector<std::uint64_t> numbers 1052 { 1053 0ULL, 1054 1ULL, 1055 10ULL, 1056 100ULL, 1057 1000ULL, 1058 10000ULL, 1059 100000ULL, 1060 1000000ULL, 1061 10000000ULL, 1062 100000000ULL, 1063 1000000000ULL, 1064 2147483646ULL, 1065 static_cast<std::uint64_t>(INT32_MAX) 1066 }; 1067 1068 for (auto i : numbers) 1069 { 1070 1071 CAPTURE(i) 1072 1073 json j = 1074 { 1075 { "entry", i } 1076 }; 1077 1078 auto iu = i; 1079 std::vector<std::uint8_t> expected_bson = 1080 { 1081 0x10u, 0x00u, 0x00u, 0x00u, // size (little endian) 1082 0x10u, /// entry: int32 1083 'e', 'n', 't', 'r', 'y', '\x00', 1084 static_cast<std::uint8_t>((iu >> (8u * 0u)) & 0xffu), 1085 static_cast<std::uint8_t>((iu >> (8u * 1u)) & 0xffu), 1086 static_cast<std::uint8_t>((iu >> (8u * 2u)) & 0xffu), 1087 static_cast<std::uint8_t>((iu >> (8u * 3u)) & 0xffu), 1088 0x00u // end marker 1089 }; 1090 1091 const auto bson = json::to_bson(j); 1092 CHECK(bson == expected_bson); 1093 1094 auto j_roundtrip = json::from_bson(bson); 1095 1096 CHECK(j.at("entry").is_number_unsigned()); 1097 CHECK(j_roundtrip.at("entry").is_number_integer()); 1098 CHECK(j_roundtrip == j); 1099 CHECK(json::from_bson(bson, true, false) == j); 1100 1101 } 1102 } 1103 1104 SECTION("unsigned std::uint64_t: INT32_MAX+1 .. INT64_MAX") 1105 { 1106 std::vector<std::uint64_t> numbers 1107 { 1108 static_cast<std::uint64_t>(INT32_MAX) + 1, 1109 4000000000ULL, 1110 static_cast<std::uint64_t>(UINT32_MAX), 1111 10000000000ULL, 1112 100000000000ULL, 1113 1000000000000ULL, 1114 10000000000000ULL, 1115 100000000000000ULL, 1116 1000000000000000ULL, 1117 10000000000000000ULL, 1118 100000000000000000ULL, 1119 1000000000000000000ULL, 1120 static_cast<std::uint64_t>(INT64_MAX), 1121 }; 1122 1123 for (auto i : numbers) 1124 { 1125 1126 CAPTURE(i) 1127 1128 json j = 1129 { 1130 { "entry", i } 1131 }; 1132 1133 auto iu = i; 1134 std::vector<std::uint8_t> expected_bson = 1135 { 1136 0x14u, 0x00u, 0x00u, 0x00u, // size (little endian) 1137 0x12u, /// entry: int64 1138 'e', 'n', 't', 'r', 'y', '\x00', 1139 static_cast<std::uint8_t>((iu >> (8u * 0u)) & 0xffu), 1140 static_cast<std::uint8_t>((iu >> (8u * 1u)) & 0xffu), 1141 static_cast<std::uint8_t>((iu >> (8u * 2u)) & 0xffu), 1142 static_cast<std::uint8_t>((iu >> (8u * 3u)) & 0xffu), 1143 static_cast<std::uint8_t>((iu >> (8u * 4u)) & 0xffu), 1144 static_cast<std::uint8_t>((iu >> (8u * 5u)) & 0xffu), 1145 static_cast<std::uint8_t>((iu >> (8u * 6u)) & 0xffu), 1146 static_cast<std::uint8_t>((iu >> (8u * 7u)) & 0xffu), 1147 0x00u // end marker 1148 }; 1149 1150 const auto bson = json::to_bson(j); 1151 CHECK(bson == expected_bson); 1152 1153 auto j_roundtrip = json::from_bson(bson); 1154 1155 CHECK(j.at("entry").is_number_unsigned()); 1156 CHECK(j_roundtrip.at("entry").is_number_integer()); 1157 CHECK(j_roundtrip == j); 1158 CHECK(json::from_bson(bson, true, false) == j); 1159 } 1160 } 1161 1162 SECTION("unsigned std::uint64_t: INT64_MAX+1 .. UINT64_MAX") 1163 { 1164 std::vector<std::uint64_t> numbers 1165 { 1166 static_cast<std::uint64_t>(INT64_MAX) + 1ULL, 1167 10000000000000000000ULL, 1168 18000000000000000000ULL, 1169 UINT64_MAX - 1ULL, 1170 UINT64_MAX, 1171 }; 1172 1173 for (auto i : numbers) 1174 { 1175 1176 CAPTURE(i) 1177 1178 json j = 1179 { 1180 { "entry", i } 1181 }; 1182 1183 auto iu = i; 1184 std::vector<std::uint8_t> expected_bson = 1185 { 1186 0x14u, 0x00u, 0x00u, 0x00u, // size (little endian) 1187 0x12u, /// entry: int64 1188 'e', 'n', 't', 'r', 'y', '\x00', 1189 static_cast<std::uint8_t>((iu >> (8u * 0u)) & 0xffu), 1190 static_cast<std::uint8_t>((iu >> (8u * 1u)) & 0xffu), 1191 static_cast<std::uint8_t>((iu >> (8u * 2u)) & 0xffu), 1192 static_cast<std::uint8_t>((iu >> (8u * 3u)) & 0xffu), 1193 static_cast<std::uint8_t>((iu >> (8u * 4u)) & 0xffu), 1194 static_cast<std::uint8_t>((iu >> (8u * 5u)) & 0xffu), 1195 static_cast<std::uint8_t>((iu >> (8u * 6u)) & 0xffu), 1196 static_cast<std::uint8_t>((iu >> (8u * 7u)) & 0xffu), 1197 0x00u // end marker 1198 }; 1199 1200 CHECK_THROWS_AS(json::to_bson(j), json::out_of_range&); 1201 #if JSON_DIAGNOSTICS 1202 CHECK_THROWS_WITH_STD_STR(json::to_bson(j), "[json.exception.out_of_range.407] (/entry) integer number " + std::to_string(i) + " cannot be represented by BSON as it does not fit int64"); 1203 #else 1204 CHECK_THROWS_WITH_STD_STR(json::to_bson(j), "[json.exception.out_of_range.407] integer number " + std::to_string(i) + " cannot be represented by BSON as it does not fit int64"); 1205 #endif 1206 } 1207 } 1208 1209 } 1210 } 1211 } 1212 1213 TEST_CASE("BSON roundtrips" * doctest::skip()) 1214 { 1215 SECTION("reference files") 1216 { 1217 for (std::string filename : 1218 { 1219 TEST_DATA_DIRECTORY "/json.org/1.json", 1220 TEST_DATA_DIRECTORY "/json.org/2.json", 1221 TEST_DATA_DIRECTORY "/json.org/3.json", 1222 TEST_DATA_DIRECTORY "/json.org/4.json", 1223 TEST_DATA_DIRECTORY "/json.org/5.json" 1224 }) 1225 { CAPTURE(filename)1226 CAPTURE(filename) 1227 1228 { 1229 INFO_WITH_TEMP(filename + ": std::vector<std::uint8_t>"); 1230 // parse JSON file 1231 std::ifstream f_json(filename); 1232 json j1 = json::parse(f_json); 1233 1234 // parse BSON file 1235 auto packed = utils::read_binary_file(filename + ".bson"); 1236 json j2; 1237 CHECK_NOTHROW(j2 = json::from_bson(packed)); 1238 1239 // compare parsed JSON values 1240 CHECK(j1 == j2); 1241 } 1242 1243 { 1244 INFO_WITH_TEMP(filename + ": std::ifstream"); 1245 // parse JSON file 1246 std::ifstream f_json(filename); 1247 json j1 = json::parse(f_json); 1248 1249 // parse BSON file 1250 std::ifstream f_bson(filename + ".bson", std::ios::binary); 1251 json j2; 1252 CHECK_NOTHROW(j2 = json::from_bson(f_bson)); 1253 1254 // compare parsed JSON values 1255 CHECK(j1 == j2); 1256 } 1257 1258 { 1259 INFO_WITH_TEMP(filename + ": uint8_t* and size"); 1260 // parse JSON file 1261 std::ifstream f_json(filename); 1262 json j1 = json::parse(f_json); 1263 1264 // parse BSON file 1265 auto packed = utils::read_binary_file(filename + ".bson"); 1266 json j2; 1267 CHECK_NOTHROW(j2 = json::from_bson({packed.data(), packed.size()})); 1268 1269 // compare parsed JSON values 1270 CHECK(j1 == j2); 1271 } 1272 1273 { 1274 INFO_WITH_TEMP(filename + ": output to output adapters"); 1275 // parse JSON file 1276 std::ifstream f_json(filename); 1277 json j1 = json::parse(f_json); 1278 1279 // parse BSON file 1280 auto packed = utils::read_binary_file(filename + ".bson"); 1281 1282 { 1283 INFO_WITH_TEMP(filename + ": output adapters: std::vector<std::uint8_t>"); 1284 std::vector<std::uint8_t> vec; 1285 json::to_bson(j1, vec); 1286 1287 if (vec != packed) 1288 { 1289 // the exact serializations may differ due to the order of 1290 // object keys; in these cases, just compare whether both 1291 // serializations create the same JSON value 1292 CHECK(json::from_bson(vec) == json::from_bson(packed)); 1293 } 1294 } 1295 } 1296 } 1297 } 1298 } 1299