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