• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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