1 // __ _____ _____ _____
2 // __| | __| | | | JSON for Modern C++ (supporting code)
3 // | | |__ | | | | | | version 3.11.3
4 // |_____|_____|_____|_|___| https://github.com/nlohmann/json
5 //
6 // SPDX-FileCopyrightText: 2013-2023 Niels Lohmann <https://nlohmann.me>
7 // SPDX-License-Identifier: MIT
8
9 #include "doctest_compatibility.h"
10
11 #define JSON_TESTS_PRIVATE
12 #include <nlohmann/json.hpp>
13 using nlohmann::json;
14
15 #include <algorithm>
16 #include <climits>
17 #include <limits>
18 #include <iostream>
19 #include <fstream>
20 #include <set>
21 #include "make_test_data_available.hpp"
22 #include "test_utils.hpp"
23
24 namespace
25 {
26 class SaxCountdown
27 {
28 public:
SaxCountdown(const int count)29 explicit SaxCountdown(const int count) : events_left(count)
30 {}
31
null()32 bool null()
33 {
34 return events_left-- > 0;
35 }
36
boolean(bool)37 bool boolean(bool /*unused*/)
38 {
39 return events_left-- > 0;
40 }
41
number_integer(json::number_integer_t)42 bool number_integer(json::number_integer_t /*unused*/)
43 {
44 return events_left-- > 0;
45 }
46
number_unsigned(json::number_unsigned_t)47 bool number_unsigned(json::number_unsigned_t /*unused*/)
48 {
49 return events_left-- > 0;
50 }
51
number_float(json::number_float_t,const std::string &)52 bool number_float(json::number_float_t /*unused*/, const std::string& /*unused*/)
53 {
54 return events_left-- > 0;
55 }
56
string(std::string &)57 bool string(std::string& /*unused*/)
58 {
59 return events_left-- > 0;
60 }
61
binary(std::vector<std::uint8_t> &)62 bool binary(std::vector<std::uint8_t>& /*unused*/)
63 {
64 return events_left-- > 0;
65 }
66
start_object(std::size_t)67 bool start_object(std::size_t /*unused*/)
68 {
69 return events_left-- > 0;
70 }
71
key(std::string &)72 bool key(std::string& /*unused*/)
73 {
74 return events_left-- > 0;
75 }
76
end_object()77 bool end_object()
78 {
79 return events_left-- > 0;
80 }
81
start_array(std::size_t)82 bool start_array(std::size_t /*unused*/)
83 {
84 return events_left-- > 0;
85 }
86
end_array()87 bool end_array()
88 {
89 return events_left-- > 0;
90 }
91
parse_error(std::size_t,const std::string &,const json::exception &)92 bool parse_error(std::size_t /*unused*/, const std::string& /*unused*/, const json::exception& /*unused*/) // NOLINT(readability-convert-member-functions-to-static)
93 {
94 return false;
95 }
96
97 private:
98 int events_left = 0;
99 };
100 } // namespace
101
102 // at some point in the future, a unit test dedicated to type traits might be a good idea
103 template <typename OfType, typename T, bool MinInRange, bool MaxInRange>
104 struct trait_test_arg
105 {
106 using of_type = OfType;
107 using type = T;
108 static constexpr bool min_in_range = MinInRange;
109 static constexpr bool max_in_range = MaxInRange;
110 };
111
112 TEST_CASE_TEMPLATE_DEFINE("value_in_range_of trait", T, value_in_range_of_test)
113 {
114 using nlohmann::detail::value_in_range_of;
115
116 using of_type = typename T::of_type;
117 using type = typename T::type;
118 constexpr bool min_in_range = T::min_in_range;
119 constexpr bool max_in_range = T::max_in_range;
120
121 type const val_min = std::numeric_limits<type>::min();
122 type const val_min2 = val_min + 1;
123 type const val_max = std::numeric_limits<type>::max();
124 type const val_max2 = val_max - 1;
125
126 REQUIRE(CHAR_BIT == 8);
127
128 std::string of_type_str;
129 if (std::is_unsigned<of_type>::value)
130 {
131 of_type_str += "u";
132 }
133 of_type_str += "int";
134 of_type_str += std::to_string(sizeof(of_type) * 8);
135
136 INFO("of_type := ", of_type_str);
137
138 std::string type_str;
139 if (std::is_unsigned<type>::value)
140 {
141 type_str += "u";
142 }
143 type_str += "int";
144 type_str += std::to_string(sizeof(type) * 8);
145
146 INFO("type := ", type_str);
147
148 CAPTURE(val_min);
149 CAPTURE(min_in_range);
150 CAPTURE(val_max);
151 CAPTURE(max_in_range);
152
153 if (min_in_range)
154 {
155 CHECK(value_in_range_of<of_type>(val_min));
156 CHECK(value_in_range_of<of_type>(val_min2));
157 }
158 else
159 {
160 CHECK_FALSE(value_in_range_of<of_type>(val_min));
161 CHECK_FALSE(value_in_range_of<of_type>(val_min2));
162 }
163
164 if (max_in_range)
165 {
166 CHECK(value_in_range_of<of_type>(val_max));
167 CHECK(value_in_range_of<of_type>(val_max2));
168 }
169 else
170 {
171 CHECK_FALSE(value_in_range_of<of_type>(val_max));
172 CHECK_FALSE(value_in_range_of<of_type>(val_max2));
173 }
174 }
175
176 TEST_CASE_TEMPLATE_INVOKE(value_in_range_of_test, \
177 trait_test_arg<std::int32_t, std::int32_t, true, true>, \
178 trait_test_arg<std::int32_t, std::uint32_t, true, false>, \
179 trait_test_arg<std::uint32_t, std::int32_t, false, true>, \
180 trait_test_arg<std::uint32_t, std::uint32_t, true, true>, \
181 trait_test_arg<std::int32_t, std::int64_t, false, false>, \
182 trait_test_arg<std::int32_t, std::uint64_t, true, false>, \
183 trait_test_arg<std::uint32_t, std::int64_t, false, false>, \
184 trait_test_arg<std::uint32_t, std::uint64_t, true, false>, \
185 trait_test_arg<std::int64_t, std::int32_t, true, true>, \
186 trait_test_arg<std::int64_t, std::uint32_t, true, true>, \
187 trait_test_arg<std::uint64_t, std::int32_t, false, true>, \
188 trait_test_arg<std::uint64_t, std::uint32_t, true, true>, \
189 trait_test_arg<std::int64_t, std::int64_t, true, true>, \
190 trait_test_arg<std::int64_t, std::uint64_t, true, false>, \
191 trait_test_arg<std::uint64_t, std::int64_t, false, true>, \
192 trait_test_arg<std::uint64_t, std::uint64_t, true, true>);
193
194 #if SIZE_MAX == 0xffffffff
195 TEST_CASE_TEMPLATE_INVOKE(value_in_range_of_test, \
196 trait_test_arg<std::size_t, std::int32_t, false, true>, \
197 trait_test_arg<std::size_t, std::uint32_t, true, true>, \
198 trait_test_arg<std::size_t, std::int64_t, false, false>, \
199 trait_test_arg<std::size_t, std::uint64_t, true, false>);
200 #else
201 TEST_CASE_TEMPLATE_INVOKE(value_in_range_of_test, \
202 trait_test_arg<std::size_t, std::int32_t, false, true>, \
203 trait_test_arg<std::size_t, std::uint32_t, true, true>, \
204 trait_test_arg<std::size_t, std::int64_t, false, true>, \
205 trait_test_arg<std::size_t, std::uint64_t, true, true>);
206 #endif
207
208 TEST_CASE("BJData")
209 {
210 SECTION("binary_reader BJData LUT arrays are sorted")
211 {
212 std::vector<std::uint8_t> const data;
213 auto ia = nlohmann::detail::input_adapter(data);
214 // NOLINTNEXTLINE(hicpp-move-const-arg,performance-move-const-arg)
215 nlohmann::detail::binary_reader<json, decltype(ia)> const br{std::move(ia), json::input_format_t::bjdata};
216
217 CHECK(std::is_sorted(br.bjd_optimized_type_markers.begin(), br.bjd_optimized_type_markers.end()));
218 CHECK(std::is_sorted(br.bjd_types_map.begin(), br.bjd_types_map.end()));
219 }
220
221 SECTION("individual values")
222 {
223 SECTION("discarded")
224 {
225 // discarded values are not serialized
226 json const j = json::value_t::discarded;
227 const auto result = json::to_bjdata(j);
228 CHECK(result.empty());
229 }
230
231 SECTION("null")
232 {
233 json const j = nullptr;
234 std::vector<uint8_t> const expected = {'Z'};
235 const auto result = json::to_bjdata(j);
236 CHECK(result == expected);
237
238 // roundtrip
239 CHECK(json::from_bjdata(result) == j);
240 CHECK(json::from_bjdata(result, true, false) == j);
241 }
242
243 SECTION("boolean")
244 {
245 SECTION("true")
246 {
247 json const j = true;
248 std::vector<uint8_t> const expected = {'T'};
249 const auto result = json::to_bjdata(j);
250 CHECK(result == expected);
251
252 // roundtrip
253 CHECK(json::from_bjdata(result) == j);
254 CHECK(json::from_bjdata(result, true, false) == j);
255 }
256
257 SECTION("false")
258 {
259 json const j = false;
260 std::vector<uint8_t> const expected = {'F'};
261 const auto result = json::to_bjdata(j);
262 CHECK(result == expected);
263
264 // roundtrip
265 CHECK(json::from_bjdata(result) == j);
266 CHECK(json::from_bjdata(result, true, false) == j);
267 }
268 }
269
270 SECTION("number")
271 {
272 SECTION("signed")
273 {
274 SECTION("-9223372036854775808..-2147483649 (int64)")
275 {
276 std::vector<int64_t> const numbers
277 {
278 (std::numeric_limits<int64_t>::min)(),
279 -1000000000000000000LL,
280 -100000000000000000LL,
281 -10000000000000000LL,
282 -1000000000000000LL,
283 -100000000000000LL,
284 -10000000000000LL,
285 -1000000000000LL,
286 -100000000000LL,
287 -10000000000LL,
288 -2147483649LL,
289 };
290 for (const auto i : numbers)
291 {
292 CAPTURE(i)
293
294 // create JSON value with integer number
295 json const j = i;
296
297 // check type
298 CHECK(j.is_number_integer());
299
300 // create expected byte vector
301 std::vector<uint8_t> const expected
302 {
303 static_cast<uint8_t>('L'),
304 static_cast<uint8_t>(i & 0xff),
305 static_cast<uint8_t>((i >> 8) & 0xff),
306 static_cast<uint8_t>((i >> 16) & 0xff),
307 static_cast<uint8_t>((i >> 24) & 0xff),
308 static_cast<uint8_t>((i >> 32) & 0xff),
309 static_cast<uint8_t>((i >> 40) & 0xff),
310 static_cast<uint8_t>((i >> 48) & 0xff),
311 static_cast<uint8_t>((i >> 56) & 0xff),
312 };
313
314 // compare result + size
315 const auto result = json::to_bjdata(j);
316 CHECK(result == expected);
317 CHECK(result.size() == 9);
318
319 // check individual bytes
320 CHECK(result[0] == 'L');
321 int64_t const restored = (static_cast<int64_t>(result[8]) << 070) +
322 (static_cast<int64_t>(result[7]) << 060) +
323 (static_cast<int64_t>(result[6]) << 050) +
324 (static_cast<int64_t>(result[5]) << 040) +
325 (static_cast<int64_t>(result[4]) << 030) +
326 (static_cast<int64_t>(result[3]) << 020) +
327 (static_cast<int64_t>(result[2]) << 010) +
328 static_cast<int64_t>(result[1]);
329 CHECK(restored == i);
330
331 // roundtrip
332 CHECK(json::from_bjdata(result) == j);
333 CHECK(json::from_bjdata(result, true, false) == j);
334 }
335 }
336
337 SECTION("-2147483648..-32769 (int32)")
338 {
339 std::vector<int32_t> const numbers
340 {
341 -32769,
342 -100000,
343 -1000000,
344 -10000000,
345 -100000000,
346 -1000000000,
347 -2147483647 - 1, // https://stackoverflow.com/a/29356002/266378
348 };
349 for (const auto i : numbers)
350 {
351 CAPTURE(i)
352
353 // create JSON value with integer number
354 json const j = i;
355
356 // check type
357 CHECK(j.is_number_integer());
358
359 // create expected byte vector
360 std::vector<uint8_t> const expected
361 {
362 static_cast<uint8_t>('l'),
363 static_cast<uint8_t>(i & 0xff),
364 static_cast<uint8_t>((i >> 8) & 0xff),
365 static_cast<uint8_t>((i >> 16) & 0xff),
366 static_cast<uint8_t>((i >> 24) & 0xff),
367 };
368
369 // compare result + size
370 const auto result = json::to_bjdata(j);
371 CHECK(result == expected);
372 CHECK(result.size() == 5);
373
374 // check individual bytes
375 CHECK(result[0] == 'l');
376 int32_t const restored = (static_cast<int32_t>(result[4]) << 030) +
377 (static_cast<int32_t>(result[3]) << 020) +
378 (static_cast<int32_t>(result[2]) << 010) +
379 static_cast<int32_t>(result[1]);
380 CHECK(restored == i);
381
382 // roundtrip
383 CHECK(json::from_bjdata(result) == j);
384 CHECK(json::from_bjdata(result, true, false) == j);
385 }
386 }
387
388 SECTION("-32768..-129 (int16)")
389 {
390 for (int32_t i = -32768; i <= -129; ++i)
391 {
392 CAPTURE(i)
393
394 // create JSON value with integer number
395 json const j = i;
396
397 // check type
398 CHECK(j.is_number_integer());
399
400 // create expected byte vector
401 std::vector<uint8_t> const expected
402 {
403 static_cast<uint8_t>('I'),
404 static_cast<uint8_t>(i & 0xff),
405 static_cast<uint8_t>((i >> 8) & 0xff),
406 };
407
408 // compare result + size
409 const auto result = json::to_bjdata(j);
410 CHECK(result == expected);
411 CHECK(result.size() == 3);
412
413 // check individual bytes
414 CHECK(result[0] == 'I');
415 auto const restored = static_cast<int16_t>(((result[2] << 8) + result[1]));
416 CHECK(restored == i);
417
418 // roundtrip
419 CHECK(json::from_bjdata(result) == j);
420 CHECK(json::from_bjdata(result, true, false) == j);
421 }
422 }
423
424 SECTION("-9263 (int16)")
425 {
426 json const j = -9263;
427 std::vector<uint8_t> const expected = {'I', 0xd1, 0xdb};
428
429 // compare result + size
430 const auto result = json::to_bjdata(j);
431 CHECK(result == expected);
432 CHECK(result.size() == 3);
433
434 // check individual bytes
435 CHECK(result[0] == 'I');
436 auto const restored = static_cast<int16_t>(((result[2] << 8) + result[1]));
437 CHECK(restored == -9263);
438
439 // roundtrip
440 CHECK(json::from_bjdata(result) == j);
441 CHECK(json::from_bjdata(result, true, false) == j);
442 }
443
444 SECTION("-128..-1 (int8)")
445 {
446 for (auto i = -128; i <= -1; ++i)
447 {
448 CAPTURE(i)
449
450 // create JSON value with integer number
451 json const j = i;
452
453 // check type
454 CHECK(j.is_number_integer());
455
456 // create expected byte vector
457 std::vector<uint8_t> const expected
458 {
459 'i',
460 static_cast<uint8_t>(i),
461 };
462
463 // compare result + size
464 const auto result = json::to_bjdata(j);
465 CHECK(result == expected);
466 CHECK(result.size() == 2);
467
468 // check individual bytes
469 CHECK(result[0] == 'i');
470 CHECK(static_cast<int8_t>(result[1]) == i);
471
472 // roundtrip
473 CHECK(json::from_bjdata(result) == j);
474 CHECK(json::from_bjdata(result, true, false) == j);
475 }
476 }
477
478 SECTION("0..127 (int8)")
479 {
480 for (size_t i = 0; i <= 127; ++i)
481 {
482 CAPTURE(i)
483
484 // create JSON value with integer number
485 json j = -1;
486 j.get_ref<json::number_integer_t&>() = static_cast<json::number_integer_t>(i);
487
488 // check type
489 CHECK(j.is_number_integer());
490
491 // create expected byte vector
492 std::vector<uint8_t> const expected
493 {
494 static_cast<uint8_t>('i'),
495 static_cast<uint8_t>(i),
496 };
497
498 // compare result + size
499 const auto result = json::to_bjdata(j);
500 CHECK(result == expected);
501 CHECK(result.size() == 2);
502
503 // check individual bytes
504 CHECK(result[0] == 'i');
505 CHECK(result[1] == i);
506
507 // roundtrip
508 CHECK(json::from_bjdata(result) == j);
509 CHECK(json::from_bjdata(result, true, false) == j);
510 }
511 }
512
513 SECTION("128..255 (uint8)")
514 {
515 for (size_t i = 128; i <= 255; ++i)
516 {
517 CAPTURE(i)
518
519 // create JSON value with integer number
520 json j = -1;
521 j.get_ref<json::number_integer_t&>() = static_cast<json::number_integer_t>(i);
522
523 // check type
524 CHECK(j.is_number_integer());
525
526 // create expected byte vector
527 std::vector<uint8_t> const expected
528 {
529 static_cast<uint8_t>('U'),
530 static_cast<uint8_t>(i),
531 };
532
533 // compare result + size
534 const auto result = json::to_bjdata(j);
535 CHECK(result == expected);
536 CHECK(result.size() == 2);
537
538 // check individual bytes
539 CHECK(result[0] == 'U');
540 CHECK(result[1] == i);
541
542 // roundtrip
543 CHECK(json::from_bjdata(result) == j);
544 CHECK(json::from_bjdata(result, true, false) == j);
545 }
546 }
547
548 SECTION("256..32767 (int16)")
549 {
550 for (size_t i = 256; i <= 32767; ++i)
551 {
552 CAPTURE(i)
553
554 // create JSON value with integer number
555 json j = -1;
556 j.get_ref<json::number_integer_t&>() = static_cast<json::number_integer_t>(i);
557
558 // check type
559 CHECK(j.is_number_integer());
560
561 // create expected byte vector
562 std::vector<uint8_t> const expected
563 {
564 static_cast<uint8_t>('I'),
565 static_cast<uint8_t>(i & 0xff),
566 static_cast<uint8_t>((i >> 8) & 0xff),
567 };
568
569 // compare result + size
570 const auto result = json::to_bjdata(j);
571 CHECK(result == expected);
572 CHECK(result.size() == 3);
573
574 // check individual bytes
575 CHECK(result[0] == 'I');
576 auto const restored = static_cast<uint16_t>(static_cast<uint8_t>(result[2]) * 256 + static_cast<uint8_t>(result[1]));
577 CHECK(restored == i);
578
579 // roundtrip
580 CHECK(json::from_bjdata(result) == j);
581 CHECK(json::from_bjdata(result, true, false) == j);
582 }
583 }
584
585 SECTION("32768..65535 (uint16)")
586 {
587 for (const uint32_t i :
588 {
589 32768u, 55555u, 65535u
590 })
591 {
592 CAPTURE(i)
593
594 // create JSON value with integer number
595 json j = -1;
596 j.get_ref<json::number_integer_t&>() = static_cast<json::number_integer_t>(i);
597
598 // check type
599 CHECK(j.is_number_integer());
600
601 // create expected byte vector
602 std::vector<uint8_t> const expected
603 {
604 static_cast<uint8_t>('u'),
605 static_cast<uint8_t>(i & 0xff),
606 static_cast<uint8_t>((i >> 8) & 0xff),
607 };
608
609 // compare result + size
610 const auto result = json::to_bjdata(j);
611 CHECK(result == expected);
612 CHECK(result.size() == 3);
613
614 // check individual bytes
615 CHECK(result[0] == 'u');
616 auto const restored = static_cast<uint16_t>(static_cast<uint8_t>(result[2]) * 256 + static_cast<uint8_t>(result[1]));
617 CHECK(restored == i);
618
619 // roundtrip
620 CHECK(json::from_bjdata(result) == j);
621 CHECK(json::from_bjdata(result, true, false) == j);
622 }
623 }
624
625 SECTION("65536..2147483647 (int32)")
626 {
627 for (const uint32_t i :
628 {
629 65536u, 77777u, 2147483647u
630 })
631 {
632 CAPTURE(i)
633
634 // create JSON value with integer number
635 json j = -1;
636 j.get_ref<json::number_integer_t&>() = static_cast<json::number_integer_t>(i);
637
638 // check type
639 CHECK(j.is_number_integer());
640
641 // create expected byte vector
642 std::vector<uint8_t> const expected
643 {
644 'l',
645 static_cast<uint8_t>(i & 0xff),
646 static_cast<uint8_t>((i >> 8) & 0xff),
647 static_cast<uint8_t>((i >> 16) & 0xff),
648 static_cast<uint8_t>((i >> 24) & 0xff),
649 };
650
651 // compare result + size
652 const auto result = json::to_bjdata(j);
653 CHECK(result == expected);
654 CHECK(result.size() == 5);
655
656 // check individual bytes
657 CHECK(result[0] == 'l');
658 uint32_t const restored = (static_cast<uint32_t>(result[4]) << 030) +
659 (static_cast<uint32_t>(result[3]) << 020) +
660 (static_cast<uint32_t>(result[2]) << 010) +
661 static_cast<uint32_t>(result[1]);
662 CHECK(restored == i);
663
664 // roundtrip
665 CHECK(json::from_bjdata(result) == j);
666 CHECK(json::from_bjdata(result, true, false) == j);
667 }
668 }
669
670 SECTION("2147483648..4294967295 (uint32)")
671 {
672 for (const uint32_t i :
673 {
674 2147483648u, 3333333333u, 4294967295u
675 })
676 {
677 CAPTURE(i)
678
679 // create JSON value with integer number
680 json j = -1;
681 j.get_ref<json::number_integer_t&>() = static_cast<json::number_integer_t>(i);
682
683 // check type
684 CHECK(j.is_number_integer());
685
686 // create expected byte vector
687 std::vector<uint8_t> const expected
688 {
689 'm',
690 static_cast<uint8_t>(i & 0xff),
691 static_cast<uint8_t>((i >> 8) & 0xff),
692 static_cast<uint8_t>((i >> 16) & 0xff),
693 static_cast<uint8_t>((i >> 24) & 0xff),
694 };
695
696 // compare result + size
697 const auto result = json::to_bjdata(j);
698 CHECK(result == expected);
699 CHECK(result.size() == 5);
700
701 // check individual bytes
702 CHECK(result[0] == 'm');
703 uint32_t const restored = (static_cast<uint32_t>(result[4]) << 030) +
704 (static_cast<uint32_t>(result[3]) << 020) +
705 (static_cast<uint32_t>(result[2]) << 010) +
706 static_cast<uint32_t>(result[1]);
707 CHECK(restored == i);
708
709 // roundtrip
710 CHECK(json::from_bjdata(result) == j);
711 CHECK(json::from_bjdata(result, true, false) == j);
712 }
713 }
714
715 SECTION("4294967296..9223372036854775807 (int64)")
716 {
717 std::vector<uint64_t> const v = {4294967296LU, 9223372036854775807LU};
718 for (const uint64_t i : v)
719 {
720 CAPTURE(i)
721
722 // create JSON value with integer number
723 json j = -1;
724 j.get_ref<json::number_integer_t&>() = static_cast<json::number_integer_t>(i);
725
726 // check type
727 CHECK(j.is_number_integer());
728
729 // create expected byte vector
730 std::vector<uint8_t> const expected
731 {
732 'L',
733 static_cast<uint8_t>(i & 0xff),
734 static_cast<uint8_t>((i >> 010) & 0xff),
735 static_cast<uint8_t>((i >> 020) & 0xff),
736 static_cast<uint8_t>((i >> 030) & 0xff),
737 static_cast<uint8_t>((i >> 040) & 0xff),
738 static_cast<uint8_t>((i >> 050) & 0xff),
739 static_cast<uint8_t>((i >> 060) & 0xff),
740 static_cast<uint8_t>((i >> 070) & 0xff),
741 };
742
743 // compare result + size
744 const auto result = json::to_bjdata(j);
745 CHECK(result == expected);
746 CHECK(result.size() == 9);
747
748 // check individual bytes
749 CHECK(result[0] == 'L');
750 uint64_t const restored = (static_cast<uint64_t>(result[8]) << 070) +
751 (static_cast<uint64_t>(result[7]) << 060) +
752 (static_cast<uint64_t>(result[6]) << 050) +
753 (static_cast<uint64_t>(result[5]) << 040) +
754 (static_cast<uint64_t>(result[4]) << 030) +
755 (static_cast<uint64_t>(result[3]) << 020) +
756 (static_cast<uint64_t>(result[2]) << 010) +
757 static_cast<uint64_t>(result[1]);
758 CHECK(restored == i);
759
760 // roundtrip
761 CHECK(json::from_bjdata(result) == j);
762 CHECK(json::from_bjdata(result, true, false) == j);
763 }
764 }
765
766 SECTION("9223372036854775808..18446744073709551615 (uint64)")
767 {
768 std::vector<uint64_t> const v = {9223372036854775808ull, 18446744073709551615ull};
769 for (const uint64_t i : v)
770 {
771 CAPTURE(i)
772
773 // create JSON value with integer number
774 json const j = i;
775
776 // check type
777 CHECK(j.is_number_unsigned());
778
779 // create expected byte vector
780 std::vector<uint8_t> const expected
781 {
782 'M',
783 static_cast<uint8_t>(i & 0xff),
784 static_cast<uint8_t>((i >> 010) & 0xff),
785 static_cast<uint8_t>((i >> 020) & 0xff),
786 static_cast<uint8_t>((i >> 030) & 0xff),
787 static_cast<uint8_t>((i >> 040) & 0xff),
788 static_cast<uint8_t>((i >> 050) & 0xff),
789 static_cast<uint8_t>((i >> 060) & 0xff),
790 static_cast<uint8_t>((i >> 070) & 0xff),
791 };
792
793 // compare result + size
794 const auto result = json::to_bjdata(j);
795 CHECK(result == expected);
796 CHECK(result.size() == 9);
797
798 // check individual bytes
799 CHECK(result[0] == 'M');
800 uint64_t const restored = (static_cast<uint64_t>(result[8]) << 070) +
801 (static_cast<uint64_t>(result[7]) << 060) +
802 (static_cast<uint64_t>(result[6]) << 050) +
803 (static_cast<uint64_t>(result[5]) << 040) +
804 (static_cast<uint64_t>(result[4]) << 030) +
805 (static_cast<uint64_t>(result[3]) << 020) +
806 (static_cast<uint64_t>(result[2]) << 010) +
807 static_cast<uint64_t>(result[1]);
808 CHECK(restored == i);
809
810 // roundtrip
811 CHECK(json::from_bjdata(result) == j);
812 CHECK(json::from_bjdata(result, true, false) == j);
813 }
814 }
815 }
816
817 SECTION("unsigned")
818 {
819 SECTION("0..127 (int8)")
820 {
821 for (size_t i = 0; i <= 127; ++i)
822 {
823 CAPTURE(i)
824
825 // create JSON value with unsigned integer number
826 json const j = i;
827
828 // check type
829 CHECK(j.is_number_unsigned());
830
831 // create expected byte vector
832 std::vector<uint8_t> const expected{'i', static_cast<uint8_t>(i)};
833
834 // compare result + size
835 const auto result = json::to_bjdata(j);
836 CHECK(result == expected);
837 CHECK(result.size() == 2);
838
839 // check individual bytes
840 CHECK(result[0] == 'i');
841 auto const restored = static_cast<uint8_t>(result[1]);
842 CHECK(restored == i);
843
844 // roundtrip
845 CHECK(json::from_bjdata(result) == j);
846 CHECK(json::from_bjdata(result, true, false) == j);
847 }
848 }
849
850 SECTION("128..255 (uint8)")
851 {
852 for (size_t i = 128; i <= 255; ++i)
853 {
854 CAPTURE(i)
855
856 // create JSON value with unsigned integer number
857 json const j = i;
858
859 // check type
860 CHECK(j.is_number_unsigned());
861
862 // create expected byte vector
863 std::vector<uint8_t> const expected{'U', static_cast<uint8_t>(i)};
864
865 // compare result + size
866 const auto result = json::to_bjdata(j);
867 CHECK(result == expected);
868 CHECK(result.size() == 2);
869
870 // check individual bytes
871 CHECK(result[0] == 'U');
872 auto const restored = static_cast<uint8_t>(result[1]);
873 CHECK(restored == i);
874
875 // roundtrip
876 CHECK(json::from_bjdata(result) == j);
877 CHECK(json::from_bjdata(result, true, false) == j);
878 }
879 }
880
881 SECTION("256..32767 (int16)")
882 {
883 for (size_t i = 256; i <= 32767; ++i)
884 {
885 CAPTURE(i)
886
887 // create JSON value with unsigned integer number
888 json const j = i;
889
890 // check type
891 CHECK(j.is_number_unsigned());
892
893 // create expected byte vector
894 std::vector<uint8_t> const expected
895 {
896 'I',
897 static_cast<uint8_t>(i & 0xff),
898 static_cast<uint8_t>((i >> 8) & 0xff),
899 };
900
901 // compare result + size
902 const auto result = json::to_bjdata(j);
903 CHECK(result == expected);
904 CHECK(result.size() == 3);
905
906 // check individual bytes
907 CHECK(result[0] == 'I');
908 auto const restored = static_cast<uint16_t>(static_cast<uint8_t>(result[2]) * 256 + static_cast<uint8_t>(result[1]));
909 CHECK(restored == i);
910
911 // roundtrip
912 CHECK(json::from_bjdata(result) == j);
913 CHECK(json::from_bjdata(result, true, false) == j);
914 }
915 }
916
917 SECTION("32768..65535 (uint16)")
918 {
919 for (const uint32_t i :
920 {
921 32768u, 55555u, 65535u
922 })
923 {
924 CAPTURE(i)
925
926 // create JSON value with unsigned integer number
927 json const j = i;
928
929 // check type
930 CHECK(j.is_number_unsigned());
931
932 // create expected byte vector
933 std::vector<uint8_t> const expected
934 {
935 'u',
936 static_cast<uint8_t>(i & 0xff),
937 static_cast<uint8_t>((i >> 8) & 0xff),
938 };
939
940 // compare result + size
941 const auto result = json::to_bjdata(j);
942 CHECK(result == expected);
943 CHECK(result.size() == 3);
944
945 // check individual bytes
946 CHECK(result[0] == 'u');
947 auto const restored = static_cast<uint16_t>(static_cast<uint8_t>(result[2]) * 256 + static_cast<uint8_t>(result[1]));
948 CHECK(restored == i);
949
950 // roundtrip
951 CHECK(json::from_bjdata(result) == j);
952 CHECK(json::from_bjdata(result, true, false) == j);
953 }
954 }
955 SECTION("65536..2147483647 (int32)")
956 {
957 for (const uint32_t i :
958 {
959 65536u, 77777u, 2147483647u
960 })
961 {
962 CAPTURE(i)
963
964 // create JSON value with unsigned integer number
965 json const j = i;
966
967 // check type
968 CHECK(j.is_number_unsigned());
969
970 // create expected byte vector
971 std::vector<uint8_t> const expected
972 {
973 'l',
974 static_cast<uint8_t>(i & 0xff),
975 static_cast<uint8_t>((i >> 8) & 0xff),
976 static_cast<uint8_t>((i >> 16) & 0xff),
977 static_cast<uint8_t>((i >> 24) & 0xff),
978 };
979
980 // compare result + size
981 const auto result = json::to_bjdata(j);
982 CHECK(result == expected);
983 CHECK(result.size() == 5);
984
985 // check individual bytes
986 CHECK(result[0] == 'l');
987 uint32_t const restored = (static_cast<uint32_t>(result[4]) << 030) +
988 (static_cast<uint32_t>(result[3]) << 020) +
989 (static_cast<uint32_t>(result[2]) << 010) +
990 static_cast<uint32_t>(result[1]);
991 CHECK(restored == i);
992
993 // roundtrip
994 CHECK(json::from_bjdata(result) == j);
995 CHECK(json::from_bjdata(result, true, false) == j);
996 }
997 }
998
999 SECTION("2147483648..4294967295 (uint32)")
1000 {
1001 for (const uint32_t i :
1002 {
1003 2147483648u, 3333333333u, 4294967295u
1004 })
1005 {
1006 CAPTURE(i)
1007
1008 // create JSON value with unsigned integer number
1009 json const j = i;
1010
1011 // check type
1012 CHECK(j.is_number_unsigned());
1013
1014 // create expected byte vector
1015 std::vector<uint8_t> const expected
1016 {
1017 'm',
1018 static_cast<uint8_t>(i & 0xff),
1019 static_cast<uint8_t>((i >> 8) & 0xff),
1020 static_cast<uint8_t>((i >> 16) & 0xff),
1021 static_cast<uint8_t>((i >> 24) & 0xff),
1022 };
1023
1024 // compare result + size
1025 const auto result = json::to_bjdata(j);
1026 CHECK(result == expected);
1027 CHECK(result.size() == 5);
1028
1029 // check individual bytes
1030 CHECK(result[0] == 'm');
1031 uint32_t const restored = (static_cast<uint32_t>(result[4]) << 030) +
1032 (static_cast<uint32_t>(result[3]) << 020) +
1033 (static_cast<uint32_t>(result[2]) << 010) +
1034 static_cast<uint32_t>(result[1]);
1035 CHECK(restored == i);
1036
1037 // roundtrip
1038 CHECK(json::from_bjdata(result) == j);
1039 CHECK(json::from_bjdata(result, true, false) == j);
1040 }
1041 }
1042
1043 SECTION("4294967296..9223372036854775807 (int64)")
1044 {
1045 std::vector<uint64_t> const v = {4294967296ul, 9223372036854775807ul};
1046 for (const uint64_t i : v)
1047 {
1048 CAPTURE(i)
1049
1050 // create JSON value with integer number
1051 json const j = i;
1052
1053 // check type
1054 CHECK(j.is_number_unsigned());
1055
1056 // create expected byte vector
1057 std::vector<uint8_t> const expected
1058 {
1059 'L',
1060 static_cast<uint8_t>(i & 0xff),
1061 static_cast<uint8_t>((i >> 010) & 0xff),
1062 static_cast<uint8_t>((i >> 020) & 0xff),
1063 static_cast<uint8_t>((i >> 030) & 0xff),
1064 static_cast<uint8_t>((i >> 040) & 0xff),
1065 static_cast<uint8_t>((i >> 050) & 0xff),
1066 static_cast<uint8_t>((i >> 060) & 0xff),
1067 static_cast<uint8_t>((i >> 070) & 0xff),
1068 };
1069
1070 // compare result + size
1071 const auto result = json::to_bjdata(j);
1072 CHECK(result == expected);
1073 CHECK(result.size() == 9);
1074
1075 // check individual bytes
1076 CHECK(result[0] == 'L');
1077 uint64_t const restored = (static_cast<uint64_t>(result[8]) << 070) +
1078 (static_cast<uint64_t>(result[7]) << 060) +
1079 (static_cast<uint64_t>(result[6]) << 050) +
1080 (static_cast<uint64_t>(result[5]) << 040) +
1081 (static_cast<uint64_t>(result[4]) << 030) +
1082 (static_cast<uint64_t>(result[3]) << 020) +
1083 (static_cast<uint64_t>(result[2]) << 010) +
1084 static_cast<uint64_t>(result[1]);
1085 CHECK(restored == i);
1086
1087 // roundtrip
1088 CHECK(json::from_bjdata(result) == j);
1089 CHECK(json::from_bjdata(result, true, false) == j);
1090 }
1091 }
1092
1093 SECTION("9223372036854775808..18446744073709551615 (uint64)")
1094 {
1095 std::vector<uint64_t> const v = {9223372036854775808ull, 18446744073709551615ull};
1096 for (const uint64_t i : v)
1097 {
1098 CAPTURE(i)
1099
1100 // create JSON value with integer number
1101 json const j = i;
1102
1103 // check type
1104 CHECK(j.is_number_unsigned());
1105
1106 // create expected byte vector
1107 std::vector<uint8_t> const expected
1108 {
1109 'M',
1110 static_cast<uint8_t>(i & 0xff),
1111 static_cast<uint8_t>((i >> 010) & 0xff),
1112 static_cast<uint8_t>((i >> 020) & 0xff),
1113 static_cast<uint8_t>((i >> 030) & 0xff),
1114 static_cast<uint8_t>((i >> 040) & 0xff),
1115 static_cast<uint8_t>((i >> 050) & 0xff),
1116 static_cast<uint8_t>((i >> 060) & 0xff),
1117 static_cast<uint8_t>((i >> 070) & 0xff),
1118 };
1119
1120 // compare result + size
1121 const auto result = json::to_bjdata(j);
1122 CHECK(result == expected);
1123 CHECK(result.size() == 9);
1124
1125 // check individual bytes
1126 CHECK(result[0] == 'M');
1127 uint64_t const restored = (static_cast<uint64_t>(result[8]) << 070) +
1128 (static_cast<uint64_t>(result[7]) << 060) +
1129 (static_cast<uint64_t>(result[6]) << 050) +
1130 (static_cast<uint64_t>(result[5]) << 040) +
1131 (static_cast<uint64_t>(result[4]) << 030) +
1132 (static_cast<uint64_t>(result[3]) << 020) +
1133 (static_cast<uint64_t>(result[2]) << 010) +
1134 static_cast<uint64_t>(result[1]);
1135 CHECK(restored == i);
1136
1137 // roundtrip
1138 CHECK(json::from_bjdata(result) == j);
1139 CHECK(json::from_bjdata(result, true, false) == j);
1140 }
1141 }
1142 }
1143 SECTION("float64")
1144 {
1145 SECTION("3.1415925")
1146 {
1147 double v = 3.1415925;
1148 json const j = v;
1149 std::vector<uint8_t> const expected =
1150 {
1151 'D', 0xfc, 0xde, 0xa6, 0x3f, 0xfb, 0x21, 0x09, 0x40
1152 };
1153 const auto result = json::to_bjdata(j);
1154 CHECK(result == expected);
1155
1156 // roundtrip
1157 CHECK(json::from_bjdata(result) == j);
1158 CHECK(json::from_bjdata(result) == v);
1159 CHECK(json::from_bjdata(result, true, false) == j);
1160 }
1161 }
1162
1163 SECTION("half-precision float")
1164 {
1165 SECTION("simple half floats")
1166 {
1167 CHECK(json::parse("0.0") == json::from_bjdata(std::vector<uint8_t>({'h', 0x00, 0x00})));
1168 CHECK(json::parse("-0.0") == json::from_bjdata(std::vector<uint8_t>({'h', 0x00, 0x80})));
1169 CHECK(json::parse("1.0") == json::from_bjdata(std::vector<uint8_t>({'h', 0x00, 0x3c})));
1170 CHECK(json::parse("1.5") == json::from_bjdata(std::vector<uint8_t>({'h', 0x00, 0x3e})));
1171 CHECK(json::parse("65504.0") == json::from_bjdata(std::vector<uint8_t>({'h', 0xff, 0x7b})));
1172 }
1173
1174 SECTION("errors")
1175 {
1176 SECTION("no byte follows")
1177 {
1178 json _;
1179 std::vector<uint8_t> const vec0 = {'h'};
1180 CHECK_THROWS_WITH_AS(_ = json::from_bjdata(vec0), "[json.exception.parse_error.110] parse error at byte 2: syntax error while parsing BJData number: unexpected end of input", json::parse_error&);
1181 CHECK(json::from_bjdata(vec0, true, false).is_discarded());
1182 }
1183
1184 SECTION("only one byte follows")
1185 {
1186 json _;
1187 std::vector<uint8_t> const vec1 = {'h', 0x00};
1188 CHECK_THROWS_WITH_AS(_ = json::from_bjdata(vec1), "[json.exception.parse_error.110] parse error at byte 3: syntax error while parsing BJData number: unexpected end of input", json::parse_error&);
1189 CHECK(json::from_bjdata(vec1, true, false).is_discarded());
1190 }
1191 }
1192 }
1193
1194 SECTION("half-precision float (edge cases)")
1195 {
1196 SECTION("exp = 0b00000")
1197 {
1198 SECTION("0 (0 00000 0000000000)")
1199 {
1200 json const j = json::from_bjdata(std::vector<uint8_t>({'h', 0x00, 0x00}));
1201 json::number_float_t d{j};
1202 CHECK(d == 0.0);
1203 }
1204
1205 SECTION("-0 (1 00000 0000000000)")
1206 {
1207 json const j = json::from_bjdata(std::vector<uint8_t>({'h', 0x00, 0x80}));
1208 json::number_float_t d{j};
1209 CHECK(d == -0.0);
1210 }
1211
1212 SECTION("2**-24 (0 00000 0000000001)")
1213 {
1214 json const j = json::from_bjdata(std::vector<uint8_t>({'h', 0x01, 0x00}));
1215 json::number_float_t d{j};
1216 CHECK(d == std::pow(2.0, -24.0));
1217 }
1218 }
1219
1220 SECTION("exp = 0b11111")
1221 {
1222 SECTION("infinity (0 11111 0000000000)")
1223 {
1224 json const j = json::from_bjdata(std::vector<uint8_t>({'h', 0x00, 0x7c}));
1225 json::number_float_t d{j};
1226 CHECK(d == std::numeric_limits<json::number_float_t>::infinity());
1227 CHECK(j.dump() == "null");
1228 }
1229
1230 SECTION("-infinity (1 11111 0000000000)")
1231 {
1232 json const j = json::from_bjdata(std::vector<uint8_t>({'h', 0x00, 0xfc}));
1233 json::number_float_t d{j};
1234 CHECK(d == -std::numeric_limits<json::number_float_t>::infinity());
1235 CHECK(j.dump() == "null");
1236 }
1237 }
1238
1239 SECTION("other values from https://en.wikipedia.org/wiki/Half-precision_floating-point_format")
1240 {
1241 SECTION("1 (0 01111 0000000000)")
1242 {
1243 json const j = json::from_bjdata(std::vector<uint8_t>({'h', 0x00, 0x3c}));
1244 json::number_float_t d{j};
1245 CHECK(d == 1);
1246 }
1247
1248 SECTION("-2 (1 10000 0000000000)")
1249 {
1250 json const j = json::from_bjdata(std::vector<uint8_t>({'h', 0x00, 0xc0}));
1251 json::number_float_t d{j};
1252 CHECK(d == -2);
1253 }
1254
1255 SECTION("65504 (0 11110 1111111111)")
1256 {
1257 json const j = json::from_bjdata(std::vector<uint8_t>({'h', 0xff, 0x7b}));
1258 json::number_float_t d{j};
1259 CHECK(d == 65504);
1260 }
1261 }
1262
1263 SECTION("infinity")
1264 {
1265 json const j = json::from_bjdata(std::vector<uint8_t>({'h', 0x00, 0x7c}));
1266 json::number_float_t const d{j};
1267 CHECK_FALSE(std::isfinite(d));
1268 CHECK(j.dump() == "null");
1269 }
1270
1271 SECTION("NaN")
1272 {
1273 json const j = json::from_bjdata(std::vector<uint8_t>({'h', 0x00, 0x7e }));
1274 json::number_float_t const d{j};
1275 CHECK(std::isnan(d));
1276 CHECK(j.dump() == "null");
1277 }
1278 }
1279
1280 SECTION("high-precision number")
1281 {
1282 SECTION("unsigned integer number")
1283 {
1284 std::vector<uint8_t> const vec = {'H', 'i', 0x14, '1', '2', '3', '4', '5', '6', '7', '8', '9', '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', '0'};
1285 const auto j = json::from_bjdata(vec);
1286 CHECK(j.is_number_unsigned());
1287 CHECK(j.dump() == "12345678901234567890");
1288 }
1289
1290 SECTION("signed integer number")
1291 {
1292 std::vector<uint8_t> const vec = {'H', 'i', 0x13, '-', '1', '2', '3', '4', '5', '6', '7', '8', '9', '0', '1', '2', '3', '4', '5', '6', '7', '8'};
1293 const auto j = json::from_bjdata(vec);
1294 CHECK(j.is_number_integer());
1295 CHECK(j.dump() == "-123456789012345678");
1296 }
1297
1298 SECTION("floating-point number")
1299 {
1300 std::vector<uint8_t> const vec = {'H', 'i', 0x16, '3', '.', '1', '4', '1', '5', '9', '2', '6', '5', '3', '5', '8', '9', '7', '9', '3', '2', '3', '8', '4', '6'};
1301 const auto j = json::from_bjdata(vec);
1302 CHECK(j.is_number_float());
1303 CHECK(j.dump() == "3.141592653589793");
1304 }
1305
1306 SECTION("errors")
1307 {
1308 // error while parsing length
1309 std::vector<uint8_t> const vec0 = {'H', 'i'};
1310 CHECK(json::from_bjdata(vec0, true, false).is_discarded());
1311 // error while parsing string
1312 std::vector<uint8_t> const vec1 = {'H', 'i', '1'};
1313 CHECK(json::from_bjdata(vec1, true, false).is_discarded());
1314
1315 json _;
1316 std::vector<uint8_t> const vec2 = {'H', 'i', 2, '1', 'A', '3'};
1317 CHECK_THROWS_WITH_AS(_ = json::from_bjdata(vec2), "[json.exception.parse_error.115] parse error at byte 5: syntax error while parsing BJData high-precision number: invalid number text: 1A", json::parse_error);
1318 std::vector<uint8_t> const vec3 = {'H', 'i', 2, '1', '.'};
1319 CHECK_THROWS_WITH_AS(_ = json::from_bjdata(vec3), "[json.exception.parse_error.115] parse error at byte 5: syntax error while parsing BJData high-precision number: invalid number text: 1.", json::parse_error);
1320 std::vector<uint8_t> const vec4 = {'H', 2, '1', '0'};
1321 CHECK_THROWS_WITH_AS(_ = json::from_bjdata(vec4), "[json.exception.parse_error.113] parse error at byte 2: syntax error while parsing BJData size: expected length type specification (U, i, u, I, m, l, M, L) after '#'; last byte: 0x02", json::parse_error);
1322 }
1323 }
1324 }
1325
1326 SECTION("string")
1327 {
1328 SECTION("N = 0..127")
1329 {
1330 for (size_t N = 0; N <= 127; ++N)
1331 {
1332 CAPTURE(N)
1333
1334 // create JSON value with string containing of N * 'x'
1335 const auto s = std::string(N, 'x');
1336 json const j = s;
1337
1338 // create expected byte vector
1339 std::vector<uint8_t> expected;
1340 expected.push_back('S');
1341 expected.push_back('i');
1342 expected.push_back(static_cast<uint8_t>(N));
1343 for (size_t i = 0; i < N; ++i)
1344 {
1345 expected.push_back('x');
1346 }
1347
1348 // compare result + size
1349 const auto result = json::to_bjdata(j);
1350 CHECK(result == expected);
1351 CHECK(result.size() == N + 3);
1352 // check that no null byte is appended
1353 if (N > 0)
1354 {
1355 CHECK(result.back() != '\x00');
1356 }
1357
1358 // roundtrip
1359 CHECK(json::from_bjdata(result) == j);
1360 CHECK(json::from_bjdata(result, true, false) == j);
1361 }
1362 }
1363
1364 SECTION("N = 128..255")
1365 {
1366 for (size_t N = 128; N <= 255; ++N)
1367 {
1368 CAPTURE(N)
1369
1370 // create JSON value with string containing of N * 'x'
1371 const auto s = std::string(N, 'x');
1372 json const j = s;
1373
1374 // create expected byte vector
1375 std::vector<uint8_t> expected;
1376 expected.push_back('S');
1377 expected.push_back('U');
1378 expected.push_back(static_cast<uint8_t>(N));
1379 for (size_t i = 0; i < N; ++i)
1380 {
1381 expected.push_back('x');
1382 }
1383
1384 // compare result + size
1385 const auto result = json::to_bjdata(j);
1386 CHECK(result == expected);
1387 CHECK(result.size() == N + 3);
1388 // check that no null byte is appended
1389 CHECK(result.back() != '\x00');
1390
1391 // roundtrip
1392 CHECK(json::from_bjdata(result) == j);
1393 CHECK(json::from_bjdata(result, true, false) == j);
1394 }
1395 }
1396
1397 SECTION("N = 256..32767")
1398 {
1399 for (const size_t N :
1400 {
1401 256u, 999u, 1025u, 3333u, 2048u, 32767u
1402 })
1403 {
1404 CAPTURE(N)
1405
1406 // create JSON value with string containing of N * 'x'
1407 const auto s = std::string(N, 'x');
1408 json const j = s;
1409
1410 // create expected byte vector (hack: create string first)
1411 std::vector<uint8_t> expected(N, 'x');
1412 // reverse order of commands, because we insert at begin()
1413 expected.insert(expected.begin(), static_cast<uint8_t>((N >> 8) & 0xff));
1414 expected.insert(expected.begin(), static_cast<uint8_t>(N & 0xff));
1415 expected.insert(expected.begin(), 'I');
1416 expected.insert(expected.begin(), 'S');
1417
1418 // compare result + size
1419 const auto result = json::to_bjdata(j);
1420 CHECK(result == expected);
1421 CHECK(result.size() == N + 4);
1422 // check that no null byte is appended
1423 CHECK(result.back() != '\x00');
1424
1425 // roundtrip
1426 CHECK(json::from_bjdata(result) == j);
1427 CHECK(json::from_bjdata(result, true, false) == j);
1428 }
1429 }
1430
1431 SECTION("N = 32768..65535")
1432 {
1433 for (const size_t N :
1434 {
1435 32768u, 55555u, 65535u
1436 })
1437 {
1438 CAPTURE(N)
1439
1440 // create JSON value with string containing of N * 'x'
1441 const auto s = std::string(N, 'x');
1442 json const j = s;
1443
1444 // create expected byte vector (hack: create string first)
1445 std::vector<uint8_t> expected(N, 'x');
1446 // reverse order of commands, because we insert at begin()
1447 expected.insert(expected.begin(), static_cast<uint8_t>((N >> 8) & 0xff));
1448 expected.insert(expected.begin(), static_cast<uint8_t>(N & 0xff));
1449 expected.insert(expected.begin(), 'u');
1450 expected.insert(expected.begin(), 'S');
1451
1452 // compare result + size
1453 const auto result = json::to_bjdata(j);
1454 CHECK(result == expected);
1455 CHECK(result.size() == N + 4);
1456 // check that no null byte is appended
1457 CHECK(result.back() != '\x00');
1458
1459 // roundtrip
1460 CHECK(json::from_bjdata(result) == j);
1461 CHECK(json::from_bjdata(result, true, false) == j);
1462 }
1463 }
1464
1465 SECTION("N = 65536..2147483647")
1466 {
1467 for (const size_t N :
1468 {
1469 65536u, 77777u, 1048576u
1470 })
1471 {
1472 CAPTURE(N)
1473
1474 // create JSON value with string containing of N * 'x'
1475 const auto s = std::string(N, 'x');
1476 json const j = s;
1477
1478 // create expected byte vector (hack: create string first)
1479 std::vector<uint8_t> expected(N, 'x');
1480 // reverse order of commands, because we insert at begin()
1481 expected.insert(expected.begin(), static_cast<uint8_t>((N >> 24) & 0xff));
1482 expected.insert(expected.begin(), static_cast<uint8_t>((N >> 16) & 0xff));
1483 expected.insert(expected.begin(), static_cast<uint8_t>((N >> 8) & 0xff));
1484 expected.insert(expected.begin(), static_cast<uint8_t>(N & 0xff));
1485 expected.insert(expected.begin(), 'l');
1486 expected.insert(expected.begin(), 'S');
1487
1488 // compare result + size
1489 const auto result = json::to_bjdata(j);
1490 CHECK(result == expected);
1491 CHECK(result.size() == N + 6);
1492 // check that no null byte is appended
1493 CHECK(result.back() != '\x00');
1494
1495 // roundtrip
1496 CHECK(json::from_bjdata(result) == j);
1497 CHECK(json::from_bjdata(result, true, false) == j);
1498 }
1499 }
1500 }
1501
1502 SECTION("binary")
1503 {
1504 SECTION("N = 0..127")
1505 {
1506 for (std::size_t N = 0; N <= 127; ++N)
1507 {
1508 CAPTURE(N)
1509
1510 // create JSON value with byte array containing of N * 'x'
1511 const auto s = std::vector<std::uint8_t>(N, 'x');
1512 json const j = json::binary(s);
1513
1514 // create expected byte vector
1515 std::vector<std::uint8_t> expected;
1516 expected.push_back(static_cast<std::uint8_t>('['));
1517 if (N != 0)
1518 {
1519 expected.push_back(static_cast<std::uint8_t>('$'));
1520 expected.push_back(static_cast<std::uint8_t>('U'));
1521 }
1522 expected.push_back(static_cast<std::uint8_t>('#'));
1523 expected.push_back(static_cast<std::uint8_t>('i'));
1524 expected.push_back(static_cast<std::uint8_t>(N));
1525 for (size_t i = 0; i < N; ++i)
1526 {
1527 expected.push_back(0x78);
1528 }
1529
1530 // compare result + size
1531 const auto result = json::to_bjdata(j, true, true);
1532 CHECK(result == expected);
1533 if (N == 0)
1534 {
1535 CHECK(result.size() == N + 4);
1536 }
1537 else
1538 {
1539 CHECK(result.size() == N + 6);
1540 }
1541
1542 // check that no null byte is appended
1543 if (N > 0)
1544 {
1545 CHECK(result.back() != '\x00');
1546 }
1547
1548 // roundtrip only works to an array of numbers
1549 json j_out = s;
1550 CHECK(json::from_bjdata(result) == j_out);
1551 CHECK(json::from_bjdata(result, true, false) == j_out);
1552 }
1553 }
1554
1555 SECTION("N = 128..255")
1556 {
1557 for (std::size_t N = 128; N <= 255; ++N)
1558 {
1559 CAPTURE(N)
1560
1561 // create JSON value with byte array containing of N * 'x'
1562 const auto s = std::vector<std::uint8_t>(N, 'x');
1563 json const j = json::binary(s);
1564
1565 // create expected byte vector
1566 std::vector<uint8_t> expected;
1567 expected.push_back(static_cast<std::uint8_t>('['));
1568 expected.push_back(static_cast<std::uint8_t>('$'));
1569 expected.push_back(static_cast<std::uint8_t>('U'));
1570 expected.push_back(static_cast<std::uint8_t>('#'));
1571 expected.push_back(static_cast<std::uint8_t>('U'));
1572 expected.push_back(static_cast<std::uint8_t>(N));
1573 for (size_t i = 0; i < N; ++i)
1574 {
1575 expected.push_back(0x78);
1576 }
1577
1578 // compare result + size
1579 const auto result = json::to_bjdata(j, true, true);
1580 CHECK(result == expected);
1581 CHECK(result.size() == N + 6);
1582 // check that no null byte is appended
1583 CHECK(result.back() != '\x00');
1584
1585 // roundtrip only works to an array of numbers
1586 json j_out = s;
1587 CHECK(json::from_bjdata(result) == j_out);
1588 CHECK(json::from_bjdata(result, true, false) == j_out);
1589 }
1590 }
1591
1592 SECTION("N = 256..32767")
1593 {
1594 for (const std::size_t N :
1595 {
1596 256u, 999u, 1025u, 3333u, 2048u, 32767u
1597 })
1598 {
1599 CAPTURE(N)
1600
1601 // create JSON value with byte array containing of N * 'x'
1602 const auto s = std::vector<std::uint8_t>(N, 'x');
1603 json const j = json::binary(s);
1604
1605 // create expected byte vector
1606 std::vector<std::uint8_t> expected(N + 7, 'x');
1607 expected[0] = '[';
1608 expected[1] = '$';
1609 expected[2] = 'U';
1610 expected[3] = '#';
1611 expected[4] = 'I';
1612 expected[5] = static_cast<std::uint8_t>(N & 0xFF);
1613 expected[6] = static_cast<std::uint8_t>((N >> 8) & 0xFF);
1614
1615 // compare result + size
1616 const auto result = json::to_bjdata(j, true, true);
1617 CHECK(result == expected);
1618 CHECK(result.size() == N + 7);
1619 // check that no null byte is appended
1620 CHECK(result.back() != '\x00');
1621
1622 // roundtrip only works to an array of numbers
1623 json j_out = s;
1624 CHECK(json::from_bjdata(result) == j_out);
1625 CHECK(json::from_bjdata(result, true, false) == j_out);
1626 }
1627 }
1628
1629 SECTION("N = 32768..65535")
1630 {
1631 for (const std::size_t N :
1632 {
1633 32768u, 55555u, 65535u
1634 })
1635 {
1636 CAPTURE(N)
1637
1638 // create JSON value with byte array containing of N * 'x'
1639 const auto s = std::vector<std::uint8_t>(N, 'x');
1640 json const j = json::binary(s);
1641
1642 // create expected byte vector
1643 std::vector<std::uint8_t> expected(N + 7, 'x');
1644 expected[0] = '[';
1645 expected[1] = '$';
1646 expected[2] = 'U';
1647 expected[3] = '#';
1648 expected[4] = 'u';
1649 expected[5] = static_cast<std::uint8_t>(N & 0xFF);
1650 expected[6] = static_cast<std::uint8_t>((N >> 8) & 0xFF);
1651
1652 // compare result + size
1653 const auto result = json::to_bjdata(j, true, true);
1654 CHECK(result == expected);
1655 CHECK(result.size() == N + 7);
1656 // check that no null byte is appended
1657 CHECK(result.back() != '\x00');
1658
1659 // roundtrip only works to an array of numbers
1660 json j_out = s;
1661 CHECK(json::from_bjdata(result) == j_out);
1662 CHECK(json::from_bjdata(result, true, false) == j_out);
1663 }
1664 }
1665
1666 SECTION("N = 65536..2147483647")
1667 {
1668 for (const std::size_t N :
1669 {
1670 65536u, 77777u, 1048576u
1671 })
1672 {
1673 CAPTURE(N)
1674
1675 // create JSON value with byte array containing of N * 'x'
1676 const auto s = std::vector<std::uint8_t>(N, 'x');
1677 json const j = json::binary(s);
1678
1679 // create expected byte vector
1680 std::vector<std::uint8_t> expected(N + 9, 'x');
1681 expected[0] = '[';
1682 expected[1] = '$';
1683 expected[2] = 'U';
1684 expected[3] = '#';
1685 expected[4] = 'l';
1686 expected[5] = static_cast<std::uint8_t>(N & 0xFF);
1687 expected[6] = static_cast<std::uint8_t>((N >> 8) & 0xFF);
1688 expected[7] = static_cast<std::uint8_t>((N >> 16) & 0xFF);
1689 expected[8] = static_cast<std::uint8_t>((N >> 24) & 0xFF);
1690
1691 // compare result + size
1692 const auto result = json::to_bjdata(j, true, true);
1693 CHECK(result == expected);
1694 CHECK(result.size() == N + 9);
1695 // check that no null byte is appended
1696 CHECK(result.back() != '\x00');
1697
1698 // roundtrip only works to an array of numbers
1699 json j_out = s;
1700 CHECK(json::from_bjdata(result) == j_out);
1701 CHECK(json::from_bjdata(result, true, false) == j_out);
1702 }
1703 }
1704
1705 SECTION("Other Serializations")
1706 {
1707 const std::size_t N = 10;
1708 const auto s = std::vector<std::uint8_t>(N, 'x');
1709 json const j = json::binary(s);
1710
1711 SECTION("No Count No Type")
1712 {
1713 std::vector<uint8_t> expected;
1714 expected.push_back(static_cast<std::uint8_t>('['));
1715 for (std::size_t i = 0; i < N; ++i)
1716 {
1717 expected.push_back(static_cast<std::uint8_t>('U'));
1718 expected.push_back(static_cast<std::uint8_t>(0x78));
1719 }
1720 expected.push_back(static_cast<std::uint8_t>(']'));
1721
1722 // compare result + size
1723 const auto result = json::to_bjdata(j, false, false);
1724 CHECK(result == expected);
1725 CHECK(result.size() == N + 12);
1726 // check that no null byte is appended
1727 CHECK(result.back() != '\x00');
1728
1729 // roundtrip only works to an array of numbers
1730 json j_out = s;
1731 CHECK(json::from_bjdata(result) == j_out);
1732 CHECK(json::from_bjdata(result, true, false) == j_out);
1733 }
1734
1735 SECTION("Yes Count No Type")
1736 {
1737 std::vector<std::uint8_t> expected;
1738 expected.push_back(static_cast<std::uint8_t>('['));
1739 expected.push_back(static_cast<std::uint8_t>('#'));
1740 expected.push_back(static_cast<std::uint8_t>('i'));
1741 expected.push_back(static_cast<std::uint8_t>(N));
1742
1743 for (size_t i = 0; i < N; ++i)
1744 {
1745 expected.push_back(static_cast<std::uint8_t>('U'));
1746 expected.push_back(static_cast<std::uint8_t>(0x78));
1747 }
1748
1749 // compare result + size
1750 const auto result = json::to_bjdata(j, true, false);
1751 CHECK(result == expected);
1752 CHECK(result.size() == N + 14);
1753 // check that no null byte is appended
1754 CHECK(result.back() != '\x00');
1755
1756 // roundtrip only works to an array of numbers
1757 json j_out = s;
1758 CHECK(json::from_bjdata(result) == j_out);
1759 CHECK(json::from_bjdata(result, true, false) == j_out);
1760 }
1761 }
1762 }
1763 SECTION("array")
1764 {
1765 SECTION("empty")
1766 {
1767 SECTION("size=false type=false")
1768 {
1769 json const j = json::array();
1770 std::vector<uint8_t> const expected = {'[', ']'};
1771 const auto result = json::to_bjdata(j);
1772 CHECK(result == expected);
1773
1774 // roundtrip
1775 CHECK(json::from_bjdata(result) == j);
1776 CHECK(json::from_bjdata(result, true, false) == j);
1777 }
1778
1779 SECTION("size=true type=false")
1780 {
1781 json const j = json::array();
1782 std::vector<uint8_t> const expected = {'[', '#', 'i', 0};
1783 const auto result = json::to_bjdata(j, true);
1784 CHECK(result == expected);
1785
1786 // roundtrip
1787 CHECK(json::from_bjdata(result) == j);
1788 CHECK(json::from_bjdata(result, true, false) == j);
1789 }
1790
1791 SECTION("size=true type=true")
1792 {
1793 json const j = json::array();
1794 std::vector<uint8_t> const expected = {'[', '#', 'i', 0};
1795 const auto result = json::to_bjdata(j, true, true);
1796 CHECK(result == expected);
1797
1798 // roundtrip
1799 CHECK(json::from_bjdata(result) == j);
1800 CHECK(json::from_bjdata(result, true, false) == j);
1801 }
1802 }
1803
1804 SECTION("[null]")
1805 {
1806 SECTION("size=false type=false")
1807 {
1808 json const j = {nullptr};
1809 std::vector<uint8_t> const expected = {'[', 'Z', ']'};
1810 const auto result = json::to_bjdata(j);
1811 CHECK(result == expected);
1812
1813 // roundtrip
1814 CHECK(json::from_bjdata(result) == j);
1815 CHECK(json::from_bjdata(result, true, false) == j);
1816 }
1817
1818 SECTION("size=true type=false")
1819 {
1820 json const j = {nullptr};
1821 std::vector<uint8_t> const expected = {'[', '#', 'i', 1, 'Z'};
1822 const auto result = json::to_bjdata(j, true);
1823 CHECK(result == expected);
1824
1825 // roundtrip
1826 CHECK(json::from_bjdata(result) == j);
1827 CHECK(json::from_bjdata(result, true, false) == j);
1828 }
1829
1830 SECTION("size=true type=true")
1831 {
1832 json const j = {nullptr};
1833 std::vector<uint8_t> const expected = {'[', '#', 'i', 1, 'Z'};
1834 const auto result = json::to_bjdata(j, true, true);
1835 CHECK(result == expected);
1836
1837 // roundtrip
1838 CHECK(json::from_bjdata(result) == j);
1839 CHECK(json::from_bjdata(result, true, false) == j);
1840 }
1841 }
1842
1843 SECTION("[1,2,3,4,5]")
1844 {
1845 SECTION("size=false type=false")
1846 {
1847 json const j = json::parse("[1,2,3,4,5]");
1848 std::vector<uint8_t> const expected = {'[', 'i', 1, 'i', 2, 'i', 3, 'i', 4, 'i', 5, ']'};
1849 const auto result = json::to_bjdata(j);
1850 CHECK(result == expected);
1851
1852 // roundtrip
1853 CHECK(json::from_bjdata(result) == j);
1854 CHECK(json::from_bjdata(result, true, false) == j);
1855 }
1856
1857 SECTION("size=true type=false")
1858 {
1859 json const j = json::parse("[1,2,3,4,5]");
1860 std::vector<uint8_t> const expected = {'[', '#', 'i', 5, 'i', 1, 'i', 2, 'i', 3, 'i', 4, 'i', 5};
1861 const auto result = json::to_bjdata(j, true);
1862 CHECK(result == expected);
1863
1864 // roundtrip
1865 CHECK(json::from_bjdata(result) == j);
1866 CHECK(json::from_bjdata(result, true, false) == j);
1867 }
1868
1869 SECTION("size=true type=true")
1870 {
1871 json const j = json::parse("[1,2,3,4,5]");
1872 std::vector<uint8_t> const expected = {'[', '$', 'i', '#', 'i', 5, 1, 2, 3, 4, 5};
1873 const auto result = json::to_bjdata(j, true, true);
1874 CHECK(result == expected);
1875
1876 // roundtrip
1877 CHECK(json::from_bjdata(result) == j);
1878 CHECK(json::from_bjdata(result, true, false) == j);
1879 }
1880 }
1881
1882 SECTION("[[[[]]]]")
1883 {
1884 SECTION("size=false type=false")
1885 {
1886 json const j = json::parse("[[[[]]]]");
1887 std::vector<uint8_t> const expected = {'[', '[', '[', '[', ']', ']', ']', ']'};
1888 const auto result = json::to_bjdata(j);
1889 CHECK(result == expected);
1890
1891 // roundtrip
1892 CHECK(json::from_bjdata(result) == j);
1893 CHECK(json::from_bjdata(result, true, false) == j);
1894 }
1895
1896 SECTION("size=true type=false")
1897 {
1898 json const j = json::parse("[[[[]]]]");
1899 std::vector<uint8_t> const expected = {'[', '#', 'i', 1, '[', '#', 'i', 1, '[', '#', 'i', 1, '[', '#', 'i', 0};
1900 const auto result = json::to_bjdata(j, true);
1901 CHECK(result == expected);
1902
1903 // roundtrip
1904 CHECK(json::from_bjdata(result) == j);
1905 CHECK(json::from_bjdata(result, true, false) == j);
1906 }
1907
1908 SECTION("size=true type=true")
1909 {
1910 json const j = json::parse("[[[[]]]]");
1911 std::vector<uint8_t> const expected = {'[', '#', 'i', 1, '[', '#', 'i', 1, '[', '#', 'i', 1, '[', '#', 'i', 0};
1912 const auto result = json::to_bjdata(j, true, true);
1913 CHECK(result == expected);
1914
1915 // roundtrip
1916 CHECK(json::from_bjdata(result) == j);
1917 CHECK(json::from_bjdata(result, true, false) == j);
1918 }
1919 }
1920
1921 SECTION("array with int16_t elements")
1922 {
1923 SECTION("size=false type=false")
1924 {
1925 json j(257, nullptr);
1926 std::vector<uint8_t> expected(j.size() + 2, 'Z'); // all null
1927 expected[0] = '['; // opening array
1928 expected[258] = ']'; // closing array
1929 const auto result = json::to_bjdata(j);
1930 CHECK(result == expected);
1931
1932 // roundtrip
1933 CHECK(json::from_bjdata(result) == j);
1934 CHECK(json::from_bjdata(result, true, false) == j);
1935 }
1936
1937 SECTION("size=true type=false")
1938 {
1939 json j(257, nullptr);
1940 std::vector<uint8_t> expected(j.size() + 5, 'Z'); // all null
1941 expected[0] = '['; // opening array
1942 expected[1] = '#'; // array size
1943 expected[2] = 'I'; // int16
1944 expected[3] = 0x01; // 0x0101, first byte
1945 expected[4] = 0x01; // 0x0101, second byte
1946 const auto result = json::to_bjdata(j, true);
1947 CHECK(result == expected);
1948
1949 // roundtrip
1950 CHECK(json::from_bjdata(result) == j);
1951 CHECK(json::from_bjdata(result, true, false) == j);
1952 }
1953 }
1954
1955 SECTION("array with uint16_t elements")
1956 {
1957 SECTION("size=false type=false")
1958 {
1959 json j(32768, nullptr);
1960 std::vector<uint8_t> expected(j.size() + 2, 'Z'); // all null
1961 expected[0] = '['; // opening array
1962 expected[32769] = ']'; // closing array
1963 const auto result = json::to_bjdata(j);
1964 CHECK(result == expected);
1965
1966 // roundtrip
1967 CHECK(json::from_bjdata(result) == j);
1968 CHECK(json::from_bjdata(result, true, false) == j);
1969 }
1970
1971 SECTION("size=true type=false")
1972 {
1973 json j(32768, nullptr);
1974 std::vector<uint8_t> expected(j.size() + 5, 'Z'); // all null
1975 expected[0] = '['; // opening array
1976 expected[1] = '#'; // array size
1977 expected[2] = 'u'; // int16
1978 expected[3] = 0x00; // 0x0101, first byte
1979 expected[4] = 0x80; // 0x0101, second byte
1980 const auto result = json::to_bjdata(j, true);
1981 CHECK(result == expected);
1982
1983 // roundtrip
1984 CHECK(json::from_bjdata(result) == j);
1985 CHECK(json::from_bjdata(result, true, false) == j);
1986 }
1987 }
1988
1989 SECTION("array with int32_t elements")
1990 {
1991 SECTION("size=false type=false")
1992 {
1993 json j(65793, nullptr);
1994 std::vector<uint8_t> expected(j.size() + 2, 'Z'); // all null
1995 expected[0] = '['; // opening array
1996 expected[65794] = ']'; // closing array
1997 const auto result = json::to_bjdata(j);
1998 CHECK(result == expected);
1999
2000 // roundtrip
2001 CHECK(json::from_bjdata(result) == j);
2002 CHECK(json::from_bjdata(result, true, false) == j);
2003 }
2004
2005 SECTION("size=true type=false")
2006 {
2007 json j(65793, nullptr);
2008 std::vector<uint8_t> expected(j.size() + 7, 'Z'); // all null
2009 expected[0] = '['; // opening array
2010 expected[1] = '#'; // array size
2011 expected[2] = 'l'; // int32
2012 expected[3] = 0x01; // 0x00010101, fourth byte
2013 expected[4] = 0x01; // 0x00010101, third byte
2014 expected[5] = 0x01; // 0x00010101, second byte
2015 expected[6] = 0x00; // 0x00010101, first byte
2016 const auto result = json::to_bjdata(j, true);
2017 CHECK(result == expected);
2018
2019 // roundtrip
2020 CHECK(json::from_bjdata(result) == j);
2021 CHECK(json::from_bjdata(result, true, false) == j);
2022 }
2023 }
2024 }
2025
2026 SECTION("object")
2027 {
2028 SECTION("empty")
2029 {
2030 SECTION("size=false type=false")
2031 {
2032 json const j = json::object();
2033 std::vector<uint8_t> const expected = {'{', '}'};
2034 const auto result = json::to_bjdata(j);
2035 CHECK(result == expected);
2036
2037 // roundtrip
2038 CHECK(json::from_bjdata(result) == j);
2039 CHECK(json::from_bjdata(result, true, false) == j);
2040 }
2041
2042 SECTION("size=true type=false")
2043 {
2044 json const j = json::object();
2045 std::vector<uint8_t> const expected = {'{', '#', 'i', 0};
2046 const auto result = json::to_bjdata(j, true);
2047 CHECK(result == expected);
2048
2049 // roundtrip
2050 CHECK(json::from_bjdata(result) == j);
2051 CHECK(json::from_bjdata(result, true, false) == j);
2052 }
2053
2054 SECTION("size=true type=true")
2055 {
2056 json const j = json::object();
2057 std::vector<uint8_t> const expected = {'{', '#', 'i', 0};
2058 const auto result = json::to_bjdata(j, true, true);
2059 CHECK(result == expected);
2060
2061 // roundtrip
2062 CHECK(json::from_bjdata(result) == j);
2063 CHECK(json::from_bjdata(result, true, false) == j);
2064 }
2065 }
2066
2067 SECTION("{\"\":null}")
2068 {
2069 SECTION("size=false type=false")
2070 {
2071 json const j = {{"", nullptr}};
2072 std::vector<uint8_t> const expected = {'{', 'i', 0, 'Z', '}'};
2073 const auto result = json::to_bjdata(j);
2074 CHECK(result == expected);
2075
2076 // roundtrip
2077 CHECK(json::from_bjdata(result) == j);
2078 CHECK(json::from_bjdata(result, true, false) == j);
2079 }
2080
2081 SECTION("size=true type=false")
2082 {
2083 json const j = {{"", nullptr}};
2084 std::vector<uint8_t> const expected = {'{', '#', 'i', 1, 'i', 0, 'Z'};
2085 const auto result = json::to_bjdata(j, true);
2086 CHECK(result == expected);
2087
2088 // roundtrip
2089 CHECK(json::from_bjdata(result) == j);
2090 CHECK(json::from_bjdata(result, true, false) == j);
2091 }
2092 }
2093
2094 SECTION("{\"a\": {\"b\": {\"c\": {}}}}")
2095 {
2096 SECTION("size=false type=false")
2097 {
2098 json const j = json::parse(R"({"a": {"b": {"c": {}}}})");
2099 std::vector<uint8_t> const expected =
2100 {
2101 '{', 'i', 1, 'a', '{', 'i', 1, 'b', '{', 'i', 1, 'c', '{', '}', '}', '}', '}'
2102 };
2103 const auto result = json::to_bjdata(j);
2104 CHECK(result == expected);
2105
2106 // roundtrip
2107 CHECK(json::from_bjdata(result) == j);
2108 CHECK(json::from_bjdata(result, true, false) == j);
2109 }
2110
2111 SECTION("size=true type=false")
2112 {
2113 json const j = json::parse(R"({"a": {"b": {"c": {}}}})");
2114 std::vector<uint8_t> const expected =
2115 {
2116 '{', '#', 'i', 1, 'i', 1, 'a', '{', '#', 'i', 1, 'i', 1, 'b', '{', '#', 'i', 1, 'i', 1, 'c', '{', '#', 'i', 0
2117 };
2118 const auto result = json::to_bjdata(j, true);
2119 CHECK(result == expected);
2120
2121 // roundtrip
2122 CHECK(json::from_bjdata(result) == j);
2123 CHECK(json::from_bjdata(result, true, false) == j);
2124 }
2125
2126 SECTION("size=true type=true ignore object type marker")
2127 {
2128 json const j = json::parse(R"({"a": {"b": {"c": {}}}})");
2129 std::vector<uint8_t> const expected =
2130 {
2131 '{', '#', 'i', 1, 'i', 1, 'a', '{', '#', 'i', 1, 'i', 1, 'b', '{', '#', 'i', 1, 'i', 1, 'c', '{', '#', 'i', 0
2132 };
2133 const auto result = json::to_bjdata(j, true, true);
2134 CHECK(result == expected);
2135
2136 // roundtrip
2137 CHECK(json::from_bjdata(result) == j);
2138 CHECK(json::from_bjdata(result, true, false) == j);
2139 }
2140 }
2141 }
2142 }
2143
2144 SECTION("errors")
2145 {
2146 SECTION("strict mode")
2147 {
2148 std::vector<uint8_t> const vec = {'Z', 'Z'};
2149 SECTION("non-strict mode")
2150 {
2151 const auto result = json::from_bjdata(vec, false);
2152 CHECK(result == json());
2153 }
2154
2155 SECTION("strict mode")
2156 {
2157 json _;
2158 CHECK_THROWS_WITH_AS(_ = json::from_bjdata(vec),
2159 "[json.exception.parse_error.110] parse error at byte 2: syntax error while parsing BJData value: expected end of input; last byte: 0x5A", json::parse_error&);
2160 }
2161 }
2162 }
2163
2164 SECTION("SAX aborts")
2165 {
2166 SECTION("start_array()")
2167 {
2168 std::vector<uint8_t> const v = {'[', 'T', 'F', ']'};
2169 SaxCountdown scp(0);
2170 CHECK_FALSE(json::sax_parse(v, &scp, json::input_format_t::bjdata));
2171 }
2172
2173 SECTION("start_object()")
2174 {
2175 std::vector<uint8_t> const v = {'{', 'i', 3, 'f', 'o', 'o', 'F', '}'};
2176 SaxCountdown scp(0);
2177 CHECK_FALSE(json::sax_parse(v, &scp, json::input_format_t::bjdata));
2178 }
2179
2180 SECTION("key() in object")
2181 {
2182 std::vector<uint8_t> const v = {'{', 'i', 3, 'f', 'o', 'o', 'F', '}'};
2183 SaxCountdown scp(1);
2184 CHECK_FALSE(json::sax_parse(v, &scp, json::input_format_t::bjdata));
2185 }
2186
2187 SECTION("start_array(len)")
2188 {
2189 std::vector<uint8_t> const v = {'[', '#', 'i', '2', 'T', 'F'};
2190 SaxCountdown scp(0);
2191 CHECK_FALSE(json::sax_parse(v, &scp, json::input_format_t::bjdata));
2192 }
2193
2194 SECTION("start_object(len)")
2195 {
2196 std::vector<uint8_t> const v = {'{', '#', 'i', '1', 3, 'f', 'o', 'o', 'F'};
2197 SaxCountdown scp(0);
2198 CHECK_FALSE(json::sax_parse(v, &scp, json::input_format_t::bjdata));
2199 }
2200
2201 SECTION("key() in object with length")
2202 {
2203 std::vector<uint8_t> const v = {'{', 'i', 3, 'f', 'o', 'o', 'F', '}'};
2204 SaxCountdown scp(1);
2205 CHECK_FALSE(json::sax_parse(v, &scp, json::input_format_t::bjdata));
2206 }
2207
2208 SECTION("start_array() in ndarray _ArraySize_")
2209 {
2210 std::vector<uint8_t> const v = {'[', '$', 'i', '#', '[', '$', 'i', '#', 'i', 2, 2, 1, 1, 2};
2211 SaxCountdown scp(2);
2212 CHECK_FALSE(json::sax_parse(v, &scp, json::input_format_t::bjdata));
2213 }
2214
2215 SECTION("number_integer() in ndarray _ArraySize_")
2216 {
2217 std::vector<uint8_t> const v = {'[', '$', 'U', '#', '[', '$', 'i', '#', 'i', 2, 2, 1, 1, 2};
2218 SaxCountdown scp(3);
2219 CHECK_FALSE(json::sax_parse(v, &scp, json::input_format_t::bjdata));
2220 }
2221
2222 SECTION("key() in ndarray _ArrayType_")
2223 {
2224 std::vector<uint8_t> const v = {'[', '$', 'U', '#', '[', '$', 'U', '#', 'i', 2, 2, 2, 1, 2, 3, 4};
2225 SaxCountdown scp(6);
2226 CHECK_FALSE(json::sax_parse(v, &scp, json::input_format_t::bjdata));
2227 }
2228
2229 SECTION("string() in ndarray _ArrayType_")
2230 {
2231 std::vector<uint8_t> const v = {'[', '$', 'U', '#', '[', '$', 'U', '#', 'i', 2, 2, 2, 1, 2, 3, 4};
2232 SaxCountdown scp(7);
2233 CHECK_FALSE(json::sax_parse(v, &scp, json::input_format_t::bjdata));
2234 }
2235
2236 SECTION("key() in ndarray _ArrayData_")
2237 {
2238 std::vector<uint8_t> const v = {'[', '$', 'U', '#', '[', '$', 'U', '#', 'i', 2, 2, 2, 1, 2, 3, 4};
2239 SaxCountdown scp(8);
2240 CHECK_FALSE(json::sax_parse(v, &scp, json::input_format_t::bjdata));
2241 }
2242
2243 SECTION("string() in ndarray _ArrayData_")
2244 {
2245 std::vector<uint8_t> const v = {'[', '$', 'U', '#', '[', '$', 'U', '#', 'i', 2, 2, 2, 1, 2, 3, 4};
2246 SaxCountdown scp(9);
2247 CHECK_FALSE(json::sax_parse(v, &scp, json::input_format_t::bjdata));
2248 }
2249
2250 SECTION("string() in ndarray _ArrayType_")
2251 {
2252 std::vector<uint8_t> const v = {'[', '$', 'U', '#', '[', '$', 'i', '#', 'i', 2, 3, 2, 6, 5, 4, 3, 2, 1};
2253 SaxCountdown scp(11);
2254 CHECK_FALSE(json::sax_parse(v, &scp, json::input_format_t::bjdata));
2255 }
2256
2257 SECTION("start_array() in ndarray _ArrayData_")
2258 {
2259 std::vector<uint8_t> const v = {'[', '$', 'U', '#', '[', 'i', 2, 'i', 3, ']', 6, 5, 4, 3, 2, 1};
2260 SaxCountdown scp(13);
2261 CHECK_FALSE(json::sax_parse(v, &scp, json::input_format_t::bjdata));
2262 }
2263 }
2264
2265 SECTION("parsing values")
2266 {
2267 SECTION("strings")
2268 {
2269 // create a single-character string for all number types
2270 std::vector<uint8_t> s_i = {'S', 'i', 1, 'a'};
2271 std::vector<uint8_t> const s_U = {'S', 'U', 1, 'a'};
2272 std::vector<uint8_t> const s_I = {'S', 'I', 1, 0, 'a'};
2273 std::vector<uint8_t> const s_u = {'S', 'u', 1, 0, 'a'};
2274 std::vector<uint8_t> const s_l = {'S', 'l', 1, 0, 0, 0, 'a'};
2275 std::vector<uint8_t> const s_m = {'S', 'm', 1, 0, 0, 0, 'a'};
2276 std::vector<uint8_t> const s_L = {'S', 'L', 1, 0, 0, 0, 0, 0, 0, 0, 'a'};
2277 std::vector<uint8_t> const s_M = {'S', 'M', 1, 0, 0, 0, 0, 0, 0, 0, 'a'};
2278
2279 // check if string is parsed correctly to "a"
2280 CHECK(json::from_bjdata(s_i) == "a");
2281 CHECK(json::from_bjdata(s_U) == "a");
2282 CHECK(json::from_bjdata(s_I) == "a");
2283 CHECK(json::from_bjdata(s_u) == "a");
2284 CHECK(json::from_bjdata(s_l) == "a");
2285 CHECK(json::from_bjdata(s_m) == "a");
2286 CHECK(json::from_bjdata(s_L) == "a");
2287 CHECK(json::from_bjdata(s_M) == "a");
2288
2289 // roundtrip: output should be optimized
2290 CHECK(json::to_bjdata(json::from_bjdata(s_i)) == s_i);
2291 CHECK(json::to_bjdata(json::from_bjdata(s_U)) == s_i);
2292 CHECK(json::to_bjdata(json::from_bjdata(s_I)) == s_i);
2293 CHECK(json::to_bjdata(json::from_bjdata(s_u)) == s_i);
2294 CHECK(json::to_bjdata(json::from_bjdata(s_l)) == s_i);
2295 CHECK(json::to_bjdata(json::from_bjdata(s_m)) == s_i);
2296 CHECK(json::to_bjdata(json::from_bjdata(s_L)) == s_i);
2297 CHECK(json::to_bjdata(json::from_bjdata(s_M)) == s_i);
2298 }
2299
2300 SECTION("number")
2301 {
2302 SECTION("float")
2303 {
2304 // float32
2305 std::vector<uint8_t> const v_d = {'d', 0xd0, 0x0f, 0x49, 0x40};
2306 CHECK(json::from_bjdata(v_d) == 3.14159f);
2307
2308 // float64
2309 std::vector<uint8_t> const v_D = {'D', 0x6e, 0x86, 0x1b, 0xf0, 0xf9, 0x21, 0x09, 0x40};
2310 CHECK(json::from_bjdata(v_D) == 3.14159);
2311
2312 // float32 is serialized as float64 as the library does not support float32
2313 CHECK(json::to_bjdata(json::from_bjdata(v_d)) == json::to_bjdata(3.14159f));
2314 }
2315 }
2316
2317 SECTION("array")
2318 {
2319 SECTION("optimized version (length only)")
2320 {
2321 // create vector with two elements of the same type
2322 std::vector<uint8_t> const v_TU = {'[', '#', 'U', 2, 'T', 'T'};
2323 std::vector<uint8_t> const v_T = {'[', '#', 'i', 2, 'T', 'T'};
2324 std::vector<uint8_t> const v_F = {'[', '#', 'i', 2, 'F', 'F'};
2325 std::vector<uint8_t> const v_Z = {'[', '#', 'i', 2, 'Z', 'Z'};
2326 std::vector<uint8_t> const v_i = {'[', '#', 'i', 2, 'i', 0x7F, 'i', 0x7F};
2327 std::vector<uint8_t> const v_U = {'[', '#', 'i', 2, 'U', 0xFF, 'U', 0xFF};
2328 std::vector<uint8_t> const v_I = {'[', '#', 'i', 2, 'I', 0xFF, 0x7F, 'I', 0xFF, 0x7F};
2329 std::vector<uint8_t> const v_u = {'[', '#', 'i', 2, 'u', 0x0F, 0xA7, 'u', 0x0F, 0xA7};
2330 std::vector<uint8_t> const v_l = {'[', '#', 'i', 2, 'l', 0xFF, 0xFF, 0xFF, 0x7F, 'l', 0xFF, 0xFF, 0xFF, 0x7F};
2331 std::vector<uint8_t> const v_m = {'[', '#', 'i', 2, 'm', 0xFF, 0xC9, 0x9A, 0xBB, 'm', 0xFF, 0xC9, 0x9A, 0xBB};
2332 std::vector<uint8_t> const v_L = {'[', '#', 'i', 2, 'L', 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x7F, 'L', 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x7F};
2333 std::vector<uint8_t> const v_M = {'[', '#', 'i', 2, 'M', 0xFF, 0xFF, 0x63, 0xA7, 0xB3, 0xB6, 0xE0, 0x8D, 'M', 0xFF, 0xFF, 0x63, 0xA7, 0xB3, 0xB6, 0xE0, 0x8D};
2334 std::vector<uint8_t> const v_D = {'[', '#', 'i', 2, 'D', 0x4a, 0xd8, 0x12, 0x4d, 0xfb, 0x21, 0x09, 0x40, 'D', 0x4a, 0xd8, 0x12, 0x4d, 0xfb, 0x21, 0x09, 0x40};
2335 std::vector<uint8_t> const v_S = {'[', '#', 'i', 2, 'S', 'i', 1, 'a', 'S', 'i', 1, 'a'};
2336 std::vector<uint8_t> const v_C = {'[', '#', 'i', 2, 'C', 'a', 'C', 'a'};
2337
2338 // check if vector is parsed correctly
2339 CHECK(json::from_bjdata(v_TU) == json({true, true}));
2340 CHECK(json::from_bjdata(v_T) == json({true, true}));
2341 CHECK(json::from_bjdata(v_F) == json({false, false}));
2342 CHECK(json::from_bjdata(v_Z) == json({nullptr, nullptr}));
2343 CHECK(json::from_bjdata(v_i) == json({127, 127}));
2344 CHECK(json::from_bjdata(v_U) == json({255, 255}));
2345 CHECK(json::from_bjdata(v_I) == json({32767, 32767}));
2346 CHECK(json::from_bjdata(v_u) == json({42767, 42767}));
2347 CHECK(json::from_bjdata(v_l) == json({2147483647, 2147483647}));
2348 CHECK(json::from_bjdata(v_m) == json({3147483647, 3147483647}));
2349 CHECK(json::from_bjdata(v_L) == json({9223372036854775807, 9223372036854775807}));
2350 CHECK(json::from_bjdata(v_M) == json({10223372036854775807ull, 10223372036854775807ull}));
2351 CHECK(json::from_bjdata(v_D) == json({3.1415926, 3.1415926}));
2352 CHECK(json::from_bjdata(v_S) == json({"a", "a"}));
2353 CHECK(json::from_bjdata(v_C) == json({"a", "a"}));
2354
2355 // roundtrip: output should be optimized
2356 CHECK(json::to_bjdata(json::from_bjdata(v_T), true) == v_T);
2357 CHECK(json::to_bjdata(json::from_bjdata(v_F), true) == v_F);
2358 CHECK(json::to_bjdata(json::from_bjdata(v_Z), true) == v_Z);
2359 CHECK(json::to_bjdata(json::from_bjdata(v_i), true) == v_i);
2360 CHECK(json::to_bjdata(json::from_bjdata(v_U), true) == v_U);
2361 CHECK(json::to_bjdata(json::from_bjdata(v_I), true) == v_I);
2362 CHECK(json::to_bjdata(json::from_bjdata(v_u), true) == v_u);
2363 CHECK(json::to_bjdata(json::from_bjdata(v_l), true) == v_l);
2364 CHECK(json::to_bjdata(json::from_bjdata(v_m), true) == v_m);
2365 CHECK(json::to_bjdata(json::from_bjdata(v_L), true) == v_L);
2366 CHECK(json::to_bjdata(json::from_bjdata(v_M), true) == v_M);
2367 CHECK(json::to_bjdata(json::from_bjdata(v_D), true) == v_D);
2368 CHECK(json::to_bjdata(json::from_bjdata(v_S), true) == v_S);
2369 CHECK(json::to_bjdata(json::from_bjdata(v_C), true) == v_S); // char is serialized to string
2370 }
2371
2372 SECTION("optimized version (type and length)")
2373 {
2374 // create vector with two elements of the same type
2375 std::vector<uint8_t> const v_i = {'[', '$', 'i', '#', 'i', 2, 0x7F, 0x7F};
2376 std::vector<uint8_t> const v_U = {'[', '$', 'U', '#', 'i', 2, 0xFF, 0xFF};
2377 std::vector<uint8_t> const v_I = {'[', '$', 'I', '#', 'i', 2, 0xFF, 0x7F, 0xFF, 0x7F};
2378 std::vector<uint8_t> const v_u = {'[', '$', 'u', '#', 'i', 2, 0x0F, 0xA7, 0x0F, 0xA7};
2379 std::vector<uint8_t> const v_l = {'[', '$', 'l', '#', 'i', 2, 0xFF, 0xFF, 0xFF, 0x7F, 0xFF, 0xFF, 0xFF, 0x7F};
2380 std::vector<uint8_t> const v_m = {'[', '$', 'm', '#', 'i', 2, 0xFF, 0xC9, 0x9A, 0xBB, 0xFF, 0xC9, 0x9A, 0xBB};
2381 std::vector<uint8_t> const v_L = {'[', '$', 'L', '#', 'i', 2, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x7F, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x7F};
2382 std::vector<uint8_t> const v_M = {'[', '$', 'M', '#', 'i', 2, 0xFF, 0xFF, 0x63, 0xA7, 0xB3, 0xB6, 0xE0, 0x8D, 0xFF, 0xFF, 0x63, 0xA7, 0xB3, 0xB6, 0xE0, 0x8D};
2383 std::vector<uint8_t> const v_D = {'[', '$', 'D', '#', 'i', 2, 0x4a, 0xd8, 0x12, 0x4d, 0xfb, 0x21, 0x09, 0x40, 0x4a, 0xd8, 0x12, 0x4d, 0xfb, 0x21, 0x09, 0x40};
2384 std::vector<uint8_t> const v_S = {'[', '#', 'i', 2, 'S', 'i', 1, 'a', 'S', 'i', 1, 'a'};
2385 std::vector<uint8_t> const v_C = {'[', '$', 'C', '#', 'i', 2, 'a', 'a'};
2386
2387 // check if vector is parsed correctly
2388 CHECK(json::from_bjdata(v_i) == json({127, 127}));
2389 CHECK(json::from_bjdata(v_U) == json({255, 255}));
2390 CHECK(json::from_bjdata(v_I) == json({32767, 32767}));
2391 CHECK(json::from_bjdata(v_u) == json({42767, 42767}));
2392 CHECK(json::from_bjdata(v_l) == json({2147483647, 2147483647}));
2393 CHECK(json::from_bjdata(v_m) == json({3147483647, 3147483647}));
2394 CHECK(json::from_bjdata(v_L) == json({9223372036854775807, 9223372036854775807}));
2395 CHECK(json::from_bjdata(v_M) == json({10223372036854775807ull, 10223372036854775807ull}));
2396 CHECK(json::from_bjdata(v_D) == json({3.1415926, 3.1415926}));
2397 CHECK(json::from_bjdata(v_S) == json({"a", "a"}));
2398 CHECK(json::from_bjdata(v_C) == json({"a", "a"}));
2399
2400 // roundtrip: output should be optimized
2401 std::vector<uint8_t> const v_empty = {'[', '#', 'i', 0};
2402 CHECK(json::to_bjdata(json::from_bjdata(v_i), true, true) == v_i);
2403 CHECK(json::to_bjdata(json::from_bjdata(v_U), true, true) == v_U);
2404 CHECK(json::to_bjdata(json::from_bjdata(v_I), true, true) == v_I);
2405 CHECK(json::to_bjdata(json::from_bjdata(v_u), true, true) == v_u);
2406 CHECK(json::to_bjdata(json::from_bjdata(v_l), true, true) == v_l);
2407 CHECK(json::to_bjdata(json::from_bjdata(v_m), true, true) == v_m);
2408 CHECK(json::to_bjdata(json::from_bjdata(v_L), true, true) == v_L);
2409 CHECK(json::to_bjdata(json::from_bjdata(v_M), true, true) == v_M);
2410 CHECK(json::to_bjdata(json::from_bjdata(v_D), true, true) == v_D);
2411 CHECK(json::to_bjdata(json::from_bjdata(v_S), true, true) == v_S);
2412 CHECK(json::to_bjdata(json::from_bjdata(v_C), true, true) == v_S); // char is serialized to string
2413 }
2414
2415 SECTION("optimized ndarray (type and vector-size as optimized 1D array)")
2416 {
2417 // create vector with two elements of the same type
2418 std::vector<uint8_t> const v_0 = {'[', '$', 'i', '#', '[', '$', 'i', '#', 'i', 1, 0};
2419 std::vector<uint8_t> const v_1 = {'[', '$', 'i', '#', '[', '$', 'i', '#', 'i', 1, 2, 0x7F, 0x7F};
2420 std::vector<uint8_t> const v_i = {'[', '$', 'i', '#', '[', '$', 'i', '#', 'i', 2, 1, 2, 0x7F, 0x7F};
2421 std::vector<uint8_t> const v_U = {'[', '$', 'U', '#', '[', '$', 'i', '#', 'i', 2, 1, 2, 0xFF, 0xFF};
2422 std::vector<uint8_t> const v_I = {'[', '$', 'I', '#', '[', '$', 'i', '#', 'i', 2, 1, 2, 0xFF, 0x7F, 0xFF, 0x7F};
2423 std::vector<uint8_t> const v_u = {'[', '$', 'u', '#', '[', '$', 'i', '#', 'i', 2, 1, 2, 0x0F, 0xA7, 0x0F, 0xA7};
2424 std::vector<uint8_t> const v_l = {'[', '$', 'l', '#', '[', '$', 'i', '#', 'i', 2, 1, 2, 0xFF, 0xFF, 0xFF, 0x7F, 0xFF, 0xFF, 0xFF, 0x7F};
2425 std::vector<uint8_t> const v_m = {'[', '$', 'm', '#', '[', '$', 'i', '#', 'i', 2, 1, 2, 0xFF, 0xC9, 0x9A, 0xBB, 0xFF, 0xC9, 0x9A, 0xBB};
2426 std::vector<uint8_t> const v_L = {'[', '$', 'L', '#', '[', '$', 'i', '#', 'i', 2, 1, 2, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x7F, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x7F};
2427 std::vector<uint8_t> const v_M = {'[', '$', 'M', '#', '[', '$', 'i', '#', 'i', 2, 1, 2, 0xFF, 0xFF, 0x63, 0xA7, 0xB3, 0xB6, 0xE0, 0x8D, 0xFF, 0xFF, 0x63, 0xA7, 0xB3, 0xB6, 0xE0, 0x8D};
2428 std::vector<uint8_t> const v_D = {'[', '$', 'D', '#', '[', '$', 'i', '#', 'i', 2, 1, 2, 0x4a, 0xd8, 0x12, 0x4d, 0xfb, 0x21, 0x09, 0x40, 0x4a, 0xd8, 0x12, 0x4d, 0xfb, 0x21, 0x09, 0x40};
2429 std::vector<uint8_t> const v_S = {'[', '#', '[', '$', 'i', '#', 'i', 2, 1, 2, 'S', 'i', 1, 'a', 'S', 'i', 1, 'a'};
2430 std::vector<uint8_t> const v_C = {'[', '$', 'C', '#', '[', '$', 'i', '#', 'i', 2, 1, 2, 'a', 'a'};
2431
2432 // check if vector is parsed correctly
2433 CHECK(json::from_bjdata(v_0) == json::array());
2434 CHECK(json::from_bjdata(v_1) == json({127, 127}));
2435 CHECK(json::from_bjdata(v_i) == json({127, 127}));
2436 CHECK(json::from_bjdata(v_U) == json({255, 255}));
2437 CHECK(json::from_bjdata(v_I) == json({32767, 32767}));
2438 CHECK(json::from_bjdata(v_u) == json({42767, 42767}));
2439 CHECK(json::from_bjdata(v_l) == json({2147483647, 2147483647}));
2440 CHECK(json::from_bjdata(v_m) == json({3147483647, 3147483647}));
2441 CHECK(json::from_bjdata(v_L) == json({9223372036854775807, 9223372036854775807}));
2442 CHECK(json::from_bjdata(v_M) == json({10223372036854775807ull, 10223372036854775807ull}));
2443 CHECK(json::from_bjdata(v_D) == json({3.1415926, 3.1415926}));
2444 CHECK(json::from_bjdata(v_S) == json({"a", "a"}));
2445 CHECK(json::from_bjdata(v_C) == json({"a", "a"}));
2446 }
2447
2448 SECTION("optimized ndarray (type and vector-size ndarray with JData annotations)")
2449 {
2450 // create vector with 0, 1, 2 elements of the same type
2451 std::vector<uint8_t> const v_e = {'[', '$', 'U', '#', '[', '$', 'i', '#', 'i', 2, 2, 1, 0xFE, 0xFF};
2452 std::vector<uint8_t> const v_U = {'[', '$', 'U', '#', '[', '$', 'i', '#', 'i', 2, 2, 3, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06};
2453 std::vector<uint8_t> const v_i = {'[', '$', 'i', '#', '[', '$', 'i', '#', 'i', 2, 2, 3, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06};
2454 std::vector<uint8_t> const v_u = {'[', '$', 'u', '#', '[', '$', 'i', '#', 'i', 2, 2, 3, 0x01, 0x00, 0x02, 0x00, 0x03, 0x00, 0x04, 0x00, 0x05, 0x00, 0x06, 0x00};
2455 std::vector<uint8_t> const v_I = {'[', '$', 'I', '#', '[', '$', 'i', '#', 'i', 2, 2, 3, 0x01, 0x00, 0x02, 0x00, 0x03, 0x00, 0x04, 0x00, 0x05, 0x00, 0x06, 0x00};
2456 std::vector<uint8_t> const v_m = {'[', '$', 'm', '#', '[', '$', 'i', '#', 'i', 2, 2, 3, 0x01, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00};
2457 std::vector<uint8_t> const v_l = {'[', '$', 'l', '#', '[', '$', 'i', '#', 'i', 2, 2, 3, 0x01, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00};
2458 std::vector<uint8_t> const v_M = {'[', '$', 'M', '#', '[', '$', 'i', '#', 'i', 2, 2, 3, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00};
2459 std::vector<uint8_t> const v_L = {'[', '$', 'L', '#', '[', '$', 'i', '#', 'i', 2, 2, 3, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00};
2460 std::vector<uint8_t> const v_d = {'[', '$', 'd', '#', '[', '$', 'i', '#', 'i', 2, 2, 3, 0x00, 0x00, 0x80, 0x3F, 0x00, 0x00, 0x00, 0x40, 0x00, 0x00, 0x40, 0x40, 0x00, 0x00, 0x80, 0x40, 0x00, 0x00, 0xA0, 0x40, 0x00, 0x00, 0xC0, 0x40};
2461 std::vector<uint8_t> const v_D = {'[', '$', 'D', '#', '[', '$', 'i', '#', 'i', 2, 2, 3, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xF0, 0x3F, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x08, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x14, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x40};
2462 std::vector<uint8_t> const v_C = {'[', '$', 'C', '#', '[', '$', 'i', '#', 'i', 2, 2, 3, 'a', 'b', 'c', 'd', 'e', 'f'};
2463
2464 // check if vector is parsed correctly
2465 CHECK(json::from_bjdata(v_e) == json({{"_ArrayData_", {254, 255}}, {"_ArraySize_", {2, 1}}, {"_ArrayType_", "uint8"}}));
2466 CHECK(json::from_bjdata(v_U) == json({{"_ArrayData_", {1, 2, 3, 4, 5, 6}}, {"_ArraySize_", {2, 3}}, {"_ArrayType_", "uint8"}}));
2467 CHECK(json::from_bjdata(v_i) == json({{"_ArrayData_", {1, 2, 3, 4, 5, 6}}, {"_ArraySize_", {2, 3}}, {"_ArrayType_", "int8"}}));
2468 CHECK(json::from_bjdata(v_i) == json({{"_ArrayData_", {1, 2, 3, 4, 5, 6}}, {"_ArraySize_", {2, 3}}, {"_ArrayType_", "int8"}}));
2469 CHECK(json::from_bjdata(v_u) == json({{"_ArrayData_", {1, 2, 3, 4, 5, 6}}, {"_ArraySize_", {2, 3}}, {"_ArrayType_", "uint16"}}));
2470 CHECK(json::from_bjdata(v_I) == json({{"_ArrayData_", {1, 2, 3, 4, 5, 6}}, {"_ArraySize_", {2, 3}}, {"_ArrayType_", "int16"}}));
2471 CHECK(json::from_bjdata(v_m) == json({{"_ArrayData_", {1, 2, 3, 4, 5, 6}}, {"_ArraySize_", {2, 3}}, {"_ArrayType_", "uint32"}}));
2472 CHECK(json::from_bjdata(v_l) == json({{"_ArrayData_", {1, 2, 3, 4, 5, 6}}, {"_ArraySize_", {2, 3}}, {"_ArrayType_", "int32"}}));
2473 CHECK(json::from_bjdata(v_M) == json({{"_ArrayData_", {1, 2, 3, 4, 5, 6}}, {"_ArraySize_", {2, 3}}, {"_ArrayType_", "uint64"}}));
2474 CHECK(json::from_bjdata(v_L) == json({{"_ArrayData_", {1, 2, 3, 4, 5, 6}}, {"_ArraySize_", {2, 3}}, {"_ArrayType_", "int64"}}));
2475 CHECK(json::from_bjdata(v_d) == json({{"_ArrayData_", {1.f, 2.f, 3.f, 4.f, 5.f, 6.f}}, {"_ArraySize_", {2, 3}}, {"_ArrayType_", "single"}}));
2476 CHECK(json::from_bjdata(v_D) == json({{"_ArrayData_", {1., 2., 3., 4., 5., 6.}}, {"_ArraySize_", {2, 3}}, {"_ArrayType_", "double"}}));
2477 CHECK(json::from_bjdata(v_C) == json({{"_ArrayData_", {'a', 'b', 'c', 'd', 'e', 'f'}}, {"_ArraySize_", {2, 3}}, {"_ArrayType_", "char"}}));
2478
2479 // roundtrip: output should be optimized
2480 CHECK(json::to_bjdata(json::from_bjdata(v_e), true, true) == v_e);
2481 CHECK(json::to_bjdata(json::from_bjdata(v_U), true, true) == v_U);
2482 CHECK(json::to_bjdata(json::from_bjdata(v_i), true, true) == v_i);
2483 CHECK(json::to_bjdata(json::from_bjdata(v_u), true, true) == v_u);
2484 CHECK(json::to_bjdata(json::from_bjdata(v_I), true, true) == v_I);
2485 CHECK(json::to_bjdata(json::from_bjdata(v_m), true, true) == v_m);
2486 CHECK(json::to_bjdata(json::from_bjdata(v_l), true, true) == v_l);
2487 CHECK(json::to_bjdata(json::from_bjdata(v_M), true, true) == v_M);
2488 CHECK(json::to_bjdata(json::from_bjdata(v_L), true, true) == v_L);
2489 CHECK(json::to_bjdata(json::from_bjdata(v_d), true, true) == v_d);
2490 CHECK(json::to_bjdata(json::from_bjdata(v_D), true, true) == v_D);
2491 CHECK(json::to_bjdata(json::from_bjdata(v_C), true, true) == v_C);
2492 }
2493
2494 SECTION("optimized ndarray (type and vector-size as 1D array)")
2495 {
2496 // create vector with two elements of the same type
2497 std::vector<uint8_t> const v_0 = {'[', '$', 'i', '#', '[', ']'};
2498 std::vector<uint8_t> const v_E = {'[', '$', 'i', '#', '[', 'i', 2, 'i', 0, ']'};
2499 std::vector<uint8_t> const v_i = {'[', '$', 'i', '#', '[', 'i', 1, 'i', 2, ']', 0x7F, 0x7F};
2500 std::vector<uint8_t> const v_U = {'[', '$', 'U', '#', '[', 'i', 1, 'i', 2, ']', 0xFF, 0xFF};
2501 std::vector<uint8_t> const v_I = {'[', '$', 'I', '#', '[', 'i', 1, 'i', 2, ']', 0xFF, 0x7F, 0xFF, 0x7F};
2502 std::vector<uint8_t> const v_u = {'[', '$', 'u', '#', '[', 'i', 1, 'i', 2, ']', 0x0F, 0xA7, 0x0F, 0xA7};
2503 std::vector<uint8_t> const v_l = {'[', '$', 'l', '#', '[', 'i', 1, 'i', 2, ']', 0xFF, 0xFF, 0xFF, 0x7F, 0xFF, 0xFF, 0xFF, 0x7F};
2504 std::vector<uint8_t> const v_m = {'[', '$', 'm', '#', '[', 'i', 1, 'i', 2, ']', 0xFF, 0xC9, 0x9A, 0xBB, 0xFF, 0xC9, 0x9A, 0xBB};
2505 std::vector<uint8_t> const v_L = {'[', '$', 'L', '#', '[', 'i', 1, 'i', 2, ']', 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x7F, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x7F};
2506 std::vector<uint8_t> const v_M = {'[', '$', 'M', '#', '[', 'i', 1, 'i', 2, ']', 0xFF, 0xFF, 0x63, 0xA7, 0xB3, 0xB6, 0xE0, 0x8D, 0xFF, 0xFF, 0x63, 0xA7, 0xB3, 0xB6, 0xE0, 0x8D};
2507 std::vector<uint8_t> const v_D = {'[', '$', 'D', '#', '[', 'i', 1, 'i', 2, ']', 0x4a, 0xd8, 0x12, 0x4d, 0xfb, 0x21, 0x09, 0x40, 0x4a, 0xd8, 0x12, 0x4d, 0xfb, 0x21, 0x09, 0x40};
2508 std::vector<uint8_t> const v_S = {'[', '#', '[', 'i', 1, 'i', 2, ']', 'S', 'i', 1, 'a', 'S', 'i', 1, 'a'};
2509 std::vector<uint8_t> const v_C = {'[', '$', 'C', '#', '[', 'i', 1, 'i', 2, ']', 'a', 'a'};
2510 std::vector<uint8_t> const v_R = {'[', '#', '[', 'i', 2, ']', 'i', 6, 'U', 7};
2511
2512 // check if vector is parsed correctly
2513 CHECK(json::from_bjdata(v_0) == json::array());
2514 CHECK(json::from_bjdata(v_E) == json::array());
2515 CHECK(json::from_bjdata(v_i) == json({127, 127}));
2516 CHECK(json::from_bjdata(v_U) == json({255, 255}));
2517 CHECK(json::from_bjdata(v_I) == json({32767, 32767}));
2518 CHECK(json::from_bjdata(v_u) == json({42767, 42767}));
2519 CHECK(json::from_bjdata(v_l) == json({2147483647, 2147483647}));
2520 CHECK(json::from_bjdata(v_m) == json({3147483647, 3147483647}));
2521 CHECK(json::from_bjdata(v_L) == json({9223372036854775807, 9223372036854775807}));
2522 CHECK(json::from_bjdata(v_M) == json({10223372036854775807ull, 10223372036854775807ull}));
2523 CHECK(json::from_bjdata(v_D) == json({3.1415926, 3.1415926}));
2524 CHECK(json::from_bjdata(v_S) == json({"a", "a"}));
2525 CHECK(json::from_bjdata(v_C) == json({"a", "a"}));
2526 CHECK(json::from_bjdata(v_R) == json({6, 7}));
2527 }
2528
2529 SECTION("optimized ndarray (type and vector-size as size-optimized array)")
2530 {
2531 // create vector with two elements of the same type
2532 std::vector<uint8_t> const v_i = {'[', '$', 'i', '#', '[', '#', 'i', 2, 'i', 1, 'i', 2, 0x7F, 0x7F};
2533 std::vector<uint8_t> const v_U = {'[', '$', 'U', '#', '[', '#', 'i', 2, 'i', 1, 'i', 2, 0xFF, 0xFF};
2534 std::vector<uint8_t> const v_I = {'[', '$', 'I', '#', '[', '#', 'i', 2, 'i', 1, 'i', 2, 0xFF, 0x7F, 0xFF, 0x7F};
2535 std::vector<uint8_t> const v_u = {'[', '$', 'u', '#', '[', '#', 'i', 2, 'i', 1, 'i', 2, 0x0F, 0xA7, 0x0F, 0xA7};
2536 std::vector<uint8_t> const v_l = {'[', '$', 'l', '#', '[', '#', 'i', 2, 'i', 1, 'i', 2, 0xFF, 0xFF, 0xFF, 0x7F, 0xFF, 0xFF, 0xFF, 0x7F};
2537 std::vector<uint8_t> const v_m = {'[', '$', 'm', '#', '[', '#', 'i', 2, 'i', 1, 'i', 2, 0xFF, 0xC9, 0x9A, 0xBB, 0xFF, 0xC9, 0x9A, 0xBB};
2538 std::vector<uint8_t> const v_L = {'[', '$', 'L', '#', '[', '#', 'i', 2, 'i', 1, 'i', 2, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x7F, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x7F};
2539 std::vector<uint8_t> const v_M = {'[', '$', 'M', '#', '[', '#', 'i', 2, 'i', 1, 'i', 2, 0xFF, 0xFF, 0x63, 0xA7, 0xB3, 0xB6, 0xE0, 0x8D, 0xFF, 0xFF, 0x63, 0xA7, 0xB3, 0xB6, 0xE0, 0x8D};
2540 std::vector<uint8_t> const v_D = {'[', '$', 'D', '#', '[', '#', 'i', 2, 'i', 1, 'i', 2, 0x4a, 0xd8, 0x12, 0x4d, 0xfb, 0x21, 0x09, 0x40, 0x4a, 0xd8, 0x12, 0x4d, 0xfb, 0x21, 0x09, 0x40};
2541 std::vector<uint8_t> const v_S = {'[', '#', '[', '#', 'i', 2, 'i', 1, 'i', 2, 'S', 'i', 1, 'a', 'S', 'i', 1, 'a'};
2542 std::vector<uint8_t> const v_C = {'[', '$', 'C', '#', '[', '#', 'i', 2, 'i', 1, 'i', 2, 'a', 'a'};
2543
2544 // check if vector is parsed correctly
2545 CHECK(json::from_bjdata(v_i) == json({127, 127}));
2546 CHECK(json::from_bjdata(v_U) == json({255, 255}));
2547 CHECK(json::from_bjdata(v_I) == json({32767, 32767}));
2548 CHECK(json::from_bjdata(v_u) == json({42767, 42767}));
2549 CHECK(json::from_bjdata(v_l) == json({2147483647, 2147483647}));
2550 CHECK(json::from_bjdata(v_m) == json({3147483647, 3147483647}));
2551 CHECK(json::from_bjdata(v_L) == json({9223372036854775807, 9223372036854775807}));
2552 CHECK(json::from_bjdata(v_M) == json({10223372036854775807ull, 10223372036854775807ull}));
2553 CHECK(json::from_bjdata(v_D) == json({3.1415926, 3.1415926}));
2554 CHECK(json::from_bjdata(v_S) == json({"a", "a"}));
2555 CHECK(json::from_bjdata(v_C) == json({"a", "a"}));
2556 }
2557
2558 SECTION("invalid ndarray annotations remains as object")
2559 {
2560 // check if invalid ND array annotations stay as object
2561 json j_type = json({{"_ArrayData_", {1, 2, 3, 4, 5, 6}}, {"_ArraySize_", {2, 3}}, {"_ArrayType_", "invalidtype"}});
2562 json j_size = json({{"_ArrayData_", {1, 2, 3, 4, 5}}, {"_ArraySize_", {2, 3}}, {"_ArrayType_", "uint8"}});
2563
2564 // roundtrip: output should stay as object
2565 CHECK(json::from_bjdata(json::to_bjdata(j_type), true, true) == j_type);
2566 CHECK(json::from_bjdata(json::to_bjdata(j_size), true, true) == j_size);
2567 }
2568 }
2569 }
2570
2571 SECTION("parse errors")
2572 {
2573 SECTION("empty byte vector")
2574 {
2575 json _;
2576 CHECK_THROWS_WITH_AS(_ = json::from_bjdata(std::vector<uint8_t>()),
2577 "[json.exception.parse_error.110] parse error at byte 1: syntax error while parsing BJData value: unexpected end of input", json::parse_error&);
2578 }
2579
2580 SECTION("char")
2581 {
2582 SECTION("eof after C byte")
2583 {
2584 std::vector<uint8_t> const v = {'C'};
2585 json _;
2586 CHECK_THROWS_WITH_AS(_ = json::from_bjdata(v), "[json.exception.parse_error.110] parse error at byte 2: syntax error while parsing BJData char: unexpected end of input", json::parse_error&);
2587 }
2588
2589 SECTION("byte out of range")
2590 {
2591 std::vector<uint8_t> const v = {'C', 130};
2592 json _;
2593 CHECK_THROWS_WITH(_ = json::from_bjdata(v), "[json.exception.parse_error.113] parse error at byte 2: syntax error while parsing BJData char: byte after 'C' must be in range 0x00..0x7F; last byte: 0x82");
2594 }
2595 }
2596
2597 SECTION("strings")
2598 {
2599 SECTION("eof after S byte")
2600 {
2601 std::vector<uint8_t> const v = {'S'};
2602 json _;
2603 CHECK_THROWS_WITH_AS(_ = json::from_bjdata(v), "[json.exception.parse_error.110] parse error at byte 2: syntax error while parsing BJData value: unexpected end of input", json::parse_error&);
2604 }
2605
2606 SECTION("invalid byte")
2607 {
2608 std::vector<uint8_t> const v = {'S', '1', 'a'};
2609 json _;
2610 CHECK_THROWS_WITH_AS(_ = json::from_bjdata(v), "[json.exception.parse_error.113] parse error at byte 2: syntax error while parsing BJData string: expected length type specification (U, i, u, I, m, l, M, L); last byte: 0x31", json::parse_error&);
2611 }
2612
2613 SECTION("parse bjdata markers in ubjson")
2614 {
2615 // create a single-character string for all number types
2616 std::vector<uint8_t> const s_u = {'S', 'u', 1, 0, 'a'};
2617 std::vector<uint8_t> const s_m = {'S', 'm', 1, 0, 0, 0, 'a'};
2618 std::vector<uint8_t> const s_M = {'S', 'M', 1, 0, 0, 0, 0, 0, 0, 0, 'a'};
2619
2620 json _;
2621 // check if string is parsed correctly to "a"
2622 CHECK_THROWS_WITH_AS(_ = json::from_ubjson(s_u), "[json.exception.parse_error.113] parse error at byte 2: syntax error while parsing UBJSON string: expected length type specification (U, i, I, l, L); last byte: 0x75", json::parse_error&);
2623 CHECK_THROWS_WITH_AS(_ = json::from_ubjson(s_m), "[json.exception.parse_error.113] parse error at byte 2: syntax error while parsing UBJSON string: expected length type specification (U, i, I, l, L); last byte: 0x6D", json::parse_error&);
2624 CHECK_THROWS_WITH_AS(_ = json::from_ubjson(s_M), "[json.exception.parse_error.113] parse error at byte 2: syntax error while parsing UBJSON string: expected length type specification (U, i, I, l, L); last byte: 0x4D", json::parse_error&);
2625 }
2626 }
2627
2628 SECTION("array")
2629 {
2630 SECTION("optimized array: no size following type")
2631 {
2632 std::vector<uint8_t> const v = {'[', '$', 'i', 2};
2633 json _;
2634 CHECK_THROWS_WITH_AS(_ = json::from_bjdata(v), "[json.exception.parse_error.112] parse error at byte 4: syntax error while parsing BJData size: expected '#' after type information; last byte: 0x02", json::parse_error&);
2635 }
2636
2637 SECTION("optimized array: negative size")
2638 {
2639 std::vector<uint8_t> const v1 = {'[', '#', 'i', 0xF1};
2640 std::vector<uint8_t> const v2 = {'[', '$', 'I', '#', 'i', 0xF2};
2641 std::vector<uint8_t> const v3 = {'[', '$', 'I', '#', '[', 'i', 0xF4, 'i', 0x02, ']'};
2642 std::vector<uint8_t> const v4 = {'[', '$', 0xF6, '#', 'i', 0xF7};
2643 std::vector<uint8_t> const v5 = {'[', '$', 'I', '#', '[', 'i', 0xF5, 'i', 0xF1, ']'};
2644 std::vector<uint8_t> const v6 = {'[', '#', '[', 'i', 0xF3, 'i', 0x02, ']'};
2645
2646 std::vector<uint8_t> const vI = {'[', '#', 'I', 0x00, 0xF1};
2647 std::vector<uint8_t> const vl = {'[', '#', 'l', 0x00, 0x00, 0x00, 0xF2};
2648 std::vector<uint8_t> const vL = {'[', '#', 'L', 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xF3};
2649 std::vector<uint8_t> const vM = {'[', '$', 'M', '#', '[', 'I', 0x00, 0x20, 'M', 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x20, 0xFF, ']'};
2650 std::vector<uint8_t> const vMX = {'[', '$', 'U', '#', '[', 'M', 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 'U', 0x01, ']'};
2651
2652 json _;
2653 CHECK_THROWS_WITH_AS(_ = json::from_bjdata(v1), "[json.exception.parse_error.113] parse error at byte 4: syntax error while parsing BJData size: count in an optimized container must be positive", json::parse_error&);
2654 CHECK(json::from_bjdata(v1, true, false).is_discarded());
2655
2656 CHECK_THROWS_WITH_AS(_ = json::from_bjdata(v2), "[json.exception.parse_error.113] parse error at byte 6: syntax error while parsing BJData size: count in an optimized container must be positive", json::parse_error&);
2657 CHECK(json::from_bjdata(v2, true, false).is_discarded());
2658
2659 CHECK_THROWS_WITH_AS(_ = json::from_bjdata(v3), "[json.exception.parse_error.113] parse error at byte 7: syntax error while parsing BJData size: count in an optimized container must be positive", json::parse_error&);
2660 CHECK(json::from_bjdata(v3, true, false).is_discarded());
2661
2662 CHECK_THROWS_WITH_AS(_ = json::from_bjdata(v4), "[json.exception.parse_error.113] parse error at byte 6: syntax error while parsing BJData size: count in an optimized container must be positive", json::parse_error&);
2663 CHECK(json::from_bjdata(v4, true, false).is_discarded());
2664
2665 CHECK_THROWS_WITH_AS(_ = json::from_bjdata(v5), "[json.exception.parse_error.113] parse error at byte 7: syntax error while parsing BJData size: count in an optimized container must be positive", json::parse_error&);
2666 CHECK(json::from_bjdata(v5, true, false).is_discarded());
2667
2668 CHECK_THROWS_WITH_AS(_ = json::from_bjdata(v6), "[json.exception.parse_error.113] parse error at byte 5: syntax error while parsing BJData size: count in an optimized container must be positive", json::parse_error&);
2669 CHECK(json::from_bjdata(v6, true, false).is_discarded());
2670
2671 CHECK_THROWS_WITH_AS(_ = json::from_bjdata(vI), "[json.exception.parse_error.113] parse error at byte 5: syntax error while parsing BJData size: count in an optimized container must be positive", json::parse_error&);
2672 CHECK(json::from_bjdata(vI, true, false).is_discarded());
2673
2674 CHECK_THROWS_WITH_AS(_ = json::from_bjdata(vl), "[json.exception.parse_error.113] parse error at byte 7: syntax error while parsing BJData size: count in an optimized container must be positive", json::parse_error&);
2675 CHECK(json::from_bjdata(vl, true, false).is_discarded());
2676
2677 CHECK_THROWS_WITH_AS(_ = json::from_bjdata(vL), "[json.exception.parse_error.113] parse error at byte 11: syntax error while parsing BJData size: count in an optimized container must be positive", json::parse_error&);
2678 CHECK(json::from_bjdata(vL, true, false).is_discarded());
2679
2680 #if SIZE_MAX != 0xffffffff
2681 CHECK_THROWS_WITH_AS(_ = json::from_bjdata(vM), "[json.exception.out_of_range.408] syntax error while parsing BJData size: excessive ndarray size caused overflow", json::out_of_range&);
2682 #else
2683 CHECK_THROWS_WITH_AS(_ = json::from_bjdata(vM), "[json.exception.out_of_range.408] syntax error while parsing BJData size: integer value overflow", json::out_of_range&);
2684 #endif
2685 CHECK(json::from_bjdata(vM, true, false).is_discarded());
2686
2687 #if SIZE_MAX != 0xffffffff
2688 CHECK_THROWS_WITH_AS(_ = json::from_bjdata(vMX), "[json.exception.out_of_range.408] syntax error while parsing BJData size: excessive ndarray size caused overflow", json::out_of_range&);
2689 #else
2690 CHECK_THROWS_WITH_AS(_ = json::from_bjdata(vMX), "[json.exception.out_of_range.408] syntax error while parsing BJData size: integer value overflow", json::out_of_range&);
2691 #endif
2692 CHECK(json::from_bjdata(vMX, true, false).is_discarded());
2693 }
2694
2695 SECTION("optimized array: integer value overflow")
2696 {
2697 #if SIZE_MAX == 0xffffffff
2698 std::vector<uint8_t> const vL = {'[', '#', 'L', 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7F};
2699 std::vector<uint8_t> const vM = {'[', '$', 'M', '#', '[', 'I', 0x00, 0x20, 'M', 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x20, 0xFF, ']'};
2700
2701 json _;
2702 CHECK_THROWS_WITH_AS(_ = json::from_bjdata(vL), "[json.exception.out_of_range.408] syntax error while parsing BJData size: integer value overflow", json::out_of_range&);
2703 CHECK(json::from_bjdata(vL, true, false).is_discarded());
2704 CHECK_THROWS_WITH_AS(_ = json::from_bjdata(vM), "[json.exception.out_of_range.408] syntax error while parsing BJData size: integer value overflow", json::out_of_range&);
2705 CHECK(json::from_bjdata(vM, true, false).is_discarded());
2706 #endif
2707 }
2708
2709 SECTION("do not accept NTFZ markers in ndarray optimized type (with count)")
2710 {
2711 json _;
2712 std::vector<uint8_t> const v_N = {'[', '$', 'N', '#', '[', '#', 'i', 2, 'i', 1, 'i', 2};
2713 std::vector<uint8_t> const v_T = {'[', '$', 'T', '#', '[', '#', 'i', 2, 'i', 1, 'i', 2};
2714 std::vector<uint8_t> const v_F = {'[', '$', 'F', '#', '[', '#', 'i', 2, 'i', 1, 'i', 2};
2715 std::vector<uint8_t> const v_Z = {'[', '$', 'Z', '#', '[', '#', 'i', 2, 'i', 1, 'i', 2};
2716
2717 CHECK_THROWS_WITH_AS(_ = json::from_bjdata(v_N), "[json.exception.parse_error.112] parse error at byte 3: syntax error while parsing BJData type: marker 0x4E is not a permitted optimized array type", json::parse_error&);
2718 CHECK(json::from_bjdata(v_N, true, false).is_discarded());
2719
2720 CHECK_THROWS_WITH_AS(_ = json::from_bjdata(v_T), "[json.exception.parse_error.112] parse error at byte 3: syntax error while parsing BJData type: marker 0x54 is not a permitted optimized array type", json::parse_error&);
2721 CHECK(json::from_bjdata(v_T, true, false).is_discarded());
2722
2723 CHECK_THROWS_WITH_AS(_ = json::from_bjdata(v_F), "[json.exception.parse_error.112] parse error at byte 3: syntax error while parsing BJData type: marker 0x46 is not a permitted optimized array type", json::parse_error&);
2724 CHECK(json::from_bjdata(v_F, true, false).is_discarded());
2725
2726 CHECK_THROWS_WITH_AS(_ = json::from_bjdata(v_Z), "[json.exception.parse_error.112] parse error at byte 3: syntax error while parsing BJData type: marker 0x5A is not a permitted optimized array type", json::parse_error&);
2727 CHECK(json::from_bjdata(v_Z, true, false).is_discarded());
2728 }
2729
2730 SECTION("do not accept NTFZ markers in ndarray optimized type (without count)")
2731 {
2732 json _;
2733 std::vector<uint8_t> const v_N = {'[', '$', 'N', '#', '[', 'i', 1, 'i', 2, ']'};
2734 std::vector<uint8_t> const v_T = {'[', '$', 'T', '#', '[', 'i', 1, 'i', 2, ']'};
2735 std::vector<uint8_t> const v_F = {'[', '$', 'F', '#', '[', 'i', 1, 'i', 2, ']'};
2736 std::vector<uint8_t> const v_Z = {'[', '$', 'Z', '#', '[', 'i', 1, 'i', 2, ']'};
2737
2738 CHECK_THROWS_WITH_AS(_ = json::from_bjdata(v_N), "[json.exception.parse_error.112] parse error at byte 3: syntax error while parsing BJData type: marker 0x4E is not a permitted optimized array type", json::parse_error&);
2739 CHECK(json::from_bjdata(v_N, true, false).is_discarded());
2740
2741 CHECK_THROWS_WITH_AS(_ = json::from_bjdata(v_T), "[json.exception.parse_error.112] parse error at byte 3: syntax error while parsing BJData type: marker 0x54 is not a permitted optimized array type", json::parse_error&);
2742 CHECK(json::from_bjdata(v_T, true, false).is_discarded());
2743
2744 CHECK_THROWS_WITH_AS(_ = json::from_bjdata(v_F), "[json.exception.parse_error.112] parse error at byte 3: syntax error while parsing BJData type: marker 0x46 is not a permitted optimized array type", json::parse_error&);
2745 CHECK(json::from_bjdata(v_F, true, false).is_discarded());
2746
2747 CHECK_THROWS_WITH_AS(_ = json::from_bjdata(v_Z), "[json.exception.parse_error.112] parse error at byte 3: syntax error while parsing BJData type: marker 0x5A is not a permitted optimized array type", json::parse_error&);
2748 CHECK(json::from_bjdata(v_Z, true, false).is_discarded());
2749 }
2750 }
2751
2752 SECTION("strings")
2753 {
2754 std::vector<uint8_t> const vS = {'S'};
2755 json _;
2756 CHECK_THROWS_WITH_AS(_ = json::from_bjdata(vS), "[json.exception.parse_error.110] parse error at byte 2: syntax error while parsing BJData value: unexpected end of input", json::parse_error&);
2757 CHECK(json::from_bjdata(vS, true, false).is_discarded());
2758
2759 std::vector<uint8_t> const v = {'S', 'i', '2', 'a'};
2760 CHECK_THROWS_WITH_AS(_ = json::from_bjdata(v), "[json.exception.parse_error.110] parse error at byte 5: syntax error while parsing BJData string: unexpected end of input", json::parse_error&);
2761 CHECK(json::from_bjdata(v, true, false).is_discarded());
2762
2763 std::vector<uint8_t> const vC = {'C'};
2764 CHECK_THROWS_WITH_AS(_ = json::from_bjdata(vC), "[json.exception.parse_error.110] parse error at byte 2: syntax error while parsing BJData char: unexpected end of input", json::parse_error&);
2765 CHECK(json::from_bjdata(vC, true, false).is_discarded());
2766 }
2767
2768 SECTION("sizes")
2769 {
2770 std::vector<uint8_t> const vU = {'[', '#', 'U'};
2771 json _;
2772 CHECK_THROWS_WITH_AS(_ = json::from_bjdata(vU), "[json.exception.parse_error.110] parse error at byte 4: syntax error while parsing BJData number: unexpected end of input", json::parse_error&);
2773 CHECK(json::from_bjdata(vU, true, false).is_discarded());
2774
2775 std::vector<uint8_t> const vi = {'[', '#', 'i'};
2776 CHECK_THROWS_WITH_AS(_ = json::from_bjdata(vi), "[json.exception.parse_error.110] parse error at byte 4: syntax error while parsing BJData number: unexpected end of input", json::parse_error&);
2777 CHECK(json::from_bjdata(vi, true, false).is_discarded());
2778
2779 std::vector<uint8_t> const vI = {'[', '#', 'I'};
2780 CHECK_THROWS_WITH_AS(_ = json::from_bjdata(vI), "[json.exception.parse_error.110] parse error at byte 4: syntax error while parsing BJData number: unexpected end of input", json::parse_error&);
2781 CHECK(json::from_bjdata(vI, true, false).is_discarded());
2782
2783 std::vector<uint8_t> const vu = {'[', '#', 'u'};
2784 CHECK_THROWS_WITH_AS(_ = json::from_bjdata(vu), "[json.exception.parse_error.110] parse error at byte 4: syntax error while parsing BJData number: unexpected end of input", json::parse_error&);
2785 CHECK(json::from_bjdata(vu, true, false).is_discarded());
2786
2787 std::vector<uint8_t> const vl = {'[', '#', 'l'};
2788 CHECK_THROWS_WITH_AS(_ = json::from_bjdata(vl), "[json.exception.parse_error.110] parse error at byte 4: syntax error while parsing BJData number: unexpected end of input", json::parse_error&);
2789 CHECK(json::from_bjdata(vl, true, false).is_discarded());
2790
2791 std::vector<uint8_t> const vm = {'[', '#', 'm'};
2792 CHECK_THROWS_WITH_AS(_ = json::from_bjdata(vm), "[json.exception.parse_error.110] parse error at byte 4: syntax error while parsing BJData number: unexpected end of input", json::parse_error&);
2793 CHECK(json::from_bjdata(vm, true, false).is_discarded());
2794
2795 std::vector<uint8_t> const vL = {'[', '#', 'L'};
2796 CHECK_THROWS_WITH_AS(_ = json::from_bjdata(vL), "[json.exception.parse_error.110] parse error at byte 4: syntax error while parsing BJData number: unexpected end of input", json::parse_error&);
2797 CHECK(json::from_bjdata(vL, true, false).is_discarded());
2798
2799 std::vector<uint8_t> const vM = {'[', '#', 'M'};
2800 CHECK_THROWS_WITH_AS(_ = json::from_bjdata(vM), "[json.exception.parse_error.110] parse error at byte 4: syntax error while parsing BJData number: unexpected end of input", json::parse_error&);
2801 CHECK(json::from_bjdata(vM, true, false).is_discarded());
2802
2803 std::vector<uint8_t> const v0 = {'[', '#', 'T', ']'};
2804 CHECK_THROWS_WITH(_ = json::from_bjdata(v0), "[json.exception.parse_error.113] parse error at byte 3: syntax error while parsing BJData size: expected length type specification (U, i, u, I, m, l, M, L) after '#'; last byte: 0x54");
2805 CHECK(json::from_bjdata(v0, true, false).is_discarded());
2806 }
2807
2808 SECTION("parse bjdata markers as array size in ubjson")
2809 {
2810 json _;
2811 std::vector<uint8_t> const vu = {'[', '#', 'u'};
2812 CHECK_THROWS_WITH_AS(_ = json::from_ubjson(vu), "[json.exception.parse_error.113] parse error at byte 3: syntax error while parsing UBJSON size: expected length type specification (U, i, I, l, L) after '#'; last byte: 0x75", json::parse_error&);
2813 CHECK(json::from_ubjson(vu, true, false).is_discarded());
2814
2815 std::vector<uint8_t> const vm = {'[', '#', 'm'};
2816 CHECK_THROWS_WITH_AS(_ = json::from_ubjson(vm), "[json.exception.parse_error.113] parse error at byte 3: syntax error while parsing UBJSON size: expected length type specification (U, i, I, l, L) after '#'; last byte: 0x6D", json::parse_error&);
2817 CHECK(json::from_ubjson(vm, true, false).is_discarded());
2818
2819 std::vector<uint8_t> const vM = {'[', '#', 'M'};
2820 CHECK_THROWS_WITH_AS(_ = json::from_ubjson(vM), "[json.exception.parse_error.113] parse error at byte 3: syntax error while parsing UBJSON size: expected length type specification (U, i, I, l, L) after '#'; last byte: 0x4D", json::parse_error&);
2821 CHECK(json::from_ubjson(vM, true, false).is_discarded());
2822
2823 std::vector<uint8_t> const v0 = {'[', '#', '['};
2824 CHECK_THROWS_WITH_AS(_ = json::from_ubjson(v0), "[json.exception.parse_error.113] parse error at byte 3: syntax error while parsing UBJSON size: expected length type specification (U, i, I, l, L) after '#'; last byte: 0x5B", json::parse_error&);
2825 CHECK(json::from_ubjson(v0, true, false).is_discarded());
2826 }
2827
2828 SECTION("types")
2829 {
2830 std::vector<uint8_t> const v0 = {'[', '$'};
2831 json _;
2832 CHECK_THROWS_WITH_AS(_ = json::from_bjdata(v0), "[json.exception.parse_error.110] parse error at byte 3: syntax error while parsing BJData type: unexpected end of input", json::parse_error&);
2833 CHECK(json::from_bjdata(v0, true, false).is_discarded());
2834
2835 std::vector<uint8_t> const vi = {'[', '$', '#'};
2836 CHECK_THROWS_WITH_AS(_ = json::from_bjdata(vi), "[json.exception.parse_error.110] parse error at byte 4: syntax error while parsing BJData value: unexpected end of input", json::parse_error&);
2837 CHECK(json::from_bjdata(vi, true, false).is_discarded());
2838
2839 std::vector<uint8_t> const vU = {'[', '$', 'U'};
2840 CHECK_THROWS_WITH_AS(_ = json::from_bjdata(vU), "[json.exception.parse_error.110] parse error at byte 4: syntax error while parsing BJData value: unexpected end of input", json::parse_error&);
2841 CHECK(json::from_bjdata(vU, true, false).is_discarded());
2842
2843 std::vector<uint8_t> const v1 = {'[', '$', '['};
2844 CHECK_THROWS_WITH_AS(_ = json::from_bjdata(v1), "[json.exception.parse_error.112] parse error at byte 3: syntax error while parsing BJData type: marker 0x5B is not a permitted optimized array type", json::parse_error&);
2845 CHECK(json::from_bjdata(v1, true, false).is_discarded());
2846 }
2847
2848 SECTION("arrays")
2849 {
2850 std::vector<uint8_t> const vST = {'[', '$', 'i', '#', 'i', 2, 1};
2851 json _;
2852 CHECK_THROWS_WITH_AS(_ = json::from_bjdata(vST), "[json.exception.parse_error.110] parse error at byte 8: syntax error while parsing BJData number: unexpected end of input", json::parse_error&);
2853 CHECK(json::from_bjdata(vST, true, false).is_discarded());
2854
2855 std::vector<uint8_t> const vS = {'[', '#', 'i', 2, 'i', 1};
2856 CHECK_THROWS_WITH_AS(_ = json::from_bjdata(vS), "[json.exception.parse_error.110] parse error at byte 7: syntax error while parsing BJData value: unexpected end of input", json::parse_error&);
2857 CHECK(json::from_bjdata(vS, true, false).is_discarded());
2858
2859 std::vector<uint8_t> const v = {'[', 'i', 2, 'i', 1};
2860 CHECK_THROWS_WITH_AS(_ = json::from_bjdata(v), "[json.exception.parse_error.110] parse error at byte 6: syntax error while parsing BJData value: unexpected end of input", json::parse_error&);
2861 CHECK(json::from_bjdata(v, true, false).is_discarded());
2862 }
2863
2864 SECTION("ndarrays")
2865 {
2866 std::vector<uint8_t> const vST = {'[', '$', 'i', '#', '[', '$', 'i', '#'};
2867 json _;
2868 CHECK_THROWS_WITH_AS(_ = json::from_bjdata(vST), "[json.exception.parse_error.113] parse error at byte 9: syntax error while parsing BJData size: expected length type specification (U, i, u, I, m, l, M, L) after '#'; last byte: 0xFF", json::parse_error&);
2869 CHECK(json::from_bjdata(vST, true, false).is_discarded());
2870
2871 std::vector<uint8_t> const v = {'[', '$', 'i', '#', '[', '$', 'i', '#', 'i', 2, 1, 2};
2872 CHECK_THROWS_WITH_AS(_ = json::from_bjdata(v), "[json.exception.parse_error.110] parse error at byte 13: syntax error while parsing BJData number: unexpected end of input", json::parse_error&);
2873 CHECK(json::from_bjdata(v, true, false).is_discarded());
2874
2875 std::vector<uint8_t> const vS0 = {'[', '$', 'i', '#', '[', '$', 'i', '#', 'i', 2, 1};
2876 CHECK_THROWS_WITH_AS(_ = json::from_bjdata(vS0), "[json.exception.parse_error.110] parse error at byte 12: syntax error while parsing BJData number: unexpected end of input", json::parse_error&);
2877 CHECK(json::from_bjdata(vS0, true, false).is_discarded());
2878
2879 std::vector<uint8_t> const vS = {'[', '$', 'i', '#', '[', '#', 'i', 2, 1, 2, 1};
2880 CHECK_THROWS_WITH_AS(_ = json::from_bjdata(vS), "[json.exception.parse_error.113] parse error at byte 9: syntax error while parsing BJData size: expected length type specification (U, i, u, I, m, l, M, L) after '#'; last byte: 0x01", json::parse_error&);
2881 CHECK(json::from_bjdata(vS, true, false).is_discarded());
2882
2883 std::vector<uint8_t> const vT = {'[', '$', 'i', '#', '[', 'i', 2, 'i'};
2884 CHECK_THROWS_WITH_AS(_ = json::from_bjdata(vT), "[json.exception.parse_error.110] parse error at byte 9: syntax error while parsing BJData number: unexpected end of input", json::parse_error&);
2885 CHECK(json::from_bjdata(vT, true, false).is_discarded());
2886
2887 std::vector<uint8_t> const vT0 = {'[', '$', 'i', '#', '[', 'i'};
2888 CHECK_THROWS_WITH_AS(_ = json::from_bjdata(vT0), "[json.exception.parse_error.110] parse error at byte 7: syntax error while parsing BJData number: unexpected end of input", json::parse_error&);
2889 CHECK(json::from_bjdata(vT0, true, false).is_discarded());
2890
2891 std::vector<uint8_t> const vu = {'[', '$', 'i', '#', '[', '$', 'i', '#', 'u', 1, 0};
2892 CHECK_THROWS_WITH_AS(_ = json::from_bjdata(vu), "[json.exception.parse_error.110] parse error at byte 12: syntax error while parsing BJData number: unexpected end of input", json::parse_error&);
2893 CHECK(json::from_bjdata(vu, true, false).is_discarded());
2894
2895 std::vector<uint8_t> const vm = {'[', '$', 'i', '#', '[', '$', 'i', '#', 'm', 1, 0, 0, 0};
2896 CHECK_THROWS_WITH_AS(_ = json::from_bjdata(vm), "[json.exception.parse_error.110] parse error at byte 14: syntax error while parsing BJData number: unexpected end of input", json::parse_error&);
2897 CHECK(json::from_bjdata(vm, true, false).is_discarded());
2898
2899 std::vector<uint8_t> const vM = {'[', '$', 'i', '#', '[', '$', 'i', '#', 'M', 1, 0, 0, 0, 0, 0, 0, 0};
2900 CHECK_THROWS_WITH_AS(_ = json::from_bjdata(vM), "[json.exception.parse_error.110] parse error at byte 18: syntax error while parsing BJData number: unexpected end of input", json::parse_error&);
2901 CHECK(json::from_bjdata(vM, true, false).is_discarded());
2902
2903 std::vector<uint8_t> const vU = {'[', '$', 'U', '#', '[', '$', 'i', '#', 'i', 2, 2, 3, 1, 2, 3, 4, 5};
2904 CHECK_THROWS_WITH_AS(_ = json::from_bjdata(vU), "[json.exception.parse_error.110] parse error at byte 18: syntax error while parsing BJData number: unexpected end of input", json::parse_error&);
2905 CHECK(json::from_bjdata(vU, true, false).is_discarded());
2906
2907 std::vector<uint8_t> const vT1 = {'[', '$', 'T', '#', '[', '$', 'i', '#', 'i', 2, 2, 3};
2908 CHECK(json::from_bjdata(vT1, true, false).is_discarded());
2909
2910 std::vector<uint8_t> const vh = {'[', '$', 'h', '#', '[', '$', 'i', '#', 'i', 2, 2, 3};
2911 CHECK(json::from_bjdata(vh, true, false).is_discarded());
2912
2913 std::vector<uint8_t> const vR = {'[', '$', 'i', '#', '[', 'i', 1, '[', ']', ']', 1};
2914 CHECK_THROWS_WITH_AS(_ = json::from_bjdata(vR), "[json.exception.parse_error.113] parse error at byte 8: syntax error while parsing BJData size: ndarray dimensional vector is not allowed", json::parse_error&);
2915 CHECK(json::from_bjdata(vR, true, false).is_discarded());
2916
2917 std::vector<uint8_t> const vRo = {'[', '$', 'i', '#', '[', 'i', 0, '{', '}', ']', 1};
2918 CHECK_THROWS_WITH_AS(_ = json::from_bjdata(vRo), "[json.exception.parse_error.113] parse error at byte 8: syntax error while parsing BJData size: expected length type specification (U, i, u, I, m, l, M, L) after '#'; last byte: 0x7B", json::parse_error&);
2919 CHECK(json::from_bjdata(vRo, true, false).is_discarded());
2920
2921 std::vector<uint8_t> const vR1 = {'[', '$', 'i', '#', '[', '[', 'i', 1, ']', ']', 1};
2922 CHECK_THROWS_WITH_AS(_ = json::from_bjdata(vR1), "[json.exception.parse_error.113] parse error at byte 6: syntax error while parsing BJData size: ndarray dimensional vector is not allowed", json::parse_error&);
2923 CHECK(json::from_bjdata(vR1, true, false).is_discarded());
2924
2925 std::vector<uint8_t> const vR2 = {'[', '$', 'i', '#', '[', '#', '[', 'i', 1, ']', ']', 1};
2926 CHECK_THROWS_WITH_AS(_ = json::from_bjdata(vR2), "[json.exception.parse_error.113] parse error at byte 11: syntax error while parsing BJData size: expected length type specification (U, i, u, I, m, l, M, L) after '#'; last byte: 0x5D", json::parse_error&);
2927 CHECK(json::from_bjdata(vR2, true, false).is_discarded());
2928
2929 std::vector<uint8_t> const vR3 = {'[', '#', '[', 'i', '2', 'i', 2, ']'};
2930 CHECK_THROWS_WITH_AS(_ = json::from_bjdata(vR3), "[json.exception.parse_error.112] parse error at byte 8: syntax error while parsing BJData size: ndarray requires both type and size", json::parse_error&);
2931 CHECK(json::from_bjdata(vR3, true, false).is_discarded());
2932
2933 std::vector<uint8_t> const vR4 = {'[', '$', 'i', '#', '[', '$', 'i', '#', '[', 'i', 1, ']', 1};
2934 CHECK_THROWS_WITH_AS(_ = json::from_bjdata(vR4), "[json.exception.parse_error.110] parse error at byte 14: syntax error while parsing BJData number: unexpected end of input", json::parse_error&);
2935 CHECK(json::from_bjdata(vR4, true, false).is_discarded());
2936
2937 std::vector<uint8_t> const vR5 = {'[', '$', 'i', '#', '[', '[', '[', ']', ']', ']'};
2938 CHECK_THROWS_WITH_AS(_ = json::from_bjdata(vR5), "[json.exception.parse_error.113] parse error at byte 6: syntax error while parsing BJData size: ndarray dimensional vector is not allowed", json::parse_error&);
2939 CHECK(json::from_bjdata(vR5, true, false).is_discarded());
2940
2941 std::vector<uint8_t> const vR6 = {'[', '$', 'i', '#', '[', '$', 'i', '#', '[', 'i', '2', 'i', 2, ']'};
2942 CHECK_THROWS_WITH_AS(_ = json::from_bjdata(vR6), "[json.exception.parse_error.112] parse error at byte 14: syntax error while parsing BJData size: ndarray can not be recursive", json::parse_error&);
2943 CHECK(json::from_bjdata(vR6, true, false).is_discarded());
2944
2945 std::vector<uint8_t> const vH = {'[', 'H', '[', '#', '[', '$', 'i', '#', '[', 'i', '2', 'i', 2, ']'};
2946 CHECK_THROWS_WITH_AS(_ = json::from_bjdata(vH), "[json.exception.parse_error.113] parse error at byte 3: syntax error while parsing BJData size: ndarray dimensional vector is not allowed", json::parse_error&);
2947 CHECK(json::from_bjdata(vH, true, false).is_discarded());
2948 }
2949
2950 SECTION("objects")
2951 {
2952 std::vector<uint8_t> const vST = {'{', '$', 'i', '#', 'i', 2, 'i', 1, 'a', 1};
2953 json _;
2954 CHECK_THROWS_WITH_AS(_ = json::from_bjdata(vST), "[json.exception.parse_error.110] parse error at byte 11: syntax error while parsing BJData value: unexpected end of input", json::parse_error&);
2955 CHECK(json::from_bjdata(vST, true, false).is_discarded());
2956
2957 std::vector<uint8_t> const vT = {'{', '$', 'i', 'i', 1, 'a', 1};
2958 CHECK_THROWS_WITH(_ = json::from_bjdata(vT), "[json.exception.parse_error.112] parse error at byte 4: syntax error while parsing BJData size: expected '#' after type information; last byte: 0x69");
2959 CHECK(json::from_bjdata(vT, true, false).is_discarded());
2960
2961 std::vector<uint8_t> const vS = {'{', '#', 'i', 2, 'i', 1, 'a', 'i', 1};
2962 CHECK_THROWS_WITH_AS(_ = json::from_bjdata(vS), "[json.exception.parse_error.110] parse error at byte 10: syntax error while parsing BJData value: unexpected end of input", json::parse_error&);
2963 CHECK(json::from_bjdata(vS, true, false).is_discarded());
2964
2965 std::vector<uint8_t> const v = {'{', 'i', 1, 'a', 'i', 1};
2966 CHECK_THROWS_WITH_AS(_ = json::from_bjdata(v), "[json.exception.parse_error.110] parse error at byte 7: syntax error while parsing BJData value: unexpected end of input", json::parse_error&);
2967 CHECK(json::from_bjdata(v, true, false).is_discarded());
2968
2969 std::vector<uint8_t> const v2 = {'{', 'i', 1, 'a', 'i', 1, 'i'};
2970 CHECK_THROWS_WITH_AS(_ = json::from_bjdata(v2), "[json.exception.parse_error.110] parse error at byte 8: syntax error while parsing BJData number: unexpected end of input", json::parse_error&);
2971 CHECK(json::from_bjdata(v2, true, false).is_discarded());
2972
2973 std::vector<uint8_t> const v3 = {'{', 'i', 1, 'a'};
2974 CHECK_THROWS_WITH_AS(_ = json::from_bjdata(v3), "[json.exception.parse_error.110] parse error at byte 5: syntax error while parsing BJData value: unexpected end of input", json::parse_error&);
2975 CHECK(json::from_bjdata(v3, true, false).is_discarded());
2976
2977 std::vector<uint8_t> const vST1 = {'{', '$', 'd', '#', 'i', 2, 'i', 1, 'a'};
2978 CHECK_THROWS_WITH_AS(_ = json::from_bjdata(vST1), "[json.exception.parse_error.110] parse error at byte 10: syntax error while parsing BJData number: unexpected end of input", json::parse_error&);
2979 CHECK(json::from_bjdata(vST1, true, false).is_discarded());
2980
2981 std::vector<uint8_t> const vST2 = {'{', '#', 'i', 2, 'i', 1, 'a'};
2982 CHECK_THROWS_WITH_AS(_ = json::from_bjdata(vST2), "[json.exception.parse_error.110] parse error at byte 8: syntax error while parsing BJData value: unexpected end of input", json::parse_error&);
2983 CHECK(json::from_bjdata(vST2, true, false).is_discarded());
2984
2985 std::vector<uint8_t> const vO = {'{', '#', '[', 'i', 2, 'i', 1, ']', 'i', 1, 'a', 'i', 1, 'i', 1, 'b', 'i', 2};
2986 CHECK_THROWS_WITH_AS(_ = json::from_bjdata(vO), "[json.exception.parse_error.112] parse error at byte 8: syntax error while parsing BJData size: ndarray requires both type and size", json::parse_error&);
2987 CHECK(json::from_bjdata(vO, true, false).is_discarded());
2988
2989 std::vector<uint8_t> const vO2 = {'{', '$', 'i', '#', '[', 'i', 2, 'i', 1, ']', 'i', 1, 'a', 1, 'i', 1, 'b', 2};
2990 CHECK_THROWS_WITH_AS(_ = json::from_bjdata(vO2), "[json.exception.parse_error.112] parse error at byte 10: syntax error while parsing BJData object: BJData object does not support ND-array size in optimized format", json::parse_error&);
2991 CHECK(json::from_bjdata(vO2, true, false).is_discarded());
2992 }
2993 }
2994
2995 SECTION("writing optimized values")
2996 {
2997 SECTION("integer")
2998 {
2999 SECTION("array of i")
3000 {
3001 json const j = {1, -1};
3002 std::vector<uint8_t> const expected = {'[', '$', 'i', '#', 'i', 2, 1, 0xff};
3003 CHECK(json::to_bjdata(j, true, true) == expected);
3004 }
3005
3006 SECTION("array of U")
3007 {
3008 json const j = {200, 201};
3009 std::vector<uint8_t> const expected = {'[', '$', 'U', '#', 'i', 2, 0xC8, 0xC9};
3010 CHECK(json::to_bjdata(j, true, true) == expected);
3011 }
3012
3013 SECTION("array of I")
3014 {
3015 json const j = {30000, -30000};
3016 std::vector<uint8_t> const expected = {'[', '$', 'I', '#', 'i', 2, 0x30, 0x75, 0xd0, 0x8a};
3017 CHECK(json::to_bjdata(j, true, true) == expected);
3018 }
3019
3020 SECTION("array of u")
3021 {
3022 json const j = {50000, 50001};
3023 std::vector<uint8_t> const expected = {'[', '$', 'u', '#', 'i', 2, 0x50, 0xC3, 0x51, 0xC3};
3024 CHECK(json::to_bjdata(j, true, true) == expected);
3025 }
3026
3027 SECTION("array of l")
3028 {
3029 json const j = {70000, -70000};
3030 std::vector<uint8_t> const expected = {'[', '$', 'l', '#', 'i', 2, 0x70, 0x11, 0x01, 0x00, 0x90, 0xEE, 0xFE, 0xFF};
3031 CHECK(json::to_bjdata(j, true, true) == expected);
3032 }
3033
3034 SECTION("array of m")
3035 {
3036 json const j = {3147483647, 3147483648};
3037 std::vector<uint8_t> const expected = {'[', '$', 'm', '#', 'i', 2, 0xFF, 0xC9, 0x9A, 0xBB, 0x00, 0xCA, 0x9A, 0xBB};
3038 CHECK(json::to_bjdata(j, true, true) == expected);
3039 }
3040
3041 SECTION("array of L")
3042 {
3043 json const j = {5000000000, -5000000000};
3044 std::vector<uint8_t> const expected = {'[', '$', 'L', '#', 'i', 2, 0x00, 0xF2, 0x05, 0x2A, 0x01, 0x00, 0x00, 0x00, 0x00, 0x0E, 0xFA, 0xD5, 0xFE, 0xFF, 0xFF, 0xFF};
3045 CHECK(json::to_bjdata(j, true, true) == expected);
3046 }
3047 }
3048
3049 SECTION("unsigned integer")
3050 {
3051 SECTION("array of i")
3052 {
3053 json const j = {1u, 2u};
3054 std::vector<uint8_t> const expected = {'[', '$', 'i', '#', 'i', 2, 1, 2};
3055 std::vector<uint8_t> const expected_size = {'[', '#', 'i', 2, 'i', 1, 'i', 2};
3056 CHECK(json::to_bjdata(j, true, true) == expected);
3057 CHECK(json::to_bjdata(j, true) == expected_size);
3058 }
3059
3060 SECTION("array of U")
3061 {
3062 json const j = {200u, 201u};
3063 std::vector<uint8_t> const expected = {'[', '$', 'U', '#', 'i', 2, 0xC8, 0xC9};
3064 std::vector<uint8_t> const expected_size = {'[', '#', 'i', 2, 'U', 0xC8, 'U', 0xC9};
3065 CHECK(json::to_bjdata(j, true, true) == expected);
3066 CHECK(json::to_bjdata(j, true) == expected_size);
3067 }
3068
3069 SECTION("array of I")
3070 {
3071 json const j = {30000u, 30001u};
3072 std::vector<uint8_t> const expected = {'[', '$', 'I', '#', 'i', 2, 0x30, 0x75, 0x31, 0x75};
3073 std::vector<uint8_t> const expected_size = {'[', '#', 'i', 2, 'I', 0x30, 0x75, 'I', 0x31, 0x75};
3074 CHECK(json::to_bjdata(j, true, true) == expected);
3075 CHECK(json::to_bjdata(j, true) == expected_size);
3076 }
3077
3078 SECTION("array of u")
3079 {
3080 json const j = {50000u, 50001u};
3081 std::vector<uint8_t> const expected = {'[', '$', 'u', '#', 'i', 2, 0x50, 0xC3, 0x51, 0xC3};
3082 std::vector<uint8_t> const expected_size = {'[', '#', 'i', 2, 'u', 0x50, 0xC3, 'u', 0x51, 0xC3};
3083 CHECK(json::to_bjdata(j, true, true) == expected);
3084 CHECK(json::to_bjdata(j, true) == expected_size);
3085 }
3086
3087 SECTION("array of l")
3088 {
3089 json const j = {70000u, 70001u};
3090 std::vector<uint8_t> const expected = {'[', '$', 'l', '#', 'i', 2, 0x70, 0x11, 0x01, 0x00, 0x71, 0x11, 0x01, 0x00};
3091 std::vector<uint8_t> const expected_size = {'[', '#', 'i', 2, 'l', 0x70, 0x11, 0x01, 0x00, 'l', 0x71, 0x11, 0x01, 0x00};
3092 CHECK(json::to_bjdata(j, true, true) == expected);
3093 CHECK(json::to_bjdata(j, true) == expected_size);
3094 }
3095
3096 SECTION("array of m")
3097 {
3098 json const j = {3147483647u, 3147483648u};
3099 std::vector<uint8_t> const expected = {'[', '$', 'm', '#', 'i', 2, 0xFF, 0xC9, 0x9A, 0xBB, 0x00, 0xCA, 0x9A, 0xBB};
3100 std::vector<uint8_t> const expected_size = {'[', '#', 'i', 2, 'm', 0xFF, 0xC9, 0x9A, 0xBB, 'm', 0x00, 0xCA, 0x9A, 0xBB};
3101 CHECK(json::to_bjdata(j, true, true) == expected);
3102 CHECK(json::to_bjdata(j, true) == expected_size);
3103 }
3104
3105 SECTION("array of L")
3106 {
3107 json const j = {5000000000u, 5000000001u};
3108 std::vector<uint8_t> const expected = {'[', '$', 'L', '#', 'i', 2, 0x00, 0xF2, 0x05, 0x2A, 0x01, 0x00, 0x00, 0x00, 0x01, 0xF2, 0x05, 0x2A, 0x01, 0x00, 0x00, 0x00};
3109 std::vector<uint8_t> const expected_size = {'[', '#', 'i', 2, 'L', 0x00, 0xF2, 0x05, 0x2A, 0x01, 0x00, 0x00, 0x00, 'L', 0x01, 0xF2, 0x05, 0x2A, 0x01, 0x00, 0x00, 0x00};
3110 CHECK(json::to_bjdata(j, true, true) == expected);
3111 CHECK(json::to_bjdata(j, true) == expected_size);
3112 }
3113
3114 SECTION("array of M")
3115 {
3116 json const j = {10223372036854775807ull, 10223372036854775808ull};
3117 std::vector<uint8_t> const expected = {'[', '$', 'M', '#', 'i', 2, 0xFF, 0xFF, 0x63, 0xA7, 0xB3, 0xB6, 0xE0, 0x8D, 0x00, 0x00, 0x64, 0xA7, 0xB3, 0xB6, 0xE0, 0x8D};
3118 std::vector<uint8_t> const expected_size = {'[', '#', 'i', 2, 'M', 0xFF, 0xFF, 0x63, 0xA7, 0xB3, 0xB6, 0xE0, 0x8D, 'M', 0x00, 0x00, 0x64, 0xA7, 0xB3, 0xB6, 0xE0, 0x8D};
3119 CHECK(json::to_bjdata(j, true, true) == expected);
3120 CHECK(json::to_bjdata(j, true) == expected_size);
3121 }
3122 }
3123 }
3124 }
3125
3126 TEST_CASE("Universal Binary JSON Specification Examples 1")
3127 {
3128 SECTION("Null Value")
3129 {
3130 json const j = {{"passcode", nullptr}};
3131 std::vector<uint8_t> v = {'{', 'i', 8, 'p', 'a', 's', 's', 'c', 'o', 'd', 'e', 'Z', '}'};
3132 CHECK(json::to_bjdata(j) == v);
3133 CHECK(json::from_bjdata(v) == j);
3134 }
3135
3136 SECTION("No-Op Value")
3137 {
3138 json const j = {"foo", "bar", "baz"};
3139 std::vector<uint8_t> v = {'[', 'S', 'i', 3, 'f', 'o', 'o',
3140 'S', 'i', 3, 'b', 'a', 'r',
3141 'S', 'i', 3, 'b', 'a', 'z', ']'
3142 };
3143 std::vector<uint8_t> const v2 = {'[', 'S', 'i', 3, 'f', 'o', 'o', 'N',
3144 'S', 'i', 3, 'b', 'a', 'r', 'N', 'N', 'N',
3145 'S', 'i', 3, 'b', 'a', 'z', 'N', 'N', ']'
3146 };
3147 CHECK(json::to_bjdata(j) == v);
3148 CHECK(json::from_bjdata(v) == j);
3149 CHECK(json::from_bjdata(v2) == j);
3150 }
3151
3152 SECTION("Boolean Types")
3153 {
3154 json const j = {{"authorized", true}, {"verified", false}};
3155 std::vector<uint8_t> v = {'{', 'i', 10, 'a', 'u', 't', 'h', 'o', 'r', 'i', 'z', 'e', 'd', 'T',
3156 'i', 8, 'v', 'e', 'r', 'i', 'f', 'i', 'e', 'd', 'F', '}'
3157 };
3158 CHECK(json::to_bjdata(j) == v);
3159 CHECK(json::from_bjdata(v) == j);
3160 }
3161
3162 SECTION("Numeric Types")
3163 {
3164 json j =
3165 {
3166 {"int8", 16},
3167 {"uint8", 255},
3168 {"int16", 32767},
3169 {"uint16", 42767},
3170 {"int32", 2147483647},
3171 {"uint32", 3147483647},
3172 {"int64", 9223372036854775807},
3173 {"uint64", 10223372036854775807ull},
3174 {"float64", 113243.7863123}
3175 };
3176 std::vector<uint8_t> v = {'{',
3177 'i', 7, 'f', 'l', 'o', 'a', 't', '6', '4', 'D', 0xcf, 0x34, 0xbc, 0x94, 0xbc, 0xa5, 0xfb, 0x40,
3178 'i', 5, 'i', 'n', 't', '1', '6', 'I', 0xff, 0x7f,
3179 'i', 5, 'i', 'n', 't', '3', '2', 'l', 0xff, 0xff, 0xff, 0x7f,
3180 'i', 5, 'i', 'n', 't', '6', '4', 'L', 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x7f,
3181 'i', 4, 'i', 'n', 't', '8', 'i', 16,
3182 'i', 6, 'u', 'i', 'n', 't', '1', '6', 'u', 0x0F, 0xA7,
3183 'i', 6, 'u', 'i', 'n', 't', '3', '2', 'm', 0xFF, 0xC9, 0x9A, 0xBB,
3184 'i', 6, 'u', 'i', 'n', 't', '6', '4', 'M', 0xFF, 0xFF, 0x63, 0xA7, 0xB3, 0xB6, 0xE0, 0x8D,
3185 'i', 5, 'u', 'i', 'n', 't', '8', 'U', 0xff,
3186 '}'
3187 };
3188 CHECK(json::to_bjdata(j) == v);
3189 CHECK(json::from_bjdata(v) == j);
3190 }
3191
3192 SECTION("Char Type")
3193 {
3194 json const j = {{"rolecode", "a"}, {"delim", ";"}};
3195 std::vector<uint8_t> const v = {'{', 'i', 5, 'd', 'e', 'l', 'i', 'm', 'C', ';', 'i', 8, 'r', 'o', 'l', 'e', 'c', 'o', 'd', 'e', 'C', 'a', '}'};
3196 //CHECK(json::to_bjdata(j) == v);
3197 CHECK(json::from_bjdata(v) == j);
3198 }
3199
3200 SECTION("String Type")
3201 {
3202 SECTION("English")
3203 {
3204 json const j = "hello";
3205 std::vector<uint8_t> v = {'S', 'i', 5, 'h', 'e', 'l', 'l', 'o'};
3206 CHECK(json::to_bjdata(j) == v);
3207 CHECK(json::from_bjdata(v) == j);
3208 }
3209
3210 SECTION("Russian")
3211 {
3212 json const j = "привет";
3213 std::vector<uint8_t> v = {'S', 'i', 12, 0xD0, 0xBF, 0xD1, 0x80, 0xD0, 0xB8, 0xD0, 0xB2, 0xD0, 0xB5, 0xD1, 0x82};
3214 CHECK(json::to_bjdata(j) == v);
3215 CHECK(json::from_bjdata(v) == j);
3216 }
3217
3218 SECTION("Russian")
3219 {
3220 json const j = "مرحبا";
3221 std::vector<uint8_t> v = {'S', 'i', 10, 0xD9, 0x85, 0xD8, 0xB1, 0xD8, 0xAD, 0xD8, 0xA8, 0xD8, 0xA7};
3222 CHECK(json::to_bjdata(j) == v);
3223 CHECK(json::from_bjdata(v) == j);
3224 }
3225 }
3226
3227 SECTION("Array Type")
3228 {
3229 SECTION("size=false type=false")
3230 {
3231 // note the float has been replaced by a double
3232 json const j = {nullptr, true, false, 4782345193, 153.132, "ham"};
3233 std::vector<uint8_t> v = {'[', 'Z', 'T', 'F', 'L', 0xE9, 0xCB, 0x0C, 0x1D, 0x01, 0x00, 0x00, 0x00, 'D', 0x4e, 0x62, 0x10, 0x58, 0x39, 0x24, 0x63, 0x40, 'S', 'i', 3, 'h', 'a', 'm', ']'};
3234 CHECK(json::to_bjdata(j) == v);
3235 CHECK(json::from_bjdata(v) == j);
3236 }
3237
3238 SECTION("size=true type=false")
3239 {
3240 // note the float has been replaced by a double
3241 json const j = {nullptr, true, false, 4782345193, 153.132, "ham"};
3242 std::vector<uint8_t> v = {'[', '#', 'i', 6, 'Z', 'T', 'F', 'L', 0xE9, 0xCB, 0x0C, 0x1D, 0x01, 0x00, 0x00, 0x00, 'D', 0x4e, 0x62, 0x10, 0x58, 0x39, 0x24, 0x63, 0x40, 'S', 'i', 3, 'h', 'a', 'm'};
3243 CHECK(json::to_bjdata(j, true) == v);
3244 CHECK(json::from_bjdata(v) == j);
3245 }
3246
3247 SECTION("size=true type=true")
3248 {
3249 // note the float has been replaced by a double
3250 json const j = {nullptr, true, false, 4782345193, 153.132, "ham"};
3251 std::vector<uint8_t> v = {'[', '#', 'i', 6, 'Z', 'T', 'F', 'L', 0xE9, 0xCB, 0x0C, 0x1D, 0x01, 0x00, 0x00, 0x00, 'D', 0x4e, 0x62, 0x10, 0x58, 0x39, 0x24, 0x63, 0x40, 'S', 'i', 3, 'h', 'a', 'm'};
3252 CHECK(json::to_bjdata(j, true, true) == v);
3253 CHECK(json::from_bjdata(v) == j);
3254 }
3255 }
3256
3257 SECTION("Object Type")
3258 {
3259 SECTION("size=false type=false")
3260 {
3261 json j =
3262 {
3263 {
3264 "post", {
3265 {"id", 1137},
3266 {"author", "rkalla"},
3267 {"timestamp", 1364482090592},
3268 {"body", "I totally agree!"}
3269 }
3270 }
3271 };
3272 std::vector<uint8_t> v = {'{', 'i', 4, 'p', 'o', 's', 't', '{',
3273 'i', 6, 'a', 'u', 't', 'h', 'o', 'r', 'S', 'i', 6, 'r', 'k', 'a', 'l', 'l', 'a',
3274 'i', 4, 'b', 'o', 'd', 'y', 'S', 'i', 16, 'I', ' ', 't', 'o', 't', 'a', 'l', 'l', 'y', ' ', 'a', 'g', 'r', 'e', 'e', '!',
3275 'i', 2, 'i', 'd', 'I', 0x71, 0x04,
3276 'i', 9, 't', 'i', 'm', 'e', 's', 't', 'a', 'm', 'p', 'L', 0x60, 0x66, 0x78, 0xB1, 0x3D, 0x01, 0x00, 0x00,
3277 '}', '}'
3278 };
3279 CHECK(json::to_bjdata(j) == v);
3280 CHECK(json::from_bjdata(v) == j);
3281 }
3282
3283 SECTION("size=true type=false")
3284 {
3285 json j =
3286 {
3287 {
3288 "post", {
3289 {"id", 1137},
3290 {"author", "rkalla"},
3291 {"timestamp", 1364482090592},
3292 {"body", "I totally agree!"}
3293 }
3294 }
3295 };
3296 std::vector<uint8_t> v = {'{', '#', 'i', 1, 'i', 4, 'p', 'o', 's', 't', '{', '#', 'i', 4,
3297 'i', 6, 'a', 'u', 't', 'h', 'o', 'r', 'S', 'i', 6, 'r', 'k', 'a', 'l', 'l', 'a',
3298 'i', 4, 'b', 'o', 'd', 'y', 'S', 'i', 16, 'I', ' ', 't', 'o', 't', 'a', 'l', 'l', 'y', ' ', 'a', 'g', 'r', 'e', 'e', '!',
3299 'i', 2, 'i', 'd', 'I', 0x71, 0x04,
3300 'i', 9, 't', 'i', 'm', 'e', 's', 't', 'a', 'm', 'p', 'L', 0x60, 0x66, 0x78, 0xB1, 0x3D, 0x01, 0x00, 0x00,
3301 };
3302 CHECK(json::to_bjdata(j, true) == v);
3303 CHECK(json::from_bjdata(v) == j);
3304 }
3305
3306 SECTION("size=true type=true")
3307 {
3308 json j =
3309 {
3310 {
3311 "post", {
3312 {"id", 1137},
3313 {"author", "rkalla"},
3314 {"timestamp", 1364482090592},
3315 {"body", "I totally agree!"}
3316 }
3317 }
3318 };
3319 std::vector<uint8_t> v = {'{', '#', 'i', 1, 'i', 4, 'p', 'o', 's', 't', '{', '#', 'i', 4,
3320 'i', 6, 'a', 'u', 't', 'h', 'o', 'r', 'S', 'i', 6, 'r', 'k', 'a', 'l', 'l', 'a',
3321 'i', 4, 'b', 'o', 'd', 'y', 'S', 'i', 16, 'I', ' ', 't', 'o', 't', 'a', 'l', 'l', 'y', ' ', 'a', 'g', 'r', 'e', 'e', '!',
3322 'i', 2, 'i', 'd', 'I', 0x71, 0x04,
3323 'i', 9, 't', 'i', 'm', 'e', 's', 't', 'a', 'm', 'p', 'L', 0x60, 0x66, 0x78, 0xB1, 0x3D, 0x01, 0x00, 0x00,
3324 };
3325 CHECK(json::to_bjdata(j, true, true) == v);
3326 CHECK(json::from_bjdata(v) == j);
3327 }
3328 }
3329
3330 SECTION("Optimized Format")
3331 {
3332 SECTION("Array Example")
3333 {
3334 SECTION("No Optimization")
3335 {
3336 // note the floats have been replaced by doubles
3337 json const j = {29.97, 31.13, 67.0, 2.113, 23.888};
3338 std::vector<uint8_t> v = {'[',
3339 'D', 0xb8, 0x1e, 0x85, 0xeb, 0x51, 0xf8, 0x3d, 0x40,
3340 'D', 0xe1, 0x7a, 0x14, 0xae, 0x47, 0x21, 0x3f, 0x40,
3341 'D', 0x00, 0x00, 0x00, 0x00, 0x00, 0xc0, 0x50, 0x40,
3342 'D', 0x81, 0x95, 0x43, 0x8b, 0x6c, 0xe7, 0x00, 0x40,
3343 'D', 0x17, 0xd9, 0xce, 0xf7, 0x53, 0xe3, 0x37, 0x40,
3344 ']'
3345 };
3346 CHECK(json::to_bjdata(j) == v);
3347 CHECK(json::from_bjdata(v) == j);
3348 }
3349
3350 SECTION("Optimized with count")
3351 {
3352 // note the floats have been replaced by doubles
3353 json const j = {29.97, 31.13, 67.0, 2.113, 23.888};
3354 std::vector<uint8_t> v = {'[', '#', 'i', 5,
3355 'D', 0xb8, 0x1e, 0x85, 0xeb, 0x51, 0xf8, 0x3d, 0x40,
3356 'D', 0xe1, 0x7a, 0x14, 0xae, 0x47, 0x21, 0x3f, 0x40,
3357 'D', 0x00, 0x00, 0x00, 0x00, 0x00, 0xc0, 0x50, 0x40,
3358 'D', 0x81, 0x95, 0x43, 0x8b, 0x6c, 0xe7, 0x00, 0x40,
3359 'D', 0x17, 0xd9, 0xce, 0xf7, 0x53, 0xe3, 0x37, 0x40,
3360 };
3361 CHECK(json::to_bjdata(j, true) == v);
3362 CHECK(json::from_bjdata(v) == j);
3363 }
3364
3365 SECTION("Optimized with type & count")
3366 {
3367 // note the floats have been replaced by doubles
3368 json const j = {29.97, 31.13, 67.0, 2.113, 23.888};
3369 std::vector<uint8_t> v = {'[', '$', 'D', '#', 'i', 5,
3370 0xb8, 0x1e, 0x85, 0xeb, 0x51, 0xf8, 0x3d, 0x40,
3371 0xe1, 0x7a, 0x14, 0xae, 0x47, 0x21, 0x3f, 0x40,
3372 0x00, 0x00, 0x00, 0x00, 0x00, 0xc0, 0x50, 0x40,
3373 0x81, 0x95, 0x43, 0x8b, 0x6c, 0xe7, 0x00, 0x40,
3374 0x17, 0xd9, 0xce, 0xf7, 0x53, 0xe3, 0x37, 0x40,
3375 };
3376 CHECK(json::to_bjdata(j, true, true) == v);
3377 CHECK(json::from_bjdata(v) == j);
3378 }
3379 }
3380
3381 SECTION("Object Example")
3382 {
3383 SECTION("No Optimization")
3384 {
3385 // note the floats have been replaced by doubles
3386 json const j = { {"lat", 29.976}, {"long", 31.131}, {"alt", 67.0} };
3387 std::vector<uint8_t> v = {'{',
3388 'i', 3, 'a', 'l', 't', 'D', 0x00, 0x00, 0x00, 0x00, 0x00, 0xc0, 0x50, 0x40,
3389 'i', 3, 'l', 'a', 't', 'D', 0x60, 0xe5, 0xd0, 0x22, 0xdb, 0xf9, 0x3d, 0x40,
3390 'i', 4, 'l', 'o', 'n', 'g', 'D', 0xa8, 0xc6, 0x4b, 0x37, 0x89, 0x21, 0x3f, 0x40,
3391 '}'
3392 };
3393 CHECK(json::to_bjdata(j) == v);
3394 CHECK(json::from_bjdata(v) == j);
3395 }
3396
3397 SECTION("Optimized with count")
3398 {
3399 // note the floats have been replaced by doubles
3400 json const j = { {"lat", 29.976}, {"long", 31.131}, {"alt", 67.0} };
3401 std::vector<uint8_t> v = {'{', '#', 'i', 3,
3402 'i', 3, 'a', 'l', 't', 'D', 0x00, 0x00, 0x00, 0x00, 0x00, 0xc0, 0x50, 0x40,
3403 'i', 3, 'l', 'a', 't', 'D', 0x60, 0xe5, 0xd0, 0x22, 0xdb, 0xf9, 0x3d, 0x40,
3404 'i', 4, 'l', 'o', 'n', 'g', 'D', 0xa8, 0xc6, 0x4b, 0x37, 0x89, 0x21, 0x3f, 0x40,
3405 };
3406 CHECK(json::to_bjdata(j, true) == v);
3407 CHECK(json::from_bjdata(v) == j);
3408 }
3409
3410 SECTION("Optimized with type & count")
3411 {
3412 // note the floats have been replaced by doubles
3413 json const j = { {"lat", 29.976}, {"long", 31.131}, {"alt", 67.0} };
3414 std::vector<uint8_t> v = {'{', '$', 'D', '#', 'i', 3,
3415 'i', 3, 'a', 'l', 't', 0x00, 0x00, 0x00, 0x00, 0x00, 0xc0, 0x50, 0x40,
3416 'i', 3, 'l', 'a', 't', 0x60, 0xe5, 0xd0, 0x22, 0xdb, 0xf9, 0x3d, 0x40,
3417 'i', 4, 'l', 'o', 'n', 'g', 0xa8, 0xc6, 0x4b, 0x37, 0x89, 0x21, 0x3f, 0x40,
3418 };
3419 CHECK(json::to_bjdata(j, true, true) == v);
3420 CHECK(json::from_bjdata(v) == j);
3421 }
3422 }
3423
3424 SECTION("Special Cases (Null, No-Op and Boolean)")
3425 {
3426 SECTION("Array")
3427 {
3428 json _;
3429 std::vector<uint8_t> const v = {'[', '$', 'N', '#', 'I', 0x00, 0x02};
3430 CHECK_THROWS_WITH_AS(_ = json::from_bjdata(v), "[json.exception.parse_error.112] parse error at byte 3: syntax error while parsing BJData type: marker 0x4E is not a permitted optimized array type", json::parse_error&);
3431 CHECK(json::from_bjdata(v, true, false).is_discarded());
3432 }
3433
3434 SECTION("Object")
3435 {
3436 json _;
3437 std::vector<uint8_t> const v = {'{', '$', 'Z', '#', 'i', 3, 'i', 4, 'n', 'a', 'm', 'e', 'i', 8, 'p', 'a', 's', 's', 'w', 'o', 'r', 'd', 'i', 5, 'e', 'm', 'a', 'i', 'l'};
3438 CHECK_THROWS_WITH_AS(_ = json::from_bjdata(v), "[json.exception.parse_error.112] parse error at byte 3: syntax error while parsing BJData type: marker 0x5A is not a permitted optimized array type", json::parse_error&);
3439 CHECK(json::from_bjdata(v, true, false).is_discarded());
3440 }
3441 }
3442 }
3443 }
3444
3445 #if !defined(JSON_NOEXCEPTION)
3446 TEST_CASE("all BJData first bytes")
3447 {
3448 // these bytes will fail immediately with exception parse_error.112
3449 std::set<uint8_t> supported =
3450 {
3451 'T', 'F', 'Z', 'U', 'i', 'I', 'l', 'L', 'd', 'D', 'C', 'S', '[', '{', 'N', 'H', 'u', 'm', 'M', 'h'
3452 };
3453
3454 for (auto i = 0; i < 256; ++i)
3455 {
3456 const auto byte = static_cast<uint8_t>(i);
CAPTURE(byte)3457 CAPTURE(byte)
3458
3459 try
3460 {
3461 auto res = json::from_bjdata(std::vector<uint8_t>(1, byte));
3462 }
3463 catch (const json::parse_error& e)
3464 {
3465 // check that parse_error.112 is only thrown if the
3466 // first byte is not in the supported set
3467 INFO_WITH_TEMP(e.what());
3468 if (supported.find(byte) == supported.end())
3469 {
3470 CHECK(e.id == 112);
3471 }
3472 else
3473 {
3474 CHECK(e.id != 112);
3475 }
3476 }
3477 }
3478 }
3479 #endif
3480
skip()3481 TEST_CASE("BJData roundtrips" * doctest::skip())
3482 {
3483 SECTION("input from self-generated BJData files")
3484 {
3485 for (const std::string filename :
3486 {
3487 TEST_DATA_DIRECTORY "/json_nlohmann_tests/all_unicode.json",
3488 TEST_DATA_DIRECTORY "/json.org/1.json",
3489 TEST_DATA_DIRECTORY "/json.org/2.json",
3490 TEST_DATA_DIRECTORY "/json.org/3.json",
3491 TEST_DATA_DIRECTORY "/json.org/4.json",
3492 TEST_DATA_DIRECTORY "/json.org/5.json",
3493 TEST_DATA_DIRECTORY "/json_roundtrip/roundtrip01.json",
3494 TEST_DATA_DIRECTORY "/json_roundtrip/roundtrip02.json",
3495 TEST_DATA_DIRECTORY "/json_roundtrip/roundtrip03.json",
3496 TEST_DATA_DIRECTORY "/json_roundtrip/roundtrip04.json",
3497 TEST_DATA_DIRECTORY "/json_roundtrip/roundtrip05.json",
3498 TEST_DATA_DIRECTORY "/json_roundtrip/roundtrip06.json",
3499 TEST_DATA_DIRECTORY "/json_roundtrip/roundtrip07.json",
3500 TEST_DATA_DIRECTORY "/json_roundtrip/roundtrip08.json",
3501 TEST_DATA_DIRECTORY "/json_roundtrip/roundtrip09.json",
3502 TEST_DATA_DIRECTORY "/json_roundtrip/roundtrip10.json",
3503 TEST_DATA_DIRECTORY "/json_roundtrip/roundtrip11.json",
3504 TEST_DATA_DIRECTORY "/json_roundtrip/roundtrip12.json",
3505 TEST_DATA_DIRECTORY "/json_roundtrip/roundtrip13.json",
3506 TEST_DATA_DIRECTORY "/json_roundtrip/roundtrip14.json",
3507 TEST_DATA_DIRECTORY "/json_roundtrip/roundtrip15.json",
3508 TEST_DATA_DIRECTORY "/json_roundtrip/roundtrip16.json",
3509 TEST_DATA_DIRECTORY "/json_roundtrip/roundtrip17.json",
3510 TEST_DATA_DIRECTORY "/json_roundtrip/roundtrip18.json",
3511 TEST_DATA_DIRECTORY "/json_roundtrip/roundtrip19.json",
3512 TEST_DATA_DIRECTORY "/json_roundtrip/roundtrip20.json",
3513 TEST_DATA_DIRECTORY "/json_roundtrip/roundtrip21.json",
3514 TEST_DATA_DIRECTORY "/json_roundtrip/roundtrip22.json",
3515 TEST_DATA_DIRECTORY "/json_roundtrip/roundtrip23.json",
3516 TEST_DATA_DIRECTORY "/json_roundtrip/roundtrip24.json",
3517 TEST_DATA_DIRECTORY "/json_roundtrip/roundtrip25.json",
3518 TEST_DATA_DIRECTORY "/json_roundtrip/roundtrip26.json",
3519 TEST_DATA_DIRECTORY "/json_roundtrip/roundtrip27.json",
3520 TEST_DATA_DIRECTORY "/json_roundtrip/roundtrip28.json",
3521 TEST_DATA_DIRECTORY "/json_roundtrip/roundtrip29.json",
3522 TEST_DATA_DIRECTORY "/json_roundtrip/roundtrip30.json",
3523 TEST_DATA_DIRECTORY "/json_roundtrip/roundtrip31.json",
3524 TEST_DATA_DIRECTORY "/json_roundtrip/roundtrip32.json",
3525 TEST_DATA_DIRECTORY "/json_testsuite/sample.json",
3526 TEST_DATA_DIRECTORY "/json_tests/pass1.json",
3527 TEST_DATA_DIRECTORY "/json_tests/pass2.json",
3528 TEST_DATA_DIRECTORY "/json_tests/pass3.json"
3529 })
3530 {
3531 CAPTURE(filename)
3532
3533 {
3534 INFO_WITH_TEMP(filename + ": std::vector<uint8_t>");
3535 // parse JSON file
3536 std::ifstream f_json(filename);
3537 json j1 = json::parse(f_json);
3538
3539 // parse BJData file
3540 auto packed = utils::read_binary_file(filename + ".bjdata");
3541 json j2;
3542 CHECK_NOTHROW(j2 = json::from_bjdata(packed));
3543
3544 // compare parsed JSON values
3545 CHECK(j1 == j2);
3546 }
3547
3548 {
3549 INFO_WITH_TEMP(filename + ": std::ifstream");
3550 // parse JSON file
3551 std::ifstream f_json(filename);
3552 json j1 = json::parse(f_json);
3553
3554 // parse BJData file
3555 std::ifstream f_bjdata(filename + ".bjdata", std::ios::binary);
3556 json j2;
3557 CHECK_NOTHROW(j2 = json::from_bjdata(f_bjdata));
3558
3559 // compare parsed JSON values
3560 CHECK(j1 == j2);
3561 }
3562
3563 {
3564 INFO_WITH_TEMP(filename + ": output to output adapters");
3565 // parse JSON file
3566 std::ifstream f_json(filename);
3567 json const j1 = json::parse(f_json);
3568
3569 // parse BJData file
3570 auto packed = utils::read_binary_file(filename + ".bjdata");
3571
3572 {
3573 INFO_WITH_TEMP(filename + ": output adapters: std::vector<uint8_t>");
3574 std::vector<uint8_t> vec;
3575 json::to_bjdata(j1, vec);
3576 CHECK(vec == packed);
3577 }
3578 }
3579 }
3580 }
3581 }
3582