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