1 /*
2     __ _____ _____ _____
3  __|  |   __|     |   | |  JSON for Modern C++ (test suite)
4 |  |  |__   |  |  | | | |  version 3.7.3
5 |_____|_____|_____|_|___|  https://github.com/nlohmann/json
6 
7 Licensed under the MIT License <http://opensource.org/licenses/MIT>.
8 SPDX-License-Identifier: MIT
9 Copyright (c) 2013-2019 Niels Lohmann <http://nlohmann.me>.
10 
11 Permission is hereby  granted, free of charge, to any  person obtaining a copy
12 of this software and associated  documentation files (the "Software"), to deal
13 in the Software  without restriction, including without  limitation the rights
14 to  use, copy,  modify, merge,  publish, distribute,  sublicense, and/or  sell
15 copies  of  the Software,  and  to  permit persons  to  whom  the Software  is
16 furnished to do so, subject to the following conditions:
17 
18 The above copyright notice and this permission notice shall be included in all
19 copies or substantial portions of the Software.
20 
21 THE SOFTWARE  IS PROVIDED "AS  IS", WITHOUT WARRANTY  OF ANY KIND,  EXPRESS OR
22 IMPLIED,  INCLUDING BUT  NOT  LIMITED TO  THE  WARRANTIES OF  MERCHANTABILITY,
23 FITNESS FOR  A PARTICULAR PURPOSE AND  NONINFRINGEMENT. IN NO EVENT  SHALL THE
24 AUTHORS  OR COPYRIGHT  HOLDERS  BE  LIABLE FOR  ANY  CLAIM,  DAMAGES OR  OTHER
25 LIABILITY, WHETHER IN AN ACTION OF  CONTRACT, TORT OR OTHERWISE, ARISING FROM,
26 OUT OF OR IN CONNECTION WITH THE SOFTWARE  OR THE USE OR OTHER DEALINGS IN THE
27 SOFTWARE.
28 */
29 
30 #include "doctest_compatibility.h"
31 
32 #include <nlohmann/json.hpp>
33 using nlohmann::json;
34 
35 #include <fstream>
36 #include <sstream>
37 
38 TEST_CASE("BSON")
39 {
40     SECTION("individual values not supported")
41     {
42         SECTION("null")
43         {
44             json j = nullptr;
45             CHECK_THROWS_AS(json::to_bson(j), json::type_error&);
46             CHECK_THROWS_WITH(json::to_bson(j), "[json.exception.type_error.317] to serialize to BSON, top-level type must be object, but is null");
47         }
48 
49         SECTION("boolean")
50         {
51             SECTION("true")
52             {
53                 json j = true;
54                 CHECK_THROWS_AS(json::to_bson(j), json::type_error&);
55                 CHECK_THROWS_WITH(json::to_bson(j), "[json.exception.type_error.317] to serialize to BSON, top-level type must be object, but is boolean");
56             }
57 
58             SECTION("false")
59             {
60                 json j = false;
61                 CHECK_THROWS_AS(json::to_bson(j), json::type_error&);
62                 CHECK_THROWS_WITH(json::to_bson(j), "[json.exception.type_error.317] to serialize to BSON, top-level type must be object, but is boolean");
63             }
64         }
65 
66         SECTION("number")
67         {
68             json j = 42;
69             CHECK_THROWS_AS(json::to_bson(j), json::type_error&);
70             CHECK_THROWS_WITH(json::to_bson(j), "[json.exception.type_error.317] to serialize to BSON, top-level type must be object, but is number");
71         }
72 
73         SECTION("float")
74         {
75             json j = 4.2;
76             CHECK_THROWS_AS(json::to_bson(j), json::type_error&);
77             CHECK_THROWS_WITH(json::to_bson(j), "[json.exception.type_error.317] to serialize to BSON, top-level type must be object, but is number");
78         }
79 
80         SECTION("string")
81         {
82             json j = "not supported";
83             CHECK_THROWS_AS(json::to_bson(j), json::type_error&);
84             CHECK_THROWS_WITH(json::to_bson(j), "[json.exception.type_error.317] to serialize to BSON, top-level type must be object, but is string");
85         }
86 
87         SECTION("array")
88         {
89             json j = std::vector<int> {1, 2, 3, 4, 5, 6, 7};
90             CHECK_THROWS_AS(json::to_bson(j), json::type_error&);
91             CHECK_THROWS_WITH(json::to_bson(j), "[json.exception.type_error.317] to serialize to BSON, top-level type must be object, but is array");
92         }
93     }
94 
95     SECTION("keys containing code-point U+0000 cannot be serialized to BSON")
96     {
97         json j =
98         {
99             { std::string("en\0try", 6), true }
100         };
101         CHECK_THROWS_AS(json::to_bson(j), json::out_of_range&);
102         CHECK_THROWS_WITH(json::to_bson(j), "[json.exception.out_of_range.409] BSON key cannot contain code point U+0000 (at byte 2)");
103     }
104 
105     SECTION("string length must be at least 1")
106     {
107         // from https://bugs.chromium.org/p/oss-fuzz/issues/detail?id=11175
108         std::vector<uint8_t> v =
109         {
110             0x20, 0x20, 0x20, 0x20,
111             0x02,
112             0x00,
113             0x00, 0x00, 0x00, 0x80
114         };
115         json _;
116         CHECK_THROWS_AS(_ = json::from_bson(v), json::parse_error&);
117         CHECK_THROWS_WITH(_ = 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");
118     }
119 
120     SECTION("objects")
121     {
122         SECTION("empty object")
123         {
124             json j = json::object();
125             std::vector<uint8_t> expected =
126             {
127                 0x05, 0x00, 0x00, 0x00, // size (little endian)
128                 // no entries
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", true }
145             };
146 
147             std::vector<uint8_t> expected =
148             {
149                 0x0D, 0x00, 0x00, 0x00, // size (little endian)
150                 0x08,               // entry: boolean
151                 'e', 'n', 't', 'r', 'y', '\x00',
152                 0x01,           // value = true
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 bool")
165         {
166             json j =
167             {
168                 { "entry", false }
169             };
170 
171             std::vector<uint8_t> expected =
172             {
173                 0x0D, 0x00, 0x00, 0x00, // size (little endian)
174                 0x08,               // entry: boolean
175                 'e', 'n', 't', 'r', 'y', '\x00',
176                 0x00,           // value = false
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 double")
189         {
190             json j =
191             {
192                 { "entry", 4.2 }
193             };
194 
195             std::vector<uint8_t> expected =
196             {
197                 0x14, 0x00, 0x00, 0x00, // size (little endian)
198                 0x01, /// entry: double
199                 'e', 'n', 't', 'r', 'y', '\x00',
200                 0xcd, 0xcc, 0xcc, 0xcc, 0xcc, 0xcc, 0x10, 0x40,
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 string")
213         {
214             json j =
215             {
216                 { "entry", "bsonstr" }
217             };
218 
219             std::vector<uint8_t> expected =
220             {
221                 0x18, 0x00, 0x00, 0x00, // size (little endian)
222                 0x02, /// entry: string (UTF-8)
223                 'e', 'n', 't', 'r', 'y', '\x00',
224                 0x08, 0x00, 0x00, 0x00, 'b', 's', 'o', 'n', 's', 't', 'r', '\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 null member")
237         {
238             json j =
239             {
240                 { "entry", nullptr }
241             };
242 
243             std::vector<uint8_t> expected =
244             {
245                 0x0C, 0x00, 0x00, 0x00, // size (little endian)
246                 0x0A, /// entry: null
247                 'e', 'n', 't', 'r', 'y', '\x00',
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 (32-bit) member")
260         {
261             json j =
262             {
263                 { "entry", std::int32_t{0x12345678} }
264             };
265 
266             std::vector<uint8_t> expected =
267             {
268                 0x10, 0x00, 0x00, 0x00, // size (little endian)
269                 0x10, /// entry: int32
270                 'e', 'n', 't', 'r', 'y', '\x00',
271                 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 integer (64-bit) member")
284         {
285             json j =
286             {
287                 { "entry", std::int64_t{0x1234567804030201} }
288             };
289 
290             std::vector<uint8_t> expected =
291             {
292                 0x14, 0x00, 0x00, 0x00, // size (little endian)
293                 0x12, /// entry: int64
294                 'e', 'n', 't', 'r', 'y', '\x00',
295                 0x01, 0x02, 0x03, 0x04, 0x78, 0x56, 0x34, 0x12,
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 (32-bit) member")
308         {
309             json j =
310             {
311                 { "entry", std::int32_t{-1} }
312             };
313 
314             std::vector<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 negative integer (64-bit) member")
332         {
333             json j =
334             {
335                 { "entry", std::int64_t{-1} }
336             };
337 
338             std::vector<uint8_t> expected =
339             {
340                 0x10, 0x00, 0x00, 0x00, // size (little endian)
341                 0x10, /// entry: int32
342                 'e', 'n', 't', 'r', 'y', '\x00',
343                 0xFF, 0xFF, 0xFF, 0xFF,
344                 0x00 // end marker
345             };
346 
347             const auto result = json::to_bson(j);
348             CHECK(result == expected);
349 
350             // roundtrip
351             CHECK(json::from_bson(result) == j);
352             CHECK(json::from_bson(result, true, false) == j);
353         }
354 
355         SECTION("non-empty object with unsigned integer (64-bit) member")
356         {
357             // directly encoding uint64 is not supported in bson (only for timestamp values)
358             json j =
359             {
360                 { "entry", std::uint64_t{0x1234567804030201} }
361             };
362 
363             std::vector<uint8_t> expected =
364             {
365                 0x14, 0x00, 0x00, 0x00, // size (little endian)
366                 0x12, /// entry: int64
367                 'e', 'n', 't', 'r', 'y', '\x00',
368                 0x01, 0x02, 0x03, 0x04, 0x78, 0x56, 0x34, 0x12,
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 small unsigned integer member")
381         {
382             json j =
383             {
384                 { "entry", std::uint64_t{0x42} }
385             };
386 
387             std::vector<uint8_t> expected =
388             {
389                 0x10, 0x00, 0x00, 0x00, // size (little endian)
390                 0x10, /// entry: int32
391                 'e', 'n', 't', 'r', 'y', '\x00',
392                 0x42, 0x00, 0x00, 0x00,
393                 0x00 // end marker
394             };
395 
396             const auto result = json::to_bson(j);
397             CHECK(result == expected);
398 
399             // roundtrip
400             CHECK(json::from_bson(result) == j);
401             CHECK(json::from_bson(result, true, false) == j);
402         }
403 
404         SECTION("non-empty object with object member")
405         {
406             json j =
407             {
408                 { "entry", json::object() }
409             };
410 
411             std::vector<uint8_t> expected =
412             {
413                 0x11, 0x00, 0x00, 0x00, // size (little endian)
414                 0x03, /// entry: embedded document
415                 'e', 'n', 't', 'r', 'y', '\x00',
416 
417                 0x05, 0x00, 0x00, 0x00, // size (little endian)
418                 // no entries
419                 0x00, // end marker (embedded document)
420 
421                 0x00 // end marker
422             };
423 
424             const auto result = json::to_bson(j);
425             CHECK(result == expected);
426 
427             // roundtrip
428             CHECK(json::from_bson(result) == j);
429             CHECK(json::from_bson(result, true, false) == j);
430         }
431 
432         SECTION("non-empty object with array member")
433         {
434             json j =
435             {
436                 { "entry", json::array() }
437             };
438 
439             std::vector<uint8_t> expected =
440             {
441                 0x11, 0x00, 0x00, 0x00, // size (little endian)
442                 0x04, /// entry: embedded document
443                 'e', 'n', 't', 'r', 'y', '\x00',
444 
445                 0x05, 0x00, 0x00, 0x00, // size (little endian)
446                 // no entries
447                 0x00, // end marker (embedded document)
448 
449                 0x00 // end marker
450             };
451 
452             const auto result = json::to_bson(j);
453             CHECK(result == expected);
454 
455             // roundtrip
456             CHECK(json::from_bson(result) == j);
457             CHECK(json::from_bson(result, true, false) == j);
458         }
459 
460         SECTION("non-empty object with non-empty array member")
461         {
462             json j =
463             {
464                 { "entry", json::array({1, 2, 3, 4, 5, 6, 7, 8}) }
465             };
466 
467             std::vector<uint8_t> expected =
468             {
469                 0x49, 0x00, 0x00, 0x00, // size (little endian)
470                 0x04, /// entry: embedded document
471                 'e', 'n', 't', 'r', 'y', '\x00',
472 
473                 0x3D, 0x00, 0x00, 0x00, // size (little endian)
474                 0x10, '0', 0x00, 0x01, 0x00, 0x00, 0x00,
475                 0x10, '1', 0x00, 0x02, 0x00, 0x00, 0x00,
476                 0x10, '2', 0x00, 0x03, 0x00, 0x00, 0x00,
477                 0x10, '3', 0x00, 0x04, 0x00, 0x00, 0x00,
478                 0x10, '4', 0x00, 0x05, 0x00, 0x00, 0x00,
479                 0x10, '5', 0x00, 0x06, 0x00, 0x00, 0x00,
480                 0x10, '6', 0x00, 0x07, 0x00, 0x00, 0x00,
481                 0x10, '7', 0x00, 0x08, 0x00, 0x00, 0x00,
482                 0x00, // end marker (embedded document)
483 
484                 0x00 // end marker
485             };
486 
487             const auto result = json::to_bson(j);
488             CHECK(result == expected);
489 
490             // roundtrip
491             CHECK(json::from_bson(result) == j);
492             CHECK(json::from_bson(result, true, false) == j);
493         }
494 
495         SECTION("Some more complex document")
496         {
497             // directly encoding uint64 is not supported in bson (only for timestamp values)
498             json j =
499             {
500                 {"double", 42.5},
501                 {"entry", 4.2},
502                 {"number", 12345},
503                 {"object", {{ "string", "value" }}}
504             };
505 
506             std::vector<uint8_t> expected =
507             {
508                 /*size */ 0x4f, 0x00, 0x00, 0x00,
509                 /*entry*/ 0x01, 'd',  'o',  'u',  'b',  'l',  'e',  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x40, 0x45, 0x40,
510                 /*entry*/ 0x01, 'e',  'n',  't',  'r',  'y',  0x00, 0xcd, 0xcc, 0xcc, 0xcc, 0xcc, 0xcc, 0x10, 0x40,
511                 /*entry*/ 0x10, 'n',  'u',  'm',  'b',  'e',  'r',  0x00, 0x39, 0x30, 0x00, 0x00,
512                 /*entry*/ 0x03, 'o',  'b',  'j',  'e',  'c',  't',  0x00,
513                 /*entry: obj-size */ 0x17, 0x00, 0x00, 0x00,
514                 /*entry: obj-entry*/0x02, 's',  't',  'r',  'i',  'n',  'g', 0x00, 0x06, 0x00, 0x00, 0x00, 'v', 'a', 'l', 'u', 'e', 0,
515                 /*entry: obj-term.*/0x00,
516                 /*obj-term*/ 0x00
517             };
518 
519             const auto result = json::to_bson(j);
520             CHECK(result == expected);
521 
522             // roundtrip
523             CHECK(json::from_bson(result) == j);
524             CHECK(json::from_bson(result, true, false) == j);
525         }
526     }
527 
528     SECTION("Examples from http://bsonspec.org/faq.html")
529     {
530         SECTION("Example 1")
531         {
532             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};
533             json parsed = json::from_bson(input);
534             json expected = {{"hello", "world"}};
535             CHECK(parsed == expected);
536             auto dumped = json::to_bson(parsed);
537             CHECK(dumped == input);
538             CHECK(json::from_bson(dumped) == expected);
539         }
540 
541         SECTION("Example 2")
542         {
543             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};
544             json parsed = json::from_bson(input);
545             json expected = {{"BSON", {"awesome", 5.05, 1986}}};
546             CHECK(parsed == expected);
547             auto dumped = json::to_bson(parsed);
548             CHECK(dumped == input);
549             CHECK(json::from_bson(dumped) == expected);
550         }
551     }
552 }
553 
554 TEST_CASE("BSON input/output_adapters")
555 {
556     json json_representation =
557     {
558         {"double", 42.5},
559         {"entry", 4.2},
560         {"number", 12345},
561         {"object", {{ "string", "value" }}}
562     };
563 
564     std::vector<uint8_t> bson_representation =
565     {
566         /*size */ 0x4f, 0x00, 0x00, 0x00,
567         /*entry*/ 0x01, 'd',  'o',  'u',  'b',  'l',  'e',  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x40, 0x45, 0x40,
568         /*entry*/ 0x01, 'e',  'n',  't',  'r',  'y',  0x00, 0xcd, 0xcc, 0xcc, 0xcc, 0xcc, 0xcc, 0x10, 0x40,
569         /*entry*/ 0x10, 'n',  'u',  'm',  'b',  'e',  'r',  0x00, 0x39, 0x30, 0x00, 0x00,
570         /*entry*/ 0x03, 'o',  'b',  'j',  'e',  'c',  't',  0x00,
571         /*entry: obj-size */ 0x17, 0x00, 0x00, 0x00,
572         /*entry: obj-entry*/0x02, 's',  't',  'r',  'i',  'n',  'g', 0x00, 0x06, 0x00, 0x00, 0x00, 'v', 'a', 'l', 'u', 'e', 0,
573         /*entry: obj-term.*/0x00,
574         /*obj-term*/ 0x00
575     };
576 
577     json j2;
578     CHECK_NOTHROW(j2 = json::from_bson(bson_representation));
579 
580     // compare parsed JSON values
581     CHECK(json_representation == j2);
582 
583     SECTION("roundtrips")
584     {
585         SECTION("std::ostringstream")
586         {
587             std::basic_ostringstream<std::uint8_t> ss;
588             json::to_bson(json_representation, ss);
589             json j3 = json::from_bson(ss.str());
590             CHECK(json_representation == j3);
591         }
592 
593         SECTION("std::string")
594         {
595             std::string s;
596             json::to_bson(json_representation, s);
597             json j3 = json::from_bson(s);
598             CHECK(json_representation == j3);
599         }
600 
601         SECTION("std::vector")
602         {
603             std::vector<std::uint8_t> v;
604             json::to_bson(json_representation, v);
605             json j3 = json::from_bson(v);
606             CHECK(json_representation == j3);
607         }
608     }
609 }
610 
611 namespace
612 {
613 class SaxCountdown
614 {
615   public:
SaxCountdown(const int count)616     explicit SaxCountdown(const int count) : events_left(count)
617     {}
618 
null()619     bool null()
620     {
621         return events_left-- > 0;
622     }
623 
boolean(bool)624     bool boolean(bool)
625     {
626         return events_left-- > 0;
627     }
628 
number_integer(json::number_integer_t)629     bool number_integer(json::number_integer_t)
630     {
631         return events_left-- > 0;
632     }
633 
number_unsigned(json::number_unsigned_t)634     bool number_unsigned(json::number_unsigned_t)
635     {
636         return events_left-- > 0;
637     }
638 
number_float(json::number_float_t,const std::string &)639     bool number_float(json::number_float_t, const std::string&)
640     {
641         return events_left-- > 0;
642     }
643 
string(std::string &)644     bool string(std::string&)
645     {
646         return events_left-- > 0;
647     }
648 
start_object(std::size_t)649     bool start_object(std::size_t)
650     {
651         return events_left-- > 0;
652     }
653 
key(std::string &)654     bool key(std::string&)
655     {
656         return events_left-- > 0;
657     }
658 
end_object()659     bool end_object()
660     {
661         return events_left-- > 0;
662     }
663 
start_array(std::size_t)664     bool start_array(std::size_t)
665     {
666         return events_left-- > 0;
667     }
668 
end_array()669     bool end_array()
670     {
671         return events_left-- > 0;
672     }
673 
parse_error(std::size_t,const std::string &,const json::exception &)674     bool parse_error(std::size_t, const std::string&, const json::exception&)
675     {
676         return false;
677     }
678 
679   private:
680     int events_left = 0;
681 };
682 }
683 
684 TEST_CASE("Incomplete BSON Input")
685 {
686     SECTION("Incomplete BSON Input 1")
687     {
688         std::vector<uint8_t> incomplete_bson =
689         {
690             0x0D, 0x00, 0x00, 0x00, // size (little endian)
691             0x08,                   // entry: boolean
692             'e', 'n', 't'           // unexpected EOF
693         };
694 
695         json _;
696         CHECK_THROWS_AS(_ = json::from_bson(incomplete_bson), json::parse_error&);
697         CHECK_THROWS_WITH(_ = json::from_bson(incomplete_bson),
698                           "[json.exception.parse_error.110] parse error at byte 9: syntax error while parsing BSON cstring: unexpected end of input");
699 
700         CHECK(json::from_bson(incomplete_bson, true, false).is_discarded());
701 
702         SaxCountdown scp(0);
703         CHECK(not json::sax_parse(incomplete_bson, &scp, json::input_format_t::bson));
704     }
705 
706     SECTION("Incomplete BSON Input 2")
707     {
708         std::vector<uint8_t> incomplete_bson =
709         {
710             0x0D, 0x00, 0x00, 0x00, // size (little endian)
711             0x08,                   // entry: boolean, unexpected EOF
712         };
713 
714         json _;
715         CHECK_THROWS_AS(_ = json::from_bson(incomplete_bson), json::parse_error&);
716         CHECK_THROWS_WITH(_ = json::from_bson(incomplete_bson),
717                           "[json.exception.parse_error.110] parse error at byte 6: syntax error while parsing BSON cstring: unexpected end of input");
718         CHECK(json::from_bson(incomplete_bson, true, false).is_discarded());
719 
720         SaxCountdown scp(0);
721         CHECK(not json::sax_parse(incomplete_bson, &scp, json::input_format_t::bson));
722     }
723 
724     SECTION("Incomplete BSON Input 3")
725     {
726         std::vector<uint8_t> incomplete_bson =
727         {
728             0x41, 0x00, 0x00, 0x00, // size (little endian)
729             0x04, /// entry: embedded document
730             'e', 'n', 't', 'r', 'y', '\x00',
731 
732             0x35, 0x00, 0x00, 0x00, // size (little endian)
733             0x10, 0x00, 0x01, 0x00, 0x00, 0x00,
734             0x10, 0x00, 0x02, 0x00, 0x00, 0x00
735             // missing input data...
736         };
737 
738         json _;
739         CHECK_THROWS_AS(_ = json::from_bson(incomplete_bson), json::parse_error&);
740         CHECK_THROWS_WITH(_ = json::from_bson(incomplete_bson),
741                           "[json.exception.parse_error.110] parse error at byte 28: syntax error while parsing BSON element list: unexpected end of input");
742         CHECK(json::from_bson(incomplete_bson, true, false).is_discarded());
743 
744         SaxCountdown scp(1);
745         CHECK(not json::sax_parse(incomplete_bson, &scp, json::input_format_t::bson));
746     }
747 
748     SECTION("Incomplete BSON Input 4")
749     {
750         std::vector<uint8_t> incomplete_bson =
751         {
752             0x0D, 0x00, // size (incomplete), unexpected EOF
753         };
754 
755         json _;
756         CHECK_THROWS_AS(_ = json::from_bson(incomplete_bson), json::parse_error&);
757         CHECK_THROWS_WITH(_ = json::from_bson(incomplete_bson),
758                           "[json.exception.parse_error.110] parse error at byte 3: syntax error while parsing BSON number: unexpected end of input");
759         CHECK(json::from_bson(incomplete_bson, true, false).is_discarded());
760 
761         SaxCountdown scp(0);
762         CHECK(not json::sax_parse(incomplete_bson, &scp, json::input_format_t::bson));
763     }
764 
765     SECTION("Improve coverage")
766     {
767         SECTION("key")
768         {
769             json j = {{"key", "value"}};
770             auto bson_vec = json::to_bson(j);
771             SaxCountdown scp(2);
772             CHECK(not json::sax_parse(bson_vec, &scp, json::input_format_t::bson));
773         }
774 
775         SECTION("array")
776         {
777             json j =
778             {
779                 { "entry", json::array() }
780             };
781             auto bson_vec = json::to_bson(j);
782             SaxCountdown scp(2);
783             CHECK(not json::sax_parse(bson_vec, &scp, json::input_format_t::bson));
784         }
785     }
786 }
787 
788 TEST_CASE("Unsupported BSON input")
789 {
790     std::vector<uint8_t> bson =
791     {
792         0x0C, 0x00, 0x00, 0x00, // size (little endian)
793         0xFF,                   // entry type: Min key (not supported yet)
794         'e', 'n', 't', 'r', 'y', '\x00',
795         0x00 // end marker
796     };
797 
798     json _;
799     CHECK_THROWS_AS(_ = json::from_bson(bson), json::parse_error&);
800     CHECK_THROWS_WITH(_ = json::from_bson(bson),
801                       "[json.exception.parse_error.114] parse error at byte 5: Unsupported BSON record type 0xFF");
802     CHECK(json::from_bson(bson, true, false).is_discarded());
803 
804     SaxCountdown scp(0);
805     CHECK(not json::sax_parse(bson, &scp, json::input_format_t::bson));
806 }
807 
808 TEST_CASE("BSON numerical data")
809 {
810     SECTION("number")
811     {
812         SECTION("signed")
813         {
814             SECTION("std::int64_t: INT64_MIN .. INT32_MIN-1")
815             {
816                 std::vector<int64_t> numbers
817                 {
818                     INT64_MIN,
819                     -1000000000000000000LL,
820                     -100000000000000000LL,
821                     -10000000000000000LL,
822                     -1000000000000000LL,
823                     -100000000000000LL,
824                     -10000000000000LL,
825                     -1000000000000LL,
826                     -100000000000LL,
827                     -10000000000LL,
828                     static_cast<std::int64_t>(INT32_MIN) - 1,
829                 };
830 
831                 for (auto i : numbers)
832                 {
833 
834                     CAPTURE(i)
835 
836                     json j =
837                     {
838                         { "entry", i }
839                     };
840                     CHECK(j.at("entry").is_number_integer());
841 
842                     std::uint64_t iu = *reinterpret_cast<std::uint64_t*>(&i);
843                     std::vector<uint8_t> expected_bson =
844                     {
845                         0x14u, 0x00u, 0x00u, 0x00u, // size (little endian)
846                         0x12u, /// entry: int64
847                         'e', 'n', 't', 'r', 'y', '\x00',
848                         static_cast<uint8_t>((iu >> (8u * 0u)) & 0xffu),
849                         static_cast<uint8_t>((iu >> (8u * 1u)) & 0xffu),
850                         static_cast<uint8_t>((iu >> (8u * 2u)) & 0xffu),
851                         static_cast<uint8_t>((iu >> (8u * 3u)) & 0xffu),
852                         static_cast<uint8_t>((iu >> (8u * 4u)) & 0xffu),
853                         static_cast<uint8_t>((iu >> (8u * 5u)) & 0xffu),
854                         static_cast<uint8_t>((iu >> (8u * 6u)) & 0xffu),
855                         static_cast<uint8_t>((iu >> (8u * 7u)) & 0xffu),
856                         0x00u // end marker
857                     };
858 
859                     const auto bson = json::to_bson(j);
860                     CHECK(bson == expected_bson);
861 
862                     auto j_roundtrip = json::from_bson(bson);
863 
864                     CHECK(j_roundtrip.at("entry").is_number_integer());
865                     CHECK(j_roundtrip == j);
866                     CHECK(json::from_bson(bson, true, false) == j);
867 
868                 }
869             }
870 
871 
872             SECTION("signed std::int32_t: INT32_MIN .. INT32_MAX")
873             {
874                 std::vector<int32_t> numbers
875                 {
876                     INT32_MIN,
877                     -2147483647L,
878                     -1000000000L,
879                     -100000000L,
880                     -10000000L,
881                     -1000000L,
882                     -100000L,
883                     -10000L,
884                     -1000L,
885                     -100L,
886                     -10L,
887                     -1L,
888                     0L,
889                     1L,
890                     10L,
891                     100L,
892                     1000L,
893                     10000L,
894                     100000L,
895                     1000000L,
896                     10000000L,
897                     100000000L,
898                     1000000000L,
899                     2147483646L,
900                     INT32_MAX
901                 };
902 
903                 for (auto i : numbers)
904                 {
905 
906                     CAPTURE(i)
907 
908                     json j =
909                     {
910                         { "entry", i }
911                     };
912                     CHECK(j.at("entry").is_number_integer());
913 
914                     std::uint32_t iu = *reinterpret_cast<std::uint32_t*>(&i);
915                     std::vector<uint8_t> expected_bson =
916                     {
917                         0x10u, 0x00u, 0x00u, 0x00u, // size (little endian)
918                         0x10u, /// entry: int32
919                         'e', 'n', 't', 'r', 'y', '\x00',
920                         static_cast<uint8_t>((iu >> (8u * 0u)) & 0xffu),
921                         static_cast<uint8_t>((iu >> (8u * 1u)) & 0xffu),
922                         static_cast<uint8_t>((iu >> (8u * 2u)) & 0xffu),
923                         static_cast<uint8_t>((iu >> (8u * 3u)) & 0xffu),
924                         0x00u // end marker
925                     };
926 
927                     const auto bson = json::to_bson(j);
928                     CHECK(bson == expected_bson);
929 
930                     auto j_roundtrip = json::from_bson(bson);
931 
932                     CHECK(j_roundtrip.at("entry").is_number_integer());
933                     CHECK(j_roundtrip == j);
934                     CHECK(json::from_bson(bson, true, false) == j);
935 
936                 }
937             }
938 
939             SECTION("signed std::int64_t: INT32_MAX+1 .. INT64_MAX")
940             {
941                 std::vector<int64_t> numbers
942                 {
943                     INT64_MAX,
944                     1000000000000000000LL,
945                     100000000000000000LL,
946                     10000000000000000LL,
947                     1000000000000000LL,
948                     100000000000000LL,
949                     10000000000000LL,
950                     1000000000000LL,
951                     100000000000LL,
952                     10000000000LL,
953                     static_cast<std::int64_t>(INT32_MAX) + 1,
954                 };
955 
956                 for (auto i : numbers)
957                 {
958 
959                     CAPTURE(i)
960 
961                     json j =
962                     {
963                         { "entry", i }
964                     };
965                     CHECK(j.at("entry").is_number_integer());
966 
967                     std::uint64_t iu = *reinterpret_cast<std::uint64_t*>(&i);
968                     std::vector<uint8_t> expected_bson =
969                     {
970                         0x14u, 0x00u, 0x00u, 0x00u, // size (little endian)
971                         0x12u, /// entry: int64
972                         'e', 'n', 't', 'r', 'y', '\x00',
973                         static_cast<uint8_t>((iu >> (8u * 0u)) & 0xffu),
974                         static_cast<uint8_t>((iu >> (8u * 1u)) & 0xffu),
975                         static_cast<uint8_t>((iu >> (8u * 2u)) & 0xffu),
976                         static_cast<uint8_t>((iu >> (8u * 3u)) & 0xffu),
977                         static_cast<uint8_t>((iu >> (8u * 4u)) & 0xffu),
978                         static_cast<uint8_t>((iu >> (8u * 5u)) & 0xffu),
979                         static_cast<uint8_t>((iu >> (8u * 6u)) & 0xffu),
980                         static_cast<uint8_t>((iu >> (8u * 7u)) & 0xffu),
981                         0x00u // end marker
982                     };
983 
984                     const auto bson = json::to_bson(j);
985                     CHECK(bson == expected_bson);
986 
987                     auto j_roundtrip = json::from_bson(bson);
988 
989                     CHECK(j_roundtrip.at("entry").is_number_integer());
990                     CHECK(j_roundtrip == j);
991                     CHECK(json::from_bson(bson, true, false) == j);
992 
993                 }
994             }
995         }
996 
997         SECTION("unsigned")
998         {
999             SECTION("unsigned std::uint64_t: 0 .. INT32_MAX")
1000             {
1001                 std::vector<std::uint64_t> numbers
1002                 {
1003                     0ULL,
1004                     1ULL,
1005                     10ULL,
1006                     100ULL,
1007                     1000ULL,
1008                     10000ULL,
1009                     100000ULL,
1010                     1000000ULL,
1011                     10000000ULL,
1012                     100000000ULL,
1013                     1000000000ULL,
1014                     2147483646ULL,
1015                     static_cast<std::uint64_t>(INT32_MAX)
1016                 };
1017 
1018                 for (auto i : numbers)
1019                 {
1020 
1021                     CAPTURE(i)
1022 
1023                     json j =
1024                     {
1025                         { "entry", i }
1026                     };
1027 
1028                     auto iu = i;
1029                     std::vector<uint8_t> expected_bson =
1030                     {
1031                         0x10u, 0x00u, 0x00u, 0x00u, // size (little endian)
1032                         0x10u, /// entry: int32
1033                         'e', 'n', 't', 'r', 'y', '\x00',
1034                         static_cast<uint8_t>((iu >> (8u * 0u)) & 0xffu),
1035                         static_cast<uint8_t>((iu >> (8u * 1u)) & 0xffu),
1036                         static_cast<uint8_t>((iu >> (8u * 2u)) & 0xffu),
1037                         static_cast<uint8_t>((iu >> (8u * 3u)) & 0xffu),
1038                         0x00u // end marker
1039                     };
1040 
1041                     const auto bson = json::to_bson(j);
1042                     CHECK(bson == expected_bson);
1043 
1044                     auto j_roundtrip = json::from_bson(bson);
1045 
1046                     CHECK(j.at("entry").is_number_unsigned());
1047                     CHECK(j_roundtrip.at("entry").is_number_integer());
1048                     CHECK(j_roundtrip == j);
1049                     CHECK(json::from_bson(bson, true, false) == j);
1050 
1051                 }
1052             }
1053 
1054             SECTION("unsigned std::uint64_t: INT32_MAX+1 .. INT64_MAX")
1055             {
1056                 std::vector<std::uint64_t> numbers
1057                 {
1058                     static_cast<std::uint64_t>(INT32_MAX) + 1,
1059                     4000000000ULL,
1060                     static_cast<std::uint64_t>(UINT32_MAX),
1061                     10000000000ULL,
1062                     100000000000ULL,
1063                     1000000000000ULL,
1064                     10000000000000ULL,
1065                     100000000000000ULL,
1066                     1000000000000000ULL,
1067                     10000000000000000ULL,
1068                     100000000000000000ULL,
1069                     1000000000000000000ULL,
1070                     static_cast<std::uint64_t>(INT64_MAX),
1071                 };
1072 
1073                 for (auto i : numbers)
1074                 {
1075 
1076                     CAPTURE(i)
1077 
1078                     json j =
1079                     {
1080                         { "entry", i }
1081                     };
1082 
1083                     auto iu = i;
1084                     std::vector<uint8_t> expected_bson =
1085                     {
1086                         0x14u, 0x00u, 0x00u, 0x00u, // size (little endian)
1087                         0x12u, /// entry: int64
1088                         'e', 'n', 't', 'r', 'y', '\x00',
1089                         static_cast<uint8_t>((iu >> (8u * 0u)) & 0xffu),
1090                         static_cast<uint8_t>((iu >> (8u * 1u)) & 0xffu),
1091                         static_cast<uint8_t>((iu >> (8u * 2u)) & 0xffu),
1092                         static_cast<uint8_t>((iu >> (8u * 3u)) & 0xffu),
1093                         static_cast<uint8_t>((iu >> (8u * 4u)) & 0xffu),
1094                         static_cast<uint8_t>((iu >> (8u * 5u)) & 0xffu),
1095                         static_cast<uint8_t>((iu >> (8u * 6u)) & 0xffu),
1096                         static_cast<uint8_t>((iu >> (8u * 7u)) & 0xffu),
1097                         0x00u // end marker
1098                     };
1099 
1100                     const auto bson = json::to_bson(j);
1101                     CHECK(bson == expected_bson);
1102 
1103                     auto j_roundtrip = json::from_bson(bson);
1104 
1105                     CHECK(j.at("entry").is_number_unsigned());
1106                     CHECK(j_roundtrip.at("entry").is_number_integer());
1107                     CHECK(j_roundtrip == j);
1108                     CHECK(json::from_bson(bson, true, false) == j);
1109                 }
1110             }
1111 
1112             SECTION("unsigned std::uint64_t: INT64_MAX+1 .. UINT64_MAX")
1113             {
1114                 std::vector<std::uint64_t> numbers
1115                 {
1116                     static_cast<std::uint64_t>(INT64_MAX) + 1ULL,
1117                     10000000000000000000ULL,
1118                     18000000000000000000ULL,
1119                     UINT64_MAX - 1ULL,
1120                     UINT64_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<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<uint8_t>((iu >> (8u * 0u)) & 0xffu),
1140                         static_cast<uint8_t>((iu >> (8u * 1u)) & 0xffu),
1141                         static_cast<uint8_t>((iu >> (8u * 2u)) & 0xffu),
1142                         static_cast<uint8_t>((iu >> (8u * 3u)) & 0xffu),
1143                         static_cast<uint8_t>((iu >> (8u * 4u)) & 0xffu),
1144                         static_cast<uint8_t>((iu >> (8u * 5u)) & 0xffu),
1145                         static_cast<uint8_t>((iu >> (8u * 6u)) & 0xffu),
1146                         static_cast<uint8_t>((iu >> (8u * 7u)) & 0xffu),
1147                         0x00u // end marker
1148                     };
1149 
1150                     CHECK_THROWS_AS(json::to_bson(j), json::out_of_range&);
1151                     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");
1152                 }
1153             }
1154 
1155         }
1156     }
1157 }
1158 
skip()1159 TEST_CASE("BSON roundtrips" * doctest::skip())
1160 {
1161     SECTION("reference files")
1162     {
1163         for (std::string filename :
1164                 {
1165                     "test/data/json.org/1.json",
1166                     "test/data/json.org/2.json",
1167                     "test/data/json.org/3.json",
1168                     "test/data/json.org/4.json",
1169                     "test/data/json.org/5.json"
1170                 })
1171         {
1172             CAPTURE(filename)
1173 
1174             {
1175                 INFO_WITH_TEMP(filename + ": std::vector<uint8_t>");
1176                 // parse JSON file
1177                 std::ifstream f_json(filename);
1178                 json j1 = json::parse(f_json);
1179 
1180                 // parse BSON file
1181                 std::ifstream f_bson(filename + ".bson", std::ios::binary);
1182                 std::vector<uint8_t> packed(
1183                     (std::istreambuf_iterator<char>(f_bson)),
1184                     std::istreambuf_iterator<char>());
1185                 json j2;
1186                 CHECK_NOTHROW(j2 = json::from_bson(packed));
1187 
1188                 // compare parsed JSON values
1189                 CHECK(j1 == j2);
1190             }
1191 
1192             {
1193                 INFO_WITH_TEMP(filename + ": std::ifstream");
1194                 // parse JSON file
1195                 std::ifstream f_json(filename);
1196                 json j1 = json::parse(f_json);
1197 
1198                 // parse BSON file
1199                 std::ifstream f_bson(filename + ".bson", std::ios::binary);
1200                 json j2;
1201                 CHECK_NOTHROW(j2 = json::from_bson(f_bson));
1202 
1203                 // compare parsed JSON values
1204                 CHECK(j1 == j2);
1205             }
1206 
1207             {
1208                 INFO_WITH_TEMP(filename + ": uint8_t* and size");
1209                 // parse JSON file
1210                 std::ifstream f_json(filename);
1211                 json j1 = json::parse(f_json);
1212 
1213                 // parse BSON file
1214                 std::ifstream f_bson(filename + ".bson", std::ios::binary);
1215                 std::vector<uint8_t> packed(
1216                     (std::istreambuf_iterator<char>(f_bson)),
1217                     std::istreambuf_iterator<char>());
1218                 json j2;
1219                 CHECK_NOTHROW(j2 = json::from_bson({packed.data(), packed.size()}));
1220 
1221                 // compare parsed JSON values
1222                 CHECK(j1 == j2);
1223             }
1224 
1225             {
1226                 INFO_WITH_TEMP(filename + ": output to output adapters");
1227                 // parse JSON file
1228                 std::ifstream f_json(filename);
1229                 json j1 = json::parse(f_json);
1230 
1231                 // parse BSON file
1232                 std::ifstream f_bson(filename + ".bson", std::ios::binary);
1233                 std::vector<uint8_t> packed(
1234                     (std::istreambuf_iterator<char>(f_bson)),
1235                     std::istreambuf_iterator<char>());
1236 
1237                 {
1238                     INFO_WITH_TEMP(filename + ": output adapters: std::vector<uint8_t>");
1239                     std::vector<uint8_t> vec;
1240                     json::to_bson(j1, vec);
1241 
1242                     if (vec != packed)
1243                     {
1244                         // the exact serializations may differ due to the order of
1245                         // object keys; in these cases, just compare whether both
1246                         // serializations create the same JSON value
1247                         CHECK(json::from_bson(vec) == json::from_bson(packed));
1248                     }
1249                 }
1250             }
1251         }
1252     }
1253 }
1254