1 // __ _____ _____ _____
2 // __| | __| | | | JSON for Modern C++ (supporting code)
3 // | | |__ | | | | | | version 3.11.3
4 // |_____|_____|_____|_|___| https://github.com/nlohmann/json
5 //
6 // SPDX-FileCopyrightText: 2013-2023 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 <limits>
16 #include <sstream>
17 #include "make_test_data_available.hpp"
18 #include "test_utils.hpp"
19
20 TEST_CASE("BSON")
21 {
22 SECTION("individual values not supported")
23 {
24 SECTION("null")
25 {
26 json const j = nullptr;
27 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&);
28 }
29
30 SECTION("boolean")
31 {
32 SECTION("true")
33 {
34 json const j = true;
35 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&);
36 }
37
38 SECTION("false")
39 {
40 json const j = false;
41 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&);
42 }
43 }
44
45 SECTION("number")
46 {
47 json const j = 42;
48 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&);
49 }
50
51 SECTION("float")
52 {
53 json const j = 4.2;
54 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&);
55 }
56
57 SECTION("string")
58 {
59 json const j = "not supported";
60 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&);
61 }
62
63 SECTION("array")
64 {
65 json const j = std::vector<int> {1, 2, 3, 4, 5, 6, 7};
66 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&);
67 }
68 }
69
70 SECTION("keys containing code-point U+0000 cannot be serialized to BSON")
71 {
72 json const j =
73 {
74 { std::string("en\0try", 6), true }
75 };
76 #if JSON_DIAGNOSTICS
77 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&);
78 #else
79 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&);
80 #endif
81 }
82
83 SECTION("string length must be at least 1")
84 {
85 // from https://bugs.chromium.org/p/oss-fuzz/issues/detail?id=11175
86 std::vector<std::uint8_t> const v =
87 {
88 0x20, 0x20, 0x20, 0x20,
89 0x02,
90 0x00,
91 0x00, 0x00, 0x00, 0x80
92 };
93 json _;
94 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&);
95 }
96
97 SECTION("objects")
98 {
99 SECTION("empty object")
100 {
101 json const j = json::object();
102 std::vector<std::uint8_t> const expected =
103 {
104 0x05, 0x00, 0x00, 0x00, // size (little endian)
105 // no entries
106 0x00 // end marker
107 };
108
109 const auto result = json::to_bson(j);
110 CHECK(result == expected);
111
112 // roundtrip
113 CHECK(json::from_bson(result) == j);
114 CHECK(json::from_bson(result, true, false) == j);
115 }
116
117 SECTION("non-empty object with bool")
118 {
119 json const j =
120 {
121 { "entry", true }
122 };
123
124 std::vector<std::uint8_t> const expected =
125 {
126 0x0D, 0x00, 0x00, 0x00, // size (little endian)
127 0x08, // entry: boolean
128 'e', 'n', 't', 'r', 'y', '\x00',
129 0x01, // value = true
130 0x00 // end marker
131 };
132
133 const auto result = json::to_bson(j);
134 CHECK(result == expected);
135
136 // roundtrip
137 CHECK(json::from_bson(result) == j);
138 CHECK(json::from_bson(result, true, false) == j);
139 }
140
141 SECTION("non-empty object with bool")
142 {
143 json const j =
144 {
145 { "entry", false }
146 };
147
148 std::vector<std::uint8_t> const expected =
149 {
150 0x0D, 0x00, 0x00, 0x00, // size (little endian)
151 0x08, // entry: boolean
152 'e', 'n', 't', 'r', 'y', '\x00',
153 0x00, // value = false
154 0x00 // end marker
155 };
156
157 const auto result = json::to_bson(j);
158 CHECK(result == expected);
159
160 // roundtrip
161 CHECK(json::from_bson(result) == j);
162 CHECK(json::from_bson(result, true, false) == j);
163 }
164
165 SECTION("non-empty object with double")
166 {
167 json const j =
168 {
169 { "entry", 4.2 }
170 };
171
172 std::vector<std::uint8_t> const expected =
173 {
174 0x14, 0x00, 0x00, 0x00, // size (little endian)
175 0x01, /// entry: double
176 'e', 'n', 't', 'r', 'y', '\x00',
177 0xcd, 0xcc, 0xcc, 0xcc, 0xcc, 0xcc, 0x10, 0x40,
178 0x00 // end marker
179 };
180
181 const auto result = json::to_bson(j);
182 CHECK(result == expected);
183
184 // roundtrip
185 CHECK(json::from_bson(result) == j);
186 CHECK(json::from_bson(result, true, false) == j);
187 }
188
189 SECTION("non-empty object with string")
190 {
191 json const j =
192 {
193 { "entry", "bsonstr" }
194 };
195
196 std::vector<std::uint8_t> const expected =
197 {
198 0x18, 0x00, 0x00, 0x00, // size (little endian)
199 0x02, /// entry: string (UTF-8)
200 'e', 'n', 't', 'r', 'y', '\x00',
201 0x08, 0x00, 0x00, 0x00, 'b', 's', 'o', 'n', 's', 't', 'r', '\x00',
202 0x00 // end marker
203 };
204
205 const auto result = json::to_bson(j);
206 CHECK(result == expected);
207
208 // roundtrip
209 CHECK(json::from_bson(result) == j);
210 CHECK(json::from_bson(result, true, false) == j);
211 }
212
213 SECTION("non-empty object with null member")
214 {
215 json const j =
216 {
217 { "entry", nullptr }
218 };
219
220 std::vector<std::uint8_t> const expected =
221 {
222 0x0C, 0x00, 0x00, 0x00, // size (little endian)
223 0x0A, /// entry: null
224 'e', 'n', 't', 'r', 'y', '\x00',
225 0x00 // end marker
226 };
227
228 const auto result = json::to_bson(j);
229 CHECK(result == expected);
230
231 // roundtrip
232 CHECK(json::from_bson(result) == j);
233 CHECK(json::from_bson(result, true, false) == j);
234 }
235
236 SECTION("non-empty object with integer (32-bit) member")
237 {
238 json const j =
239 {
240 { "entry", std::int32_t{0x12345678} }
241 };
242
243 std::vector<std::uint8_t> const expected =
244 {
245 0x10, 0x00, 0x00, 0x00, // size (little endian)
246 0x10, /// entry: int32
247 'e', 'n', 't', 'r', 'y', '\x00',
248 0x78, 0x56, 0x34, 0x12,
249 0x00 // end marker
250 };
251
252 const auto result = json::to_bson(j);
253 CHECK(result == expected);
254
255 // roundtrip
256 CHECK(json::from_bson(result) == j);
257 CHECK(json::from_bson(result, true, false) == j);
258 }
259
260 SECTION("non-empty object with integer (64-bit) member")
261 {
262 json const j =
263 {
264 { "entry", std::int64_t{0x1234567804030201} }
265 };
266
267 std::vector<std::uint8_t> const expected =
268 {
269 0x14, 0x00, 0x00, 0x00, // size (little endian)
270 0x12, /// entry: int64
271 'e', 'n', 't', 'r', 'y', '\x00',
272 0x01, 0x02, 0x03, 0x04, 0x78, 0x56, 0x34, 0x12,
273 0x00 // end marker
274 };
275
276 const auto result = json::to_bson(j);
277 CHECK(result == expected);
278
279 // roundtrip
280 CHECK(json::from_bson(result) == j);
281 CHECK(json::from_bson(result, true, false) == j);
282 }
283
284 SECTION("non-empty object with negative integer (32-bit) member")
285 {
286 json const j =
287 {
288 { "entry", std::int32_t{-1} }
289 };
290
291 std::vector<std::uint8_t> const expected =
292 {
293 0x10, 0x00, 0x00, 0x00, // size (little endian)
294 0x10, /// entry: int32
295 'e', 'n', 't', 'r', 'y', '\x00',
296 0xFF, 0xFF, 0xFF, 0xFF,
297 0x00 // end marker
298 };
299
300 const auto result = json::to_bson(j);
301 CHECK(result == expected);
302
303 // roundtrip
304 CHECK(json::from_bson(result) == j);
305 CHECK(json::from_bson(result, true, false) == j);
306 }
307
308 SECTION("non-empty object with negative integer (64-bit) member")
309 {
310 json const j =
311 {
312 { "entry", std::int64_t{-1} }
313 };
314
315 std::vector<std::uint8_t> const expected =
316 {
317 0x10, 0x00, 0x00, 0x00, // size (little endian)
318 0x10, /// entry: int32
319 'e', 'n', 't', 'r', 'y', '\x00',
320 0xFF, 0xFF, 0xFF, 0xFF,
321 0x00 // end marker
322 };
323
324 const auto result = json::to_bson(j);
325 CHECK(result == expected);
326
327 // roundtrip
328 CHECK(json::from_bson(result) == j);
329 CHECK(json::from_bson(result, true, false) == j);
330 }
331
332 SECTION("non-empty object with unsigned integer (64-bit) member")
333 {
334 // directly encoding uint64 is not supported in bson (only for timestamp values)
335 json const j =
336 {
337 { "entry", std::uint64_t{0x1234567804030201} }
338 };
339
340 std::vector<std::uint8_t> const expected =
341 {
342 0x14, 0x00, 0x00, 0x00, // size (little endian)
343 0x12, /// entry: int64
344 'e', 'n', 't', 'r', 'y', '\x00',
345 0x01, 0x02, 0x03, 0x04, 0x78, 0x56, 0x34, 0x12,
346 0x00 // end marker
347 };
348
349 const auto result = json::to_bson(j);
350 CHECK(result == expected);
351
352 // roundtrip
353 CHECK(json::from_bson(result) == j);
354 CHECK(json::from_bson(result, true, false) == j);
355 }
356
357 SECTION("non-empty object with small unsigned integer member")
358 {
359 json const j =
360 {
361 { "entry", std::uint64_t{0x42} }
362 };
363
364 std::vector<std::uint8_t> const expected =
365 {
366 0x10, 0x00, 0x00, 0x00, // size (little endian)
367 0x10, /// entry: int32
368 'e', 'n', 't', 'r', 'y', '\x00',
369 0x42, 0x00, 0x00, 0x00,
370 0x00 // end marker
371 };
372
373 const auto result = json::to_bson(j);
374 CHECK(result == expected);
375
376 // roundtrip
377 CHECK(json::from_bson(result) == j);
378 CHECK(json::from_bson(result, true, false) == j);
379 }
380
381 SECTION("non-empty object with object member")
382 {
383 json const j =
384 {
385 { "entry", json::object() }
386 };
387
388 std::vector<std::uint8_t> const expected =
389 {
390 0x11, 0x00, 0x00, 0x00, // size (little endian)
391 0x03, /// entry: embedded document
392 'e', 'n', 't', 'r', 'y', '\x00',
393
394 0x05, 0x00, 0x00, 0x00, // size (little endian)
395 // no entries
396 0x00, // end marker (embedded document)
397
398 0x00 // end marker
399 };
400
401 const auto result = json::to_bson(j);
402 CHECK(result == expected);
403
404 // roundtrip
405 CHECK(json::from_bson(result) == j);
406 CHECK(json::from_bson(result, true, false) == j);
407 }
408
409 SECTION("non-empty object with array member")
410 {
411 json const j =
412 {
413 { "entry", json::array() }
414 };
415
416 std::vector<std::uint8_t> const expected =
417 {
418 0x11, 0x00, 0x00, 0x00, // size (little endian)
419 0x04, /// entry: embedded document
420 'e', 'n', 't', 'r', 'y', '\x00',
421
422 0x05, 0x00, 0x00, 0x00, // size (little endian)
423 // no entries
424 0x00, // end marker (embedded document)
425
426 0x00 // end marker
427 };
428
429 const auto result = json::to_bson(j);
430 CHECK(result == expected);
431
432 // roundtrip
433 CHECK(json::from_bson(result) == j);
434 CHECK(json::from_bson(result, true, false) == j);
435 }
436
437 SECTION("non-empty object with non-empty array member")
438 {
439 json const j =
440 {
441 { "entry", json::array({1, 2, 3, 4, 5, 6, 7, 8}) }
442 };
443
444 std::vector<std::uint8_t> const expected =
445 {
446 0x49, 0x00, 0x00, 0x00, // size (little endian)
447 0x04, /// entry: embedded document
448 'e', 'n', 't', 'r', 'y', '\x00',
449
450 0x3D, 0x00, 0x00, 0x00, // size (little endian)
451 0x10, '0', 0x00, 0x01, 0x00, 0x00, 0x00,
452 0x10, '1', 0x00, 0x02, 0x00, 0x00, 0x00,
453 0x10, '2', 0x00, 0x03, 0x00, 0x00, 0x00,
454 0x10, '3', 0x00, 0x04, 0x00, 0x00, 0x00,
455 0x10, '4', 0x00, 0x05, 0x00, 0x00, 0x00,
456 0x10, '5', 0x00, 0x06, 0x00, 0x00, 0x00,
457 0x10, '6', 0x00, 0x07, 0x00, 0x00, 0x00,
458 0x10, '7', 0x00, 0x08, 0x00, 0x00, 0x00,
459 0x00, // end marker (embedded document)
460
461 0x00 // end marker
462 };
463
464 const auto result = json::to_bson(j);
465 CHECK(result == expected);
466
467 // roundtrip
468 CHECK(json::from_bson(result) == j);
469 CHECK(json::from_bson(result, true, false) == j);
470 }
471
472 SECTION("non-empty object with binary member")
473 {
474 const size_t N = 10;
475 const auto s = std::vector<std::uint8_t>(N, 'x');
476 json const j =
477 {
478 { "entry", json::binary(s, 0) }
479 };
480
481 std::vector<std::uint8_t> const expected =
482 {
483 0x1B, 0x00, 0x00, 0x00, // size (little endian)
484 0x05, // entry: binary
485 'e', 'n', 't', 'r', 'y', '\x00',
486
487 0x0A, 0x00, 0x00, 0x00, // size of binary (little endian)
488 0x00, // Generic binary subtype
489 0x78, 0x78, 0x78, 0x78, 0x78, 0x78, 0x78, 0x78, 0x78, 0x78,
490
491 0x00 // end marker
492 };
493
494 const auto result = json::to_bson(j);
495 CHECK(result == expected);
496
497 // roundtrip
498 CHECK(json::from_bson(result) == j);
499 CHECK(json::from_bson(result, true, false) == j);
500 }
501
502 SECTION("non-empty object with binary member with subtype")
503 {
504 // an MD5 hash
505 const std::vector<std::uint8_t> md5hash = {0xd7, 0x7e, 0x27, 0x54, 0xbe, 0x12, 0x37, 0xfe, 0xd6, 0x0c, 0x33, 0x98, 0x30, 0x3b, 0x8d, 0xc4};
506 json const j =
507 {
508 { "entry", json::binary(md5hash, 5) }
509 };
510
511 std::vector<std::uint8_t> const expected =
512 {
513 0x21, 0x00, 0x00, 0x00, // size (little endian)
514 0x05, // entry: binary
515 'e', 'n', 't', 'r', 'y', '\x00',
516
517 0x10, 0x00, 0x00, 0x00, // size of binary (little endian)
518 0x05, // MD5 binary subtype
519 0xd7, 0x7e, 0x27, 0x54, 0xbe, 0x12, 0x37, 0xfe, 0xd6, 0x0c, 0x33, 0x98, 0x30, 0x3b, 0x8d, 0xc4,
520
521 0x00 // end marker
522 };
523
524 const auto result = json::to_bson(j);
525 CHECK(result == expected);
526
527 // roundtrip
528 CHECK(json::from_bson(result) == j);
529 CHECK(json::from_bson(result, true, false) == j);
530 }
531
532 SECTION("Some more complex document")
533 {
534 // directly encoding uint64 is not supported in bson (only for timestamp values)
535 json const j =
536 {
537 {"double", 42.5},
538 {"entry", 4.2},
539 {"number", 12345},
540 {"object", {{ "string", "value" }}}
541 };
542
543 std::vector<std::uint8_t> const expected =
544 {
545 /*size */ 0x4f, 0x00, 0x00, 0x00,
546 /*entry*/ 0x01, 'd', 'o', 'u', 'b', 'l', 'e', 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x40, 0x45, 0x40,
547 /*entry*/ 0x01, 'e', 'n', 't', 'r', 'y', 0x00, 0xcd, 0xcc, 0xcc, 0xcc, 0xcc, 0xcc, 0x10, 0x40,
548 /*entry*/ 0x10, 'n', 'u', 'm', 'b', 'e', 'r', 0x00, 0x39, 0x30, 0x00, 0x00,
549 /*entry*/ 0x03, 'o', 'b', 'j', 'e', 'c', 't', 0x00,
550 /*entry: obj-size */ 0x17, 0x00, 0x00, 0x00,
551 /*entry: obj-entry*/0x02, 's', 't', 'r', 'i', 'n', 'g', 0x00, 0x06, 0x00, 0x00, 0x00, 'v', 'a', 'l', 'u', 'e', 0,
552 /*entry: obj-term.*/0x00,
553 /*obj-term*/ 0x00
554 };
555
556 const auto result = json::to_bson(j);
557 CHECK(result == expected);
558
559 // roundtrip
560 CHECK(json::from_bson(result) == j);
561 CHECK(json::from_bson(result, true, false) == j);
562 }
563 }
564
565 SECTION("Examples from https://bsonspec.org/faq.html")
566 {
567 SECTION("Example 1")
568 {
569 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};
570 json parsed = json::from_bson(input);
571 json expected = {{"hello", "world"}};
572 CHECK(parsed == expected);
573 auto dumped = json::to_bson(parsed);
574 CHECK(dumped == input);
575 CHECK(json::from_bson(dumped) == expected);
576 }
577
578 SECTION("Example 2")
579 {
580 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};
581 json parsed = json::from_bson(input);
582 json expected = {{"BSON", {"awesome", 5.05, 1986}}};
583 CHECK(parsed == expected);
584 auto dumped = json::to_bson(parsed);
585 CHECK(dumped == input);
586 CHECK(json::from_bson(dumped) == expected);
587 }
588 }
589 }
590
591 TEST_CASE("BSON input/output_adapters")
592 {
593 json json_representation =
594 {
595 {"double", 42.5},
596 {"entry", 4.2},
597 {"number", 12345},
598 {"object", {{ "string", "value" }}}
599 };
600
601 std::vector<std::uint8_t> const bson_representation =
602 {
603 /*size */ 0x4f, 0x00, 0x00, 0x00,
604 /*entry*/ 0x01, 'd', 'o', 'u', 'b', 'l', 'e', 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x40, 0x45, 0x40,
605 /*entry*/ 0x01, 'e', 'n', 't', 'r', 'y', 0x00, 0xcd, 0xcc, 0xcc, 0xcc, 0xcc, 0xcc, 0x10, 0x40,
606 /*entry*/ 0x10, 'n', 'u', 'm', 'b', 'e', 'r', 0x00, 0x39, 0x30, 0x00, 0x00,
607 /*entry*/ 0x03, 'o', 'b', 'j', 'e', 'c', 't', 0x00,
608 /*entry: obj-size */ 0x17, 0x00, 0x00, 0x00,
609 /*entry: obj-entry*/0x02, 's', 't', 'r', 'i', 'n', 'g', 0x00, 0x06, 0x00, 0x00, 0x00, 'v', 'a', 'l', 'u', 'e', 0,
610 /*entry: obj-term.*/0x00,
611 /*obj-term*/ 0x00
612 };
613
614 json j2;
615 CHECK_NOTHROW(j2 = json::from_bson(bson_representation));
616
617 // compare parsed JSON values
618 CHECK(json_representation == j2);
619
620 SECTION("roundtrips")
621 {
622 SECTION("std::ostringstream")
623 {
624 std::basic_ostringstream<std::uint8_t> ss;
625 json::to_bson(json_representation, ss);
626 json j3 = json::from_bson(ss.str());
627 CHECK(json_representation == j3);
628 }
629
630 SECTION("std::string")
631 {
632 std::string s;
633 json::to_bson(json_representation, s);
634 json j3 = json::from_bson(s);
635 CHECK(json_representation == j3);
636 }
637
638 SECTION("std::vector")
639 {
640 std::vector<std::uint8_t> v;
641 json::to_bson(json_representation, v);
642 json j3 = json::from_bson(v);
643 CHECK(json_representation == j3);
644 }
645 }
646 }
647
648 namespace
649 {
650 class SaxCountdown
651 {
652 public:
SaxCountdown(const int count)653 explicit SaxCountdown(const int count) : events_left(count)
654 {}
655
null()656 bool null()
657 {
658 return events_left-- > 0;
659 }
660
boolean(bool)661 bool boolean(bool /*unused*/)
662 {
663 return events_left-- > 0;
664 }
665
number_integer(json::number_integer_t)666 bool number_integer(json::number_integer_t /*unused*/)
667 {
668 return events_left-- > 0;
669 }
670
number_unsigned(json::number_unsigned_t)671 bool number_unsigned(json::number_unsigned_t /*unused*/)
672 {
673 return events_left-- > 0;
674 }
675
number_float(json::number_float_t,const std::string &)676 bool number_float(json::number_float_t /*unused*/, const std::string& /*unused*/)
677 {
678 return events_left-- > 0;
679 }
680
string(std::string &)681 bool string(std::string& /*unused*/)
682 {
683 return events_left-- > 0;
684 }
685
binary(std::vector<std::uint8_t> &)686 bool binary(std::vector<std::uint8_t>& /*unused*/)
687 {
688 return events_left-- > 0;
689 }
690
start_object(std::size_t)691 bool start_object(std::size_t /*unused*/)
692 {
693 return events_left-- > 0;
694 }
695
key(std::string &)696 bool key(std::string& /*unused*/)
697 {
698 return events_left-- > 0;
699 }
700
end_object()701 bool end_object()
702 {
703 return events_left-- > 0;
704 }
705
start_array(std::size_t)706 bool start_array(std::size_t /*unused*/)
707 {
708 return events_left-- > 0;
709 }
710
end_array()711 bool end_array()
712 {
713 return events_left-- > 0;
714 }
715
parse_error(std::size_t,const std::string &,const json::exception &)716 bool parse_error(std::size_t /*unused*/, const std::string& /*unused*/, const json::exception& /*unused*/) // NOLINT(readability-convert-member-functions-to-static)
717 {
718 return false;
719 }
720
721 private:
722 int events_left = 0;
723 };
724 } // namespace
725
726 TEST_CASE("Incomplete BSON Input")
727 {
728 SECTION("Incomplete BSON Input 1")
729 {
730 std::vector<std::uint8_t> const incomplete_bson =
731 {
732 0x0D, 0x00, 0x00, 0x00, // size (little endian)
733 0x08, // entry: boolean
734 'e', 'n', 't' // unexpected EOF
735 };
736
737 json _;
738 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&);
739
740 CHECK(json::from_bson(incomplete_bson, true, false).is_discarded());
741
742 SaxCountdown scp(0);
743 CHECK(!json::sax_parse(incomplete_bson, &scp, json::input_format_t::bson));
744 }
745
746 SECTION("Incomplete BSON Input 2")
747 {
748 std::vector<std::uint8_t> const incomplete_bson =
749 {
750 0x0D, 0x00, 0x00, 0x00, // size (little endian)
751 0x08, // entry: boolean, unexpected EOF
752 };
753
754 json _;
755 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&);
756 CHECK(json::from_bson(incomplete_bson, true, false).is_discarded());
757
758 SaxCountdown scp(0);
759 CHECK(!json::sax_parse(incomplete_bson, &scp, json::input_format_t::bson));
760 }
761
762 SECTION("Incomplete BSON Input 3")
763 {
764 std::vector<std::uint8_t> const incomplete_bson =
765 {
766 0x41, 0x00, 0x00, 0x00, // size (little endian)
767 0x04, /// entry: embedded document
768 'e', 'n', 't', 'r', 'y', '\x00',
769
770 0x35, 0x00, 0x00, 0x00, // size (little endian)
771 0x10, 0x00, 0x01, 0x00, 0x00, 0x00,
772 0x10, 0x00, 0x02, 0x00, 0x00, 0x00
773 // missing input data...
774 };
775
776 json _;
777 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&);
778 CHECK(json::from_bson(incomplete_bson, true, false).is_discarded());
779
780 SaxCountdown scp(1);
781 CHECK(!json::sax_parse(incomplete_bson, &scp, json::input_format_t::bson));
782 }
783
784 SECTION("Incomplete BSON Input 4")
785 {
786 std::vector<std::uint8_t> const incomplete_bson =
787 {
788 0x0D, 0x00, // size (incomplete), unexpected EOF
789 };
790
791 json _;
792 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&);
793 CHECK(json::from_bson(incomplete_bson, true, false).is_discarded());
794
795 SaxCountdown scp(0);
796 CHECK(!json::sax_parse(incomplete_bson, &scp, json::input_format_t::bson));
797 }
798
799 SECTION("Improve coverage")
800 {
801 SECTION("key")
802 {
803 json const j = {{"key", "value"}};
804 auto bson_vec = json::to_bson(j);
805 SaxCountdown scp(2);
806 CHECK(!json::sax_parse(bson_vec, &scp, json::input_format_t::bson));
807 }
808
809 SECTION("array")
810 {
811 json const j =
812 {
813 { "entry", json::array() }
814 };
815 auto bson_vec = json::to_bson(j);
816 SaxCountdown scp(2);
817 CHECK(!json::sax_parse(bson_vec, &scp, json::input_format_t::bson));
818 }
819 }
820 }
821
822 TEST_CASE("Negative size of binary value")
823 {
824 // invalid BSON: the size of the binary value is -1
825 std::vector<std::uint8_t> const input =
826 {
827 0x21, 0x00, 0x00, 0x00, // size (little endian)
828 0x05, // entry: binary
829 'e', 'n', 't', 'r', 'y', '\x00',
830
831 0xFF, 0xFF, 0xFF, 0xFF, // size of binary (little endian)
832 0x05, // MD5 binary subtype
833 0xd7, 0x7e, 0x27, 0x54, 0xbe, 0x12, 0x37, 0xfe, 0xd6, 0x0c, 0x33, 0x98, 0x30, 0x3b, 0x8d, 0xc4,
834
835 0x00 // end marker
836 };
837 json _;
838 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);
839 }
840
841 TEST_CASE("Unsupported BSON input")
842 {
843 std::vector<std::uint8_t> const bson =
844 {
845 0x0C, 0x00, 0x00, 0x00, // size (little endian)
846 0xFF, // entry type: Min key (not supported yet)
847 'e', 'n', 't', 'r', 'y', '\x00',
848 0x00 // end marker
849 };
850
851 json _;
852 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&);
853 CHECK(json::from_bson(bson, true, false).is_discarded());
854
855 SaxCountdown scp(0);
856 CHECK(!json::sax_parse(bson, &scp, json::input_format_t::bson));
857 }
858
859 TEST_CASE("BSON numerical data")
860 {
861 SECTION("number")
862 {
863 SECTION("signed")
864 {
865 SECTION("std::int64_t: INT64_MIN .. INT32_MIN-1")
866 {
867 std::vector<int64_t> const numbers
868 {
869 (std::numeric_limits<int64_t>::min)(),
870 -1000000000000000000LL,
871 -100000000000000000LL,
872 -10000000000000000LL,
873 -1000000000000000LL,
874 -100000000000000LL,
875 -10000000000000LL,
876 -1000000000000LL,
877 -100000000000LL,
878 -10000000000LL,
879 static_cast<std::int64_t>((std::numeric_limits<std::int32_t>::min)()) - 1,
880 };
881
882 for (const auto i : numbers)
883 {
884
885 CAPTURE(i)
886
887 json const j =
888 {
889 { "entry", i }
890 };
891 CHECK(j.at("entry").is_number_integer());
892
893 std::uint64_t const iu = *reinterpret_cast<const std::uint64_t*>(&i);
894 std::vector<std::uint8_t> const expected_bson =
895 {
896 0x14u, 0x00u, 0x00u, 0x00u, // size (little endian)
897 0x12u, /// entry: int64
898 'e', 'n', 't', 'r', 'y', '\x00',
899 static_cast<std::uint8_t>((iu >> (8u * 0u)) & 0xffu),
900 static_cast<std::uint8_t>((iu >> (8u * 1u)) & 0xffu),
901 static_cast<std::uint8_t>((iu >> (8u * 2u)) & 0xffu),
902 static_cast<std::uint8_t>((iu >> (8u * 3u)) & 0xffu),
903 static_cast<std::uint8_t>((iu >> (8u * 4u)) & 0xffu),
904 static_cast<std::uint8_t>((iu >> (8u * 5u)) & 0xffu),
905 static_cast<std::uint8_t>((iu >> (8u * 6u)) & 0xffu),
906 static_cast<std::uint8_t>((iu >> (8u * 7u)) & 0xffu),
907 0x00u // end marker
908 };
909
910 const auto bson = json::to_bson(j);
911 CHECK(bson == expected_bson);
912
913 auto j_roundtrip = json::from_bson(bson);
914
915 CHECK(j_roundtrip.at("entry").is_number_integer());
916 CHECK(j_roundtrip == j);
917 CHECK(json::from_bson(bson, true, false) == j);
918
919 }
920 }
921
922 SECTION("signed std::int32_t: INT32_MIN .. INT32_MAX")
923 {
924 std::vector<int32_t> const numbers
925 {
926 (std::numeric_limits<int32_t>::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 (std::numeric_limits<int32_t>::max)()
951 };
952
953 for (const auto i : numbers)
954 {
955
956 CAPTURE(i)
957
958 json const j =
959 {
960 { "entry", i }
961 };
962 CHECK(j.at("entry").is_number_integer());
963
964 std::uint32_t const iu = *reinterpret_cast<const std::uint32_t*>(&i);
965 std::vector<std::uint8_t> const 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> const numbers
992 {
993 (std::numeric_limits<int64_t>::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>((std::numeric_limits<int32_t>::max)()) + 1,
1004 };
1005
1006 for (const auto i : numbers)
1007 {
1008
1009 CAPTURE(i)
1010
1011 json const j =
1012 {
1013 { "entry", i }
1014 };
1015 CHECK(j.at("entry").is_number_integer());
1016
1017 std::uint64_t const iu = *reinterpret_cast<const std::uint64_t*>(&i);
1018 std::vector<std::uint8_t> const 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> const 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>((std::numeric_limits<int32_t>::max)())
1066 };
1067
1068 for (const auto i : numbers)
1069 {
1070
1071 CAPTURE(i)
1072
1073 json const j =
1074 {
1075 { "entry", i }
1076 };
1077
1078 auto iu = i;
1079 std::vector<std::uint8_t> const 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> const numbers
1107 {
1108 static_cast<std::uint64_t>((std::numeric_limits<std::int32_t>::max)()) + 1,
1109 4000000000ULL,
1110 static_cast<std::uint64_t>((std::numeric_limits<std::uint32_t>::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>((std::numeric_limits<std::int64_t>::max)()),
1121 };
1122
1123 for (const auto i : numbers)
1124 {
1125
1126 CAPTURE(i)
1127
1128 json const j =
1129 {
1130 { "entry", i }
1131 };
1132
1133 auto iu = i;
1134 std::vector<std::uint8_t> const 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> const numbers
1165 {
1166 static_cast<std::uint64_t>((std::numeric_limits<std::int64_t>::max)()) + 1ULL,
1167 10000000000000000000ULL,
1168 18000000000000000000ULL,
1169 (std::numeric_limits<std::uint64_t>::max)() - 1ULL,
1170 (std::numeric_limits<std::uint64_t>::max)(),
1171 };
1172
1173 for (const auto i : numbers)
1174 {
1175
1176 CAPTURE(i)
1177
1178 json const j =
1179 {
1180 { "entry", i }
1181 };
1182
1183 auto iu = i;
1184 std::vector<std::uint8_t> const 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 (const 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 const 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