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
skip()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 {
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