1 /*
2 __ _____ _____ _____
3 __| | __| | | | JSON for Modern C++ (test suite)
4 | | |__ | | | | | | version 3.9.1
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 #include <test_data.hpp>
38 #include "test_utils.hpp"
39
40 TEST_CASE("BSON")
41 {
42 SECTION("individual values not supported")
43 {
44 SECTION("null")
45 {
46 json j = nullptr;
47 CHECK_THROWS_AS(json::to_bson(j), json::type_error&);
48 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");
49 }
50
51 SECTION("boolean")
52 {
53 SECTION("true")
54 {
55 json j = true;
56 CHECK_THROWS_AS(json::to_bson(j), json::type_error&);
57 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");
58 }
59
60 SECTION("false")
61 {
62 json j = false;
63 CHECK_THROWS_AS(json::to_bson(j), json::type_error&);
64 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");
65 }
66 }
67
68 SECTION("number")
69 {
70 json j = 42;
71 CHECK_THROWS_AS(json::to_bson(j), json::type_error&);
72 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");
73 }
74
75 SECTION("float")
76 {
77 json j = 4.2;
78 CHECK_THROWS_AS(json::to_bson(j), json::type_error&);
79 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");
80 }
81
82 SECTION("string")
83 {
84 json j = "not supported";
85 CHECK_THROWS_AS(json::to_bson(j), json::type_error&);
86 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");
87 }
88
89 SECTION("array")
90 {
91 json j = std::vector<int> {1, 2, 3, 4, 5, 6, 7};
92 CHECK_THROWS_AS(json::to_bson(j), json::type_error&);
93 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");
94 }
95 }
96
97 SECTION("keys containing code-point U+0000 cannot be serialized to BSON")
98 {
99 json j =
100 {
101 { std::string("en\0try", 6), true }
102 };
103 CHECK_THROWS_AS(json::to_bson(j), json::out_of_range&);
104 CHECK_THROWS_WITH(json::to_bson(j), "[json.exception.out_of_range.409] BSON key cannot contain code point U+0000 (at byte 2)");
105 }
106
107 SECTION("string length must be at least 1")
108 {
109 // from https://bugs.chromium.org/p/oss-fuzz/issues/detail?id=11175
110 std::vector<std::uint8_t> v =
111 {
112 0x20, 0x20, 0x20, 0x20,
113 0x02,
114 0x00,
115 0x00, 0x00, 0x00, 0x80
116 };
117 json _;
118 CHECK_THROWS_AS(_ = json::from_bson(v), json::parse_error&);
119 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");
120 }
121
122 SECTION("objects")
123 {
124 SECTION("empty object")
125 {
126 json j = json::object();
127 std::vector<std::uint8_t> expected =
128 {
129 0x05, 0x00, 0x00, 0x00, // size (little endian)
130 // no entries
131 0x00 // end marker
132 };
133
134 const auto result = json::to_bson(j);
135 CHECK(result == expected);
136
137 // roundtrip
138 CHECK(json::from_bson(result) == j);
139 CHECK(json::from_bson(result, true, false) == j);
140 }
141
142 SECTION("non-empty object with bool")
143 {
144 json j =
145 {
146 { "entry", true }
147 };
148
149 std::vector<std::uint8_t> expected =
150 {
151 0x0D, 0x00, 0x00, 0x00, // size (little endian)
152 0x08, // entry: boolean
153 'e', 'n', 't', 'r', 'y', '\x00',
154 0x01, // value = true
155 0x00 // end marker
156 };
157
158 const auto result = json::to_bson(j);
159 CHECK(result == expected);
160
161 // roundtrip
162 CHECK(json::from_bson(result) == j);
163 CHECK(json::from_bson(result, true, false) == j);
164 }
165
166 SECTION("non-empty object with bool")
167 {
168 json j =
169 {
170 { "entry", false }
171 };
172
173 std::vector<std::uint8_t> expected =
174 {
175 0x0D, 0x00, 0x00, 0x00, // size (little endian)
176 0x08, // entry: boolean
177 'e', 'n', 't', 'r', 'y', '\x00',
178 0x00, // value = false
179 0x00 // end marker
180 };
181
182 const auto result = json::to_bson(j);
183 CHECK(result == expected);
184
185 // roundtrip
186 CHECK(json::from_bson(result) == j);
187 CHECK(json::from_bson(result, true, false) == j);
188 }
189
190 SECTION("non-empty object with double")
191 {
192 json j =
193 {
194 { "entry", 4.2 }
195 };
196
197 std::vector<std::uint8_t> expected =
198 {
199 0x14, 0x00, 0x00, 0x00, // size (little endian)
200 0x01, /// entry: double
201 'e', 'n', 't', 'r', 'y', '\x00',
202 0xcd, 0xcc, 0xcc, 0xcc, 0xcc, 0xcc, 0x10, 0x40,
203 0x00 // end marker
204 };
205
206 const auto result = json::to_bson(j);
207 CHECK(result == expected);
208
209 // roundtrip
210 CHECK(json::from_bson(result) == j);
211 CHECK(json::from_bson(result, true, false) == j);
212 }
213
214 SECTION("non-empty object with string")
215 {
216 json j =
217 {
218 { "entry", "bsonstr" }
219 };
220
221 std::vector<std::uint8_t> expected =
222 {
223 0x18, 0x00, 0x00, 0x00, // size (little endian)
224 0x02, /// entry: string (UTF-8)
225 'e', 'n', 't', 'r', 'y', '\x00',
226 0x08, 0x00, 0x00, 0x00, 'b', 's', 'o', 'n', 's', 't', 'r', '\x00',
227 0x00 // end marker
228 };
229
230 const auto result = json::to_bson(j);
231 CHECK(result == expected);
232
233 // roundtrip
234 CHECK(json::from_bson(result) == j);
235 CHECK(json::from_bson(result, true, false) == j);
236 }
237
238 SECTION("non-empty object with null member")
239 {
240 json j =
241 {
242 { "entry", nullptr }
243 };
244
245 std::vector<std::uint8_t> expected =
246 {
247 0x0C, 0x00, 0x00, 0x00, // size (little endian)
248 0x0A, /// entry: null
249 'e', 'n', 't', 'r', 'y', '\x00',
250 0x00 // end marker
251 };
252
253 const auto result = json::to_bson(j);
254 CHECK(result == expected);
255
256 // roundtrip
257 CHECK(json::from_bson(result) == j);
258 CHECK(json::from_bson(result, true, false) == j);
259 }
260
261 SECTION("non-empty object with integer (32-bit) member")
262 {
263 json j =
264 {
265 { "entry", std::int32_t{0x12345678} }
266 };
267
268 std::vector<std::uint8_t> expected =
269 {
270 0x10, 0x00, 0x00, 0x00, // size (little endian)
271 0x10, /// entry: int32
272 'e', 'n', 't', 'r', 'y', '\x00',
273 0x78, 0x56, 0x34, 0x12,
274 0x00 // end marker
275 };
276
277 const auto result = json::to_bson(j);
278 CHECK(result == expected);
279
280 // roundtrip
281 CHECK(json::from_bson(result) == j);
282 CHECK(json::from_bson(result, true, false) == j);
283 }
284
285 SECTION("non-empty object with integer (64-bit) member")
286 {
287 json j =
288 {
289 { "entry", std::int64_t{0x1234567804030201} }
290 };
291
292 std::vector<std::uint8_t> expected =
293 {
294 0x14, 0x00, 0x00, 0x00, // size (little endian)
295 0x12, /// entry: int64
296 'e', 'n', 't', 'r', 'y', '\x00',
297 0x01, 0x02, 0x03, 0x04, 0x78, 0x56, 0x34, 0x12,
298 0x00 // end marker
299 };
300
301 const auto result = json::to_bson(j);
302 CHECK(result == expected);
303
304 // roundtrip
305 CHECK(json::from_bson(result) == j);
306 CHECK(json::from_bson(result, true, false) == j);
307 }
308
309 SECTION("non-empty object with negative integer (32-bit) member")
310 {
311 json j =
312 {
313 { "entry", std::int32_t{-1} }
314 };
315
316 std::vector<std::uint8_t> expected =
317 {
318 0x10, 0x00, 0x00, 0x00, // size (little endian)
319 0x10, /// entry: int32
320 'e', 'n', 't', 'r', 'y', '\x00',
321 0xFF, 0xFF, 0xFF, 0xFF,
322 0x00 // end marker
323 };
324
325 const auto result = json::to_bson(j);
326 CHECK(result == expected);
327
328 // roundtrip
329 CHECK(json::from_bson(result) == j);
330 CHECK(json::from_bson(result, true, false) == j);
331 }
332
333 SECTION("non-empty object with negative integer (64-bit) member")
334 {
335 json j =
336 {
337 { "entry", std::int64_t{-1} }
338 };
339
340 std::vector<std::uint8_t> expected =
341 {
342 0x10, 0x00, 0x00, 0x00, // size (little endian)
343 0x10, /// entry: int32
344 'e', 'n', 't', 'r', 'y', '\x00',
345 0xFF, 0xFF, 0xFF, 0xFF,
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 unsigned integer (64-bit) member")
358 {
359 // directly encoding uint64 is not supported in bson (only for timestamp values)
360 json j =
361 {
362 { "entry", std::uint64_t{0x1234567804030201} }
363 };
364
365 std::vector<std::uint8_t> expected =
366 {
367 0x14, 0x00, 0x00, 0x00, // size (little endian)
368 0x12, /// entry: int64
369 'e', 'n', 't', 'r', 'y', '\x00',
370 0x01, 0x02, 0x03, 0x04, 0x78, 0x56, 0x34, 0x12,
371 0x00 // end marker
372 };
373
374 const auto result = json::to_bson(j);
375 CHECK(result == expected);
376
377 // roundtrip
378 CHECK(json::from_bson(result) == j);
379 CHECK(json::from_bson(result, true, false) == j);
380 }
381
382 SECTION("non-empty object with small unsigned integer member")
383 {
384 json j =
385 {
386 { "entry", std::uint64_t{0x42} }
387 };
388
389 std::vector<std::uint8_t> expected =
390 {
391 0x10, 0x00, 0x00, 0x00, // size (little endian)
392 0x10, /// entry: int32
393 'e', 'n', 't', 'r', 'y', '\x00',
394 0x42, 0x00, 0x00, 0x00,
395 0x00 // end marker
396 };
397
398 const auto result = json::to_bson(j);
399 CHECK(result == expected);
400
401 // roundtrip
402 CHECK(json::from_bson(result) == j);
403 CHECK(json::from_bson(result, true, false) == j);
404 }
405
406 SECTION("non-empty object with object member")
407 {
408 json j =
409 {
410 { "entry", json::object() }
411 };
412
413 std::vector<std::uint8_t> expected =
414 {
415 0x11, 0x00, 0x00, 0x00, // size (little endian)
416 0x03, /// entry: embedded document
417 'e', 'n', 't', 'r', 'y', '\x00',
418
419 0x05, 0x00, 0x00, 0x00, // size (little endian)
420 // no entries
421 0x00, // end marker (embedded document)
422
423 0x00 // end marker
424 };
425
426 const auto result = json::to_bson(j);
427 CHECK(result == expected);
428
429 // roundtrip
430 CHECK(json::from_bson(result) == j);
431 CHECK(json::from_bson(result, true, false) == j);
432 }
433
434 SECTION("non-empty object with array member")
435 {
436 json j =
437 {
438 { "entry", json::array() }
439 };
440
441 std::vector<std::uint8_t> expected =
442 {
443 0x11, 0x00, 0x00, 0x00, // size (little endian)
444 0x04, /// entry: embedded document
445 'e', 'n', 't', 'r', 'y', '\x00',
446
447 0x05, 0x00, 0x00, 0x00, // size (little endian)
448 // no entries
449 0x00, // end marker (embedded document)
450
451 0x00 // end marker
452 };
453
454 const auto result = json::to_bson(j);
455 CHECK(result == expected);
456
457 // roundtrip
458 CHECK(json::from_bson(result) == j);
459 CHECK(json::from_bson(result, true, false) == j);
460 }
461
462 SECTION("non-empty object with non-empty array member")
463 {
464 json j =
465 {
466 { "entry", json::array({1, 2, 3, 4, 5, 6, 7, 8}) }
467 };
468
469 std::vector<std::uint8_t> expected =
470 {
471 0x49, 0x00, 0x00, 0x00, // size (little endian)
472 0x04, /// entry: embedded document
473 'e', 'n', 't', 'r', 'y', '\x00',
474
475 0x3D, 0x00, 0x00, 0x00, // size (little endian)
476 0x10, '0', 0x00, 0x01, 0x00, 0x00, 0x00,
477 0x10, '1', 0x00, 0x02, 0x00, 0x00, 0x00,
478 0x10, '2', 0x00, 0x03, 0x00, 0x00, 0x00,
479 0x10, '3', 0x00, 0x04, 0x00, 0x00, 0x00,
480 0x10, '4', 0x00, 0x05, 0x00, 0x00, 0x00,
481 0x10, '5', 0x00, 0x06, 0x00, 0x00, 0x00,
482 0x10, '6', 0x00, 0x07, 0x00, 0x00, 0x00,
483 0x10, '7', 0x00, 0x08, 0x00, 0x00, 0x00,
484 0x00, // end marker (embedded document)
485
486 0x00 // end marker
487 };
488
489 const auto result = json::to_bson(j);
490 CHECK(result == expected);
491
492 // roundtrip
493 CHECK(json::from_bson(result) == j);
494 CHECK(json::from_bson(result, true, false) == j);
495 }
496
497 SECTION("non-empty object with binary member")
498 {
499 const size_t N = 10;
500 const auto s = std::vector<std::uint8_t>(N, 'x');
501 json j =
502 {
503 { "entry", json::binary(s, 0) }
504 };
505
506 std::vector<std::uint8_t> expected =
507 {
508 0x1B, 0x00, 0x00, 0x00, // size (little endian)
509 0x05, // entry: binary
510 'e', 'n', 't', 'r', 'y', '\x00',
511
512 0x0A, 0x00, 0x00, 0x00, // size of binary (little endian)
513 0x00, // Generic binary subtype
514 0x78, 0x78, 0x78, 0x78, 0x78, 0x78, 0x78, 0x78, 0x78, 0x78,
515
516 0x00 // end marker
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 SECTION("non-empty object with binary member with subtype")
528 {
529 // an MD5 hash
530 const std::vector<std::uint8_t> md5hash = {0xd7, 0x7e, 0x27, 0x54, 0xbe, 0x12, 0x37, 0xfe, 0xd6, 0x0c, 0x33, 0x98, 0x30, 0x3b, 0x8d, 0xc4};
531 json j =
532 {
533 { "entry", json::binary(md5hash, 5) }
534 };
535
536 std::vector<std::uint8_t> expected =
537 {
538 0x21, 0x00, 0x00, 0x00, // size (little endian)
539 0x05, // entry: binary
540 'e', 'n', 't', 'r', 'y', '\x00',
541
542 0x10, 0x00, 0x00, 0x00, // size of binary (little endian)
543 0x05, // MD5 binary subtype
544 0xd7, 0x7e, 0x27, 0x54, 0xbe, 0x12, 0x37, 0xfe, 0xd6, 0x0c, 0x33, 0x98, 0x30, 0x3b, 0x8d, 0xc4,
545
546 0x00 // end marker
547 };
548
549 const auto result = json::to_bson(j);
550 CHECK(result == expected);
551
552 // roundtrip
553 CHECK(json::from_bson(result) == j);
554 CHECK(json::from_bson(result, true, false) == j);
555 }
556
557 SECTION("Some more complex document")
558 {
559 // directly encoding uint64 is not supported in bson (only for timestamp values)
560 json j =
561 {
562 {"double", 42.5},
563 {"entry", 4.2},
564 {"number", 12345},
565 {"object", {{ "string", "value" }}}
566 };
567
568 std::vector<std::uint8_t> expected =
569 {
570 /*size */ 0x4f, 0x00, 0x00, 0x00,
571 /*entry*/ 0x01, 'd', 'o', 'u', 'b', 'l', 'e', 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x40, 0x45, 0x40,
572 /*entry*/ 0x01, 'e', 'n', 't', 'r', 'y', 0x00, 0xcd, 0xcc, 0xcc, 0xcc, 0xcc, 0xcc, 0x10, 0x40,
573 /*entry*/ 0x10, 'n', 'u', 'm', 'b', 'e', 'r', 0x00, 0x39, 0x30, 0x00, 0x00,
574 /*entry*/ 0x03, 'o', 'b', 'j', 'e', 'c', 't', 0x00,
575 /*entry: obj-size */ 0x17, 0x00, 0x00, 0x00,
576 /*entry: obj-entry*/0x02, 's', 't', 'r', 'i', 'n', 'g', 0x00, 0x06, 0x00, 0x00, 0x00, 'v', 'a', 'l', 'u', 'e', 0,
577 /*entry: obj-term.*/0x00,
578 /*obj-term*/ 0x00
579 };
580
581 const auto result = json::to_bson(j);
582 CHECK(result == expected);
583
584 // roundtrip
585 CHECK(json::from_bson(result) == j);
586 CHECK(json::from_bson(result, true, false) == j);
587 }
588 }
589
590 SECTION("Examples from http://bsonspec.org/faq.html")
591 {
592 SECTION("Example 1")
593 {
594 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};
595 json parsed = json::from_bson(input);
596 json expected = {{"hello", "world"}};
597 CHECK(parsed == expected);
598 auto dumped = json::to_bson(parsed);
599 CHECK(dumped == input);
600 CHECK(json::from_bson(dumped) == expected);
601 }
602
603 SECTION("Example 2")
604 {
605 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};
606 json parsed = json::from_bson(input);
607 json expected = {{"BSON", {"awesome", 5.05, 1986}}};
608 CHECK(parsed == expected);
609 auto dumped = json::to_bson(parsed);
610 CHECK(dumped == input);
611 CHECK(json::from_bson(dumped) == expected);
612 }
613 }
614 }
615
616 TEST_CASE("BSON input/output_adapters")
617 {
618 json json_representation =
619 {
620 {"double", 42.5},
621 {"entry", 4.2},
622 {"number", 12345},
623 {"object", {{ "string", "value" }}}
624 };
625
626 std::vector<std::uint8_t> bson_representation =
627 {
628 /*size */ 0x4f, 0x00, 0x00, 0x00,
629 /*entry*/ 0x01, 'd', 'o', 'u', 'b', 'l', 'e', 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x40, 0x45, 0x40,
630 /*entry*/ 0x01, 'e', 'n', 't', 'r', 'y', 0x00, 0xcd, 0xcc, 0xcc, 0xcc, 0xcc, 0xcc, 0x10, 0x40,
631 /*entry*/ 0x10, 'n', 'u', 'm', 'b', 'e', 'r', 0x00, 0x39, 0x30, 0x00, 0x00,
632 /*entry*/ 0x03, 'o', 'b', 'j', 'e', 'c', 't', 0x00,
633 /*entry: obj-size */ 0x17, 0x00, 0x00, 0x00,
634 /*entry: obj-entry*/0x02, 's', 't', 'r', 'i', 'n', 'g', 0x00, 0x06, 0x00, 0x00, 0x00, 'v', 'a', 'l', 'u', 'e', 0,
635 /*entry: obj-term.*/0x00,
636 /*obj-term*/ 0x00
637 };
638
639 json j2;
640 CHECK_NOTHROW(j2 = json::from_bson(bson_representation));
641
642 // compare parsed JSON values
643 CHECK(json_representation == j2);
644
645 SECTION("roundtrips")
646 {
647 SECTION("std::ostringstream")
648 {
649 std::basic_ostringstream<std::uint8_t> ss;
650 json::to_bson(json_representation, ss);
651 json j3 = json::from_bson(ss.str());
652 CHECK(json_representation == j3);
653 }
654
655 SECTION("std::string")
656 {
657 std::string s;
658 json::to_bson(json_representation, s);
659 json j3 = json::from_bson(s);
660 CHECK(json_representation == j3);
661 }
662
663 SECTION("std::vector")
664 {
665 std::vector<std::uint8_t> v;
666 json::to_bson(json_representation, v);
667 json j3 = json::from_bson(v);
668 CHECK(json_representation == j3);
669 }
670 }
671 }
672
673 namespace
674 {
675 class SaxCountdown
676 {
677 public:
SaxCountdown(const int count)678 explicit SaxCountdown(const int count) : events_left(count)
679 {}
680
null()681 bool null()
682 {
683 return events_left-- > 0;
684 }
685
boolean(bool)686 bool boolean(bool)
687 {
688 return events_left-- > 0;
689 }
690
number_integer(json::number_integer_t)691 bool number_integer(json::number_integer_t)
692 {
693 return events_left-- > 0;
694 }
695
number_unsigned(json::number_unsigned_t)696 bool number_unsigned(json::number_unsigned_t)
697 {
698 return events_left-- > 0;
699 }
700
number_float(json::number_float_t,const std::string &)701 bool number_float(json::number_float_t, const std::string&)
702 {
703 return events_left-- > 0;
704 }
705
string(std::string &)706 bool string(std::string&)
707 {
708 return events_left-- > 0;
709 }
710
binary(std::vector<std::uint8_t> &)711 bool binary(std::vector<std::uint8_t>&)
712 {
713 return events_left-- > 0;
714 }
715
start_object(std::size_t)716 bool start_object(std::size_t)
717 {
718 return events_left-- > 0;
719 }
720
key(std::string &)721 bool key(std::string&)
722 {
723 return events_left-- > 0;
724 }
725
end_object()726 bool end_object()
727 {
728 return events_left-- > 0;
729 }
730
start_array(std::size_t)731 bool start_array(std::size_t)
732 {
733 return events_left-- > 0;
734 }
735
end_array()736 bool end_array()
737 {
738 return events_left-- > 0;
739 }
740
parse_error(std::size_t,const std::string &,const json::exception &)741 bool parse_error(std::size_t, const std::string&, const json::exception&)
742 {
743 return false;
744 }
745
746 private:
747 int events_left = 0;
748 };
749 }
750
751 TEST_CASE("Incomplete BSON Input")
752 {
753 SECTION("Incomplete BSON Input 1")
754 {
755 std::vector<std::uint8_t> incomplete_bson =
756 {
757 0x0D, 0x00, 0x00, 0x00, // size (little endian)
758 0x08, // entry: boolean
759 'e', 'n', 't' // unexpected EOF
760 };
761
762 json _;
763 CHECK_THROWS_AS(_ = json::from_bson(incomplete_bson), json::parse_error&);
764 CHECK_THROWS_WITH(_ = json::from_bson(incomplete_bson),
765 "[json.exception.parse_error.110] parse error at byte 9: syntax error while parsing BSON cstring: unexpected end of input");
766
767 CHECK(json::from_bson(incomplete_bson, true, false).is_discarded());
768
769 SaxCountdown scp(0);
770 CHECK(!json::sax_parse(incomplete_bson, &scp, json::input_format_t::bson));
771 }
772
773 SECTION("Incomplete BSON Input 2")
774 {
775 std::vector<std::uint8_t> incomplete_bson =
776 {
777 0x0D, 0x00, 0x00, 0x00, // size (little endian)
778 0x08, // entry: boolean, unexpected EOF
779 };
780
781 json _;
782 CHECK_THROWS_AS(_ = json::from_bson(incomplete_bson), json::parse_error&);
783 CHECK_THROWS_WITH(_ = json::from_bson(incomplete_bson),
784 "[json.exception.parse_error.110] parse error at byte 6: syntax error while parsing BSON cstring: unexpected end of input");
785 CHECK(json::from_bson(incomplete_bson, true, false).is_discarded());
786
787 SaxCountdown scp(0);
788 CHECK(!json::sax_parse(incomplete_bson, &scp, json::input_format_t::bson));
789 }
790
791 SECTION("Incomplete BSON Input 3")
792 {
793 std::vector<std::uint8_t> incomplete_bson =
794 {
795 0x41, 0x00, 0x00, 0x00, // size (little endian)
796 0x04, /// entry: embedded document
797 'e', 'n', 't', 'r', 'y', '\x00',
798
799 0x35, 0x00, 0x00, 0x00, // size (little endian)
800 0x10, 0x00, 0x01, 0x00, 0x00, 0x00,
801 0x10, 0x00, 0x02, 0x00, 0x00, 0x00
802 // missing input data...
803 };
804
805 json _;
806 CHECK_THROWS_AS(_ = json::from_bson(incomplete_bson), json::parse_error&);
807 CHECK_THROWS_WITH(_ = json::from_bson(incomplete_bson),
808 "[json.exception.parse_error.110] parse error at byte 28: syntax error while parsing BSON element list: unexpected end of input");
809 CHECK(json::from_bson(incomplete_bson, true, false).is_discarded());
810
811 SaxCountdown scp(1);
812 CHECK(!json::sax_parse(incomplete_bson, &scp, json::input_format_t::bson));
813 }
814
815 SECTION("Incomplete BSON Input 4")
816 {
817 std::vector<std::uint8_t> incomplete_bson =
818 {
819 0x0D, 0x00, // size (incomplete), unexpected EOF
820 };
821
822 json _;
823 CHECK_THROWS_AS(_ = json::from_bson(incomplete_bson), json::parse_error&);
824 CHECK_THROWS_WITH(_ = json::from_bson(incomplete_bson),
825 "[json.exception.parse_error.110] parse error at byte 3: syntax error while parsing BSON number: unexpected end of input");
826 CHECK(json::from_bson(incomplete_bson, true, false).is_discarded());
827
828 SaxCountdown scp(0);
829 CHECK(!json::sax_parse(incomplete_bson, &scp, json::input_format_t::bson));
830 }
831
832 SECTION("Improve coverage")
833 {
834 SECTION("key")
835 {
836 json j = {{"key", "value"}};
837 auto bson_vec = json::to_bson(j);
838 SaxCountdown scp(2);
839 CHECK(!json::sax_parse(bson_vec, &scp, json::input_format_t::bson));
840 }
841
842 SECTION("array")
843 {
844 json j =
845 {
846 { "entry", json::array() }
847 };
848 auto bson_vec = json::to_bson(j);
849 SaxCountdown scp(2);
850 CHECK(!json::sax_parse(bson_vec, &scp, json::input_format_t::bson));
851 }
852 }
853 }
854
855 TEST_CASE("Negative size of binary value")
856 {
857 // invalid BSON: the size of the binary value is -1
858 std::vector<std::uint8_t> input =
859 {
860 0x21, 0x00, 0x00, 0x00, // size (little endian)
861 0x05, // entry: binary
862 'e', 'n', 't', 'r', 'y', '\x00',
863
864 0xFF, 0xFF, 0xFF, 0xFF, // size of binary (little endian)
865 0x05, // MD5 binary subtype
866 0xd7, 0x7e, 0x27, 0x54, 0xbe, 0x12, 0x37, 0xfe, 0xd6, 0x0c, 0x33, 0x98, 0x30, 0x3b, 0x8d, 0xc4,
867
868 0x00 // end marker
869 };
870 CHECK_THROWS_AS(json::from_bson(input), json::parse_error);
871 CHECK_THROWS_WITH(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");
872 }
873
874 TEST_CASE("Unsupported BSON input")
875 {
876 std::vector<std::uint8_t> bson =
877 {
878 0x0C, 0x00, 0x00, 0x00, // size (little endian)
879 0xFF, // entry type: Min key (not supported yet)
880 'e', 'n', 't', 'r', 'y', '\x00',
881 0x00 // end marker
882 };
883
884 json _;
885 CHECK_THROWS_AS(_ = json::from_bson(bson), json::parse_error&);
886 CHECK_THROWS_WITH(_ = json::from_bson(bson),
887 "[json.exception.parse_error.114] parse error at byte 5: Unsupported BSON record type 0xFF");
888 CHECK(json::from_bson(bson, true, false).is_discarded());
889
890 SaxCountdown scp(0);
891 CHECK(!json::sax_parse(bson, &scp, json::input_format_t::bson));
892 }
893
894 TEST_CASE("BSON numerical data")
895 {
896 SECTION("number")
897 {
898 SECTION("signed")
899 {
900 SECTION("std::int64_t: INT64_MIN .. INT32_MIN-1")
901 {
902 std::vector<int64_t> numbers
903 {
904 INT64_MIN,
905 -1000000000000000000LL,
906 -100000000000000000LL,
907 -10000000000000000LL,
908 -1000000000000000LL,
909 -100000000000000LL,
910 -10000000000000LL,
911 -1000000000000LL,
912 -100000000000LL,
913 -10000000000LL,
914 static_cast<std::int64_t>(INT32_MIN) - 1,
915 };
916
917 for (auto i : numbers)
918 {
919
920 CAPTURE(i)
921
922 json j =
923 {
924 { "entry", i }
925 };
926 CHECK(j.at("entry").is_number_integer());
927
928 std::uint64_t iu = *reinterpret_cast<std::uint64_t*>(&i);
929 std::vector<std::uint8_t> expected_bson =
930 {
931 0x14u, 0x00u, 0x00u, 0x00u, // size (little endian)
932 0x12u, /// entry: int64
933 'e', 'n', 't', 'r', 'y', '\x00',
934 static_cast<std::uint8_t>((iu >> (8u * 0u)) & 0xffu),
935 static_cast<std::uint8_t>((iu >> (8u * 1u)) & 0xffu),
936 static_cast<std::uint8_t>((iu >> (8u * 2u)) & 0xffu),
937 static_cast<std::uint8_t>((iu >> (8u * 3u)) & 0xffu),
938 static_cast<std::uint8_t>((iu >> (8u * 4u)) & 0xffu),
939 static_cast<std::uint8_t>((iu >> (8u * 5u)) & 0xffu),
940 static_cast<std::uint8_t>((iu >> (8u * 6u)) & 0xffu),
941 static_cast<std::uint8_t>((iu >> (8u * 7u)) & 0xffu),
942 0x00u // end marker
943 };
944
945 const auto bson = json::to_bson(j);
946 CHECK(bson == expected_bson);
947
948 auto j_roundtrip = json::from_bson(bson);
949
950 CHECK(j_roundtrip.at("entry").is_number_integer());
951 CHECK(j_roundtrip == j);
952 CHECK(json::from_bson(bson, true, false) == j);
953
954 }
955 }
956
957
958 SECTION("signed std::int32_t: INT32_MIN .. INT32_MAX")
959 {
960 std::vector<int32_t> numbers
961 {
962 INT32_MIN,
963 -2147483647L,
964 -1000000000L,
965 -100000000L,
966 -10000000L,
967 -1000000L,
968 -100000L,
969 -10000L,
970 -1000L,
971 -100L,
972 -10L,
973 -1L,
974 0L,
975 1L,
976 10L,
977 100L,
978 1000L,
979 10000L,
980 100000L,
981 1000000L,
982 10000000L,
983 100000000L,
984 1000000000L,
985 2147483646L,
986 INT32_MAX
987 };
988
989 for (auto i : numbers)
990 {
991
992 CAPTURE(i)
993
994 json j =
995 {
996 { "entry", i }
997 };
998 CHECK(j.at("entry").is_number_integer());
999
1000 std::uint32_t iu = *reinterpret_cast<std::uint32_t*>(&i);
1001 std::vector<std::uint8_t> expected_bson =
1002 {
1003 0x10u, 0x00u, 0x00u, 0x00u, // size (little endian)
1004 0x10u, /// entry: int32
1005 'e', 'n', 't', 'r', 'y', '\x00',
1006 static_cast<std::uint8_t>((iu >> (8u * 0u)) & 0xffu),
1007 static_cast<std::uint8_t>((iu >> (8u * 1u)) & 0xffu),
1008 static_cast<std::uint8_t>((iu >> (8u * 2u)) & 0xffu),
1009 static_cast<std::uint8_t>((iu >> (8u * 3u)) & 0xffu),
1010 0x00u // end marker
1011 };
1012
1013 const auto bson = json::to_bson(j);
1014 CHECK(bson == expected_bson);
1015
1016 auto j_roundtrip = json::from_bson(bson);
1017
1018 CHECK(j_roundtrip.at("entry").is_number_integer());
1019 CHECK(j_roundtrip == j);
1020 CHECK(json::from_bson(bson, true, false) == j);
1021
1022 }
1023 }
1024
1025 SECTION("signed std::int64_t: INT32_MAX+1 .. INT64_MAX")
1026 {
1027 std::vector<int64_t> numbers
1028 {
1029 INT64_MAX,
1030 1000000000000000000LL,
1031 100000000000000000LL,
1032 10000000000000000LL,
1033 1000000000000000LL,
1034 100000000000000LL,
1035 10000000000000LL,
1036 1000000000000LL,
1037 100000000000LL,
1038 10000000000LL,
1039 static_cast<std::int64_t>(INT32_MAX) + 1,
1040 };
1041
1042 for (auto i : numbers)
1043 {
1044
1045 CAPTURE(i)
1046
1047 json j =
1048 {
1049 { "entry", i }
1050 };
1051 CHECK(j.at("entry").is_number_integer());
1052
1053 std::uint64_t iu = *reinterpret_cast<std::uint64_t*>(&i);
1054 std::vector<std::uint8_t> expected_bson =
1055 {
1056 0x14u, 0x00u, 0x00u, 0x00u, // size (little endian)
1057 0x12u, /// entry: int64
1058 'e', 'n', 't', 'r', 'y', '\x00',
1059 static_cast<std::uint8_t>((iu >> (8u * 0u)) & 0xffu),
1060 static_cast<std::uint8_t>((iu >> (8u * 1u)) & 0xffu),
1061 static_cast<std::uint8_t>((iu >> (8u * 2u)) & 0xffu),
1062 static_cast<std::uint8_t>((iu >> (8u * 3u)) & 0xffu),
1063 static_cast<std::uint8_t>((iu >> (8u * 4u)) & 0xffu),
1064 static_cast<std::uint8_t>((iu >> (8u * 5u)) & 0xffu),
1065 static_cast<std::uint8_t>((iu >> (8u * 6u)) & 0xffu),
1066 static_cast<std::uint8_t>((iu >> (8u * 7u)) & 0xffu),
1067 0x00u // end marker
1068 };
1069
1070 const auto bson = json::to_bson(j);
1071 CHECK(bson == expected_bson);
1072
1073 auto j_roundtrip = json::from_bson(bson);
1074
1075 CHECK(j_roundtrip.at("entry").is_number_integer());
1076 CHECK(j_roundtrip == j);
1077 CHECK(json::from_bson(bson, true, false) == j);
1078
1079 }
1080 }
1081 }
1082
1083 SECTION("unsigned")
1084 {
1085 SECTION("unsigned std::uint64_t: 0 .. INT32_MAX")
1086 {
1087 std::vector<std::uint64_t> numbers
1088 {
1089 0ULL,
1090 1ULL,
1091 10ULL,
1092 100ULL,
1093 1000ULL,
1094 10000ULL,
1095 100000ULL,
1096 1000000ULL,
1097 10000000ULL,
1098 100000000ULL,
1099 1000000000ULL,
1100 2147483646ULL,
1101 static_cast<std::uint64_t>(INT32_MAX)
1102 };
1103
1104 for (auto i : numbers)
1105 {
1106
1107 CAPTURE(i)
1108
1109 json j =
1110 {
1111 { "entry", i }
1112 };
1113
1114 auto iu = i;
1115 std::vector<std::uint8_t> expected_bson =
1116 {
1117 0x10u, 0x00u, 0x00u, 0x00u, // size (little endian)
1118 0x10u, /// entry: int32
1119 'e', 'n', 't', 'r', 'y', '\x00',
1120 static_cast<std::uint8_t>((iu >> (8u * 0u)) & 0xffu),
1121 static_cast<std::uint8_t>((iu >> (8u * 1u)) & 0xffu),
1122 static_cast<std::uint8_t>((iu >> (8u * 2u)) & 0xffu),
1123 static_cast<std::uint8_t>((iu >> (8u * 3u)) & 0xffu),
1124 0x00u // end marker
1125 };
1126
1127 const auto bson = json::to_bson(j);
1128 CHECK(bson == expected_bson);
1129
1130 auto j_roundtrip = json::from_bson(bson);
1131
1132 CHECK(j.at("entry").is_number_unsigned());
1133 CHECK(j_roundtrip.at("entry").is_number_integer());
1134 CHECK(j_roundtrip == j);
1135 CHECK(json::from_bson(bson, true, false) == j);
1136
1137 }
1138 }
1139
1140 SECTION("unsigned std::uint64_t: INT32_MAX+1 .. INT64_MAX")
1141 {
1142 std::vector<std::uint64_t> numbers
1143 {
1144 static_cast<std::uint64_t>(INT32_MAX) + 1,
1145 4000000000ULL,
1146 static_cast<std::uint64_t>(UINT32_MAX),
1147 10000000000ULL,
1148 100000000000ULL,
1149 1000000000000ULL,
1150 10000000000000ULL,
1151 100000000000000ULL,
1152 1000000000000000ULL,
1153 10000000000000000ULL,
1154 100000000000000000ULL,
1155 1000000000000000000ULL,
1156 static_cast<std::uint64_t>(INT64_MAX),
1157 };
1158
1159 for (auto i : numbers)
1160 {
1161
1162 CAPTURE(i)
1163
1164 json j =
1165 {
1166 { "entry", i }
1167 };
1168
1169 auto iu = i;
1170 std::vector<std::uint8_t> expected_bson =
1171 {
1172 0x14u, 0x00u, 0x00u, 0x00u, // size (little endian)
1173 0x12u, /// entry: int64
1174 'e', 'n', 't', 'r', 'y', '\x00',
1175 static_cast<std::uint8_t>((iu >> (8u * 0u)) & 0xffu),
1176 static_cast<std::uint8_t>((iu >> (8u * 1u)) & 0xffu),
1177 static_cast<std::uint8_t>((iu >> (8u * 2u)) & 0xffu),
1178 static_cast<std::uint8_t>((iu >> (8u * 3u)) & 0xffu),
1179 static_cast<std::uint8_t>((iu >> (8u * 4u)) & 0xffu),
1180 static_cast<std::uint8_t>((iu >> (8u * 5u)) & 0xffu),
1181 static_cast<std::uint8_t>((iu >> (8u * 6u)) & 0xffu),
1182 static_cast<std::uint8_t>((iu >> (8u * 7u)) & 0xffu),
1183 0x00u // end marker
1184 };
1185
1186 const auto bson = json::to_bson(j);
1187 CHECK(bson == expected_bson);
1188
1189 auto j_roundtrip = json::from_bson(bson);
1190
1191 CHECK(j.at("entry").is_number_unsigned());
1192 CHECK(j_roundtrip.at("entry").is_number_integer());
1193 CHECK(j_roundtrip == j);
1194 CHECK(json::from_bson(bson, true, false) == j);
1195 }
1196 }
1197
1198 SECTION("unsigned std::uint64_t: INT64_MAX+1 .. UINT64_MAX")
1199 {
1200 std::vector<std::uint64_t> numbers
1201 {
1202 static_cast<std::uint64_t>(INT64_MAX) + 1ULL,
1203 10000000000000000000ULL,
1204 18000000000000000000ULL,
1205 UINT64_MAX - 1ULL,
1206 UINT64_MAX,
1207 };
1208
1209 for (auto i : numbers)
1210 {
1211
1212 CAPTURE(i)
1213
1214 json j =
1215 {
1216 { "entry", i }
1217 };
1218
1219 auto iu = i;
1220 std::vector<std::uint8_t> expected_bson =
1221 {
1222 0x14u, 0x00u, 0x00u, 0x00u, // size (little endian)
1223 0x12u, /// entry: int64
1224 'e', 'n', 't', 'r', 'y', '\x00',
1225 static_cast<std::uint8_t>((iu >> (8u * 0u)) & 0xffu),
1226 static_cast<std::uint8_t>((iu >> (8u * 1u)) & 0xffu),
1227 static_cast<std::uint8_t>((iu >> (8u * 2u)) & 0xffu),
1228 static_cast<std::uint8_t>((iu >> (8u * 3u)) & 0xffu),
1229 static_cast<std::uint8_t>((iu >> (8u * 4u)) & 0xffu),
1230 static_cast<std::uint8_t>((iu >> (8u * 5u)) & 0xffu),
1231 static_cast<std::uint8_t>((iu >> (8u * 6u)) & 0xffu),
1232 static_cast<std::uint8_t>((iu >> (8u * 7u)) & 0xffu),
1233 0x00u // end marker
1234 };
1235
1236 CHECK_THROWS_AS(json::to_bson(j), json::out_of_range&);
1237 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");
1238 }
1239 }
1240
1241 }
1242 }
1243 }
1244
skip()1245 TEST_CASE("BSON roundtrips" * doctest::skip())
1246 {
1247 SECTION("reference files")
1248 {
1249 for (std::string filename :
1250 {
1251 TEST_DATA_DIRECTORY "/json.org/1.json",
1252 TEST_DATA_DIRECTORY "/json.org/2.json",
1253 TEST_DATA_DIRECTORY "/json.org/3.json",
1254 TEST_DATA_DIRECTORY "/json.org/4.json",
1255 TEST_DATA_DIRECTORY "/json.org/5.json"
1256 })
1257 {
1258 CAPTURE(filename)
1259
1260 {
1261 INFO_WITH_TEMP(filename + ": std::vector<std::uint8_t>");
1262 // parse JSON file
1263 std::ifstream f_json(filename);
1264 json j1 = json::parse(f_json);
1265
1266 // parse BSON file
1267 auto packed = utils::read_binary_file(filename + ".bson");
1268 json j2;
1269 CHECK_NOTHROW(j2 = json::from_bson(packed));
1270
1271 // compare parsed JSON values
1272 CHECK(j1 == j2);
1273 }
1274
1275 {
1276 INFO_WITH_TEMP(filename + ": std::ifstream");
1277 // parse JSON file
1278 std::ifstream f_json(filename);
1279 json j1 = json::parse(f_json);
1280
1281 // parse BSON file
1282 std::ifstream f_bson(filename + ".bson", std::ios::binary);
1283 json j2;
1284 CHECK_NOTHROW(j2 = json::from_bson(f_bson));
1285
1286 // compare parsed JSON values
1287 CHECK(j1 == j2);
1288 }
1289
1290 {
1291 INFO_WITH_TEMP(filename + ": uint8_t* and size");
1292 // parse JSON file
1293 std::ifstream f_json(filename);
1294 json j1 = json::parse(f_json);
1295
1296 // parse BSON file
1297 auto packed = utils::read_binary_file(filename + ".bson");
1298 json j2;
1299 CHECK_NOTHROW(j2 = json::from_bson({packed.data(), packed.size()}));
1300
1301 // compare parsed JSON values
1302 CHECK(j1 == j2);
1303 }
1304
1305 {
1306 INFO_WITH_TEMP(filename + ": output to output adapters");
1307 // parse JSON file
1308 std::ifstream f_json(filename);
1309 json j1 = json::parse(f_json);
1310
1311 // parse BSON file
1312 auto packed = utils::read_binary_file(filename + ".bson");
1313
1314 {
1315 INFO_WITH_TEMP(filename + ": output adapters: std::vector<std::uint8_t>");
1316 std::vector<std::uint8_t> vec;
1317 json::to_bson(j1, vec);
1318
1319 if (vec != packed)
1320 {
1321 // the exact serializations may differ due to the order of
1322 // object keys; in these cases, just compare whether both
1323 // serializations create the same JSON value
1324 CHECK(json::from_bson(vec) == json::from_bson(packed));
1325 }
1326 }
1327 }
1328 }
1329 }
1330 }
1331