]> git.proxmox.com Git - ceph.git/blob - ceph/src/boost/libs/json/test/test.hpp
import quincy beta 17.1.0
[ceph.git] / ceph / src / boost / libs / json / test / test.hpp
1 //
2 // Copyright (c) 2019 Vinnie Falco (vinnie.falco@gmail.com)
3 //
4 // Distributed under the Boost Software License, Version 1.0. (See accompanying
5 // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
6 //
7 // Official repository: https://github.com/boostorg/json
8 //
9
10 #ifndef BOOST_JSON_TEST_HPP
11 #define BOOST_JSON_TEST_HPP
12
13 #include <boost/json/basic_parser.hpp>
14 #include <boost/json/value.hpp>
15 #include <boost/json/serializer.hpp>
16 #include <boost/json/storage_ptr.hpp>
17 #include <boost/json/detail/format.hpp>
18
19 #include <cstddef>
20 #include <iterator>
21 #include <memory>
22 #include <type_traits>
23
24 #include "test_suite.hpp"
25
26 BOOST_JSON_NS_BEGIN
27
28 //----------------------------------------------------------
29
30 struct test_failure : std::exception
31 {
32 virtual
33 char const*
34 what() const noexcept override
35 {
36 return "test failure";
37 }
38 };
39
40 struct fail_resource
41 : memory_resource
42 {
43 std::size_t fail_max = 0;
44 std::size_t fail = 0;
45 std::size_t nalloc = 0;
46 std::size_t bytes = 0;
47
48 ~fail_resource()
49 {
50 BOOST_TEST(nalloc == 0);
51 }
52
53 void*
54 do_allocate(
55 std::size_t n,
56 std::size_t) override
57 {
58 if(++fail == fail_max)
59 {
60 ++fail_max;
61 fail = 0;
62 throw test_failure{};
63 }
64 auto p = ::operator new(n);
65 ++nalloc;
66 bytes += n;
67 return p;
68 }
69
70 void
71 do_deallocate(
72 void* p,
73 std::size_t n,
74 std::size_t) noexcept override
75 {
76 if(BOOST_TEST(nalloc > 0))
77 --nalloc;
78 bytes -= n;
79 ::operator delete(p);
80 }
81
82 bool
83 do_is_equal(
84 memory_resource const& mr) const noexcept override
85 {
86 return this == &mr;
87 }
88 };
89
90 template<class F>
91 void
92 fail_loop(F&& f)
93 {
94 fail_resource ss;
95 ss.fail_max = 1;
96 while(ss.fail < 200)
97 {
98 try
99 {
100 f(&ss);
101 }
102 catch(test_failure const&)
103 {
104 continue;
105 }
106 break;
107 }
108 BOOST_TEST(ss.fail < 200);
109 }
110
111 //----------------------------------------------------------
112
113 struct unique_resource
114 : memory_resource
115 {
116 unique_resource() = default;
117
118 void*
119 do_allocate(
120 std::size_t n,
121 std::size_t) override
122 {
123 return ::operator new(n);
124 }
125
126 void
127 do_deallocate(
128 void* p,
129 std::size_t,
130 std::size_t) noexcept override
131 {
132 return ::operator delete(p);
133 }
134
135 bool
136 do_is_equal(
137 memory_resource const& mr) const noexcept override
138 {
139 return this == &mr;
140 }
141 };
142
143 //----------------------------------------------------------
144
145 // The null parser discards all the data
146
147 class null_parser
148 {
149 struct handler
150 {
151 constexpr static std::size_t max_object_size = std::size_t(-1);
152 constexpr static std::size_t max_array_size = std::size_t(-1);
153 constexpr static std::size_t max_key_size = std::size_t(-1);
154 constexpr static std::size_t max_string_size = std::size_t(-1);
155
156 bool on_document_begin( error_code& ) { return true; }
157 bool on_document_end( error_code& ) { return true; }
158 bool on_object_begin( error_code& ) { return true; }
159 bool on_object_end( std::size_t, error_code& ) { return true; }
160 bool on_array_begin( error_code& ) { return true; }
161 bool on_array_end( std::size_t, error_code& ) { return true; }
162 bool on_key_part( string_view, std::size_t, error_code& ) { return true; }
163 bool on_key( string_view, std::size_t, error_code& ) { return true; }
164 bool on_string_part( string_view, std::size_t, error_code& ) { return true; }
165 bool on_string( string_view, std::size_t, error_code& ) { return true; }
166 bool on_number_part( string_view, error_code&) { return true; }
167 bool on_int64( std::int64_t, string_view, error_code& ) { return true; }
168 bool on_uint64( std::uint64_t, string_view, error_code& ) { return true; }
169 bool on_double( double, string_view, error_code& ) { return true; }
170 bool on_bool( bool, error_code& ) { return true; }
171 bool on_null( error_code& ) { return true; }
172 bool on_comment_part( string_view, error_code& ) { return true; }
173 bool on_comment( string_view, error_code& ) { return true; }
174 };
175
176 basic_parser<handler> p_;
177
178 public:
179 null_parser()
180 : p_(parse_options())
181 {
182 }
183
184 explicit
185 null_parser(parse_options po)
186 : p_(po)
187 {
188 }
189
190 void
191 reset()
192 {
193 p_.reset();
194 }
195
196 std::size_t
197 write(
198 char const* data,
199 std::size_t size,
200 error_code& ec)
201 {
202 auto const n = p_.write_some(
203 false, data, size, ec);
204 if(! ec && n < size)
205 ec = error::extra_data;
206 return n;
207 }
208 };
209
210 //----------------------------------------------------------
211
212 class fail_parser
213 {
214 struct handler
215 {
216 constexpr static std::size_t max_object_size = std::size_t(-1);
217 constexpr static std::size_t max_array_size = std::size_t(-1);
218 constexpr static std::size_t max_key_size = std::size_t(-1);
219 constexpr static std::size_t max_string_size = std::size_t(-1);
220
221 std::size_t n;
222
223 handler()
224 : n(std::size_t(-1))
225 {
226 }
227
228 bool
229 maybe_fail(error_code& ec)
230 {
231 if(n && --n > 0)
232 return true;
233 ec = error::test_failure;
234 return false;
235 }
236
237 bool
238 on_document_begin(
239 error_code& ec)
240 {
241 return maybe_fail(ec);
242 }
243
244 bool
245 on_document_end(
246 error_code& ec)
247 {
248 return maybe_fail(ec);
249 }
250
251 bool
252 on_object_begin(
253 error_code& ec)
254 {
255 return maybe_fail(ec);
256 }
257
258 bool
259 on_object_end(
260 std::size_t,
261 error_code& ec)
262 {
263 return maybe_fail(ec);
264 }
265
266 bool
267 on_array_begin(
268 error_code& ec)
269 {
270 return maybe_fail(ec);
271 }
272
273 bool
274 on_array_end(
275 std::size_t,
276 error_code& ec)
277 {
278 return maybe_fail(ec);
279 }
280
281 bool
282 on_key_part(
283 string_view,
284 std::size_t,
285 error_code& ec)
286 {
287 return maybe_fail(ec);
288 }
289
290 bool
291 on_key(
292 string_view,
293 std::size_t,
294 error_code& ec)
295 {
296 return maybe_fail(ec);
297 }
298
299 bool
300 on_string_part(
301 string_view,
302 std::size_t,
303 error_code& ec)
304 {
305 return maybe_fail(ec);
306 }
307
308 bool
309 on_string(
310 string_view,
311 std::size_t,
312 error_code& ec)
313 {
314 return maybe_fail(ec);
315 }
316
317 bool
318 on_number_part(
319 string_view,
320 error_code& ec)
321 {
322 return maybe_fail(ec);
323 }
324
325 bool
326 on_int64(
327 int64_t,
328 string_view,
329 error_code& ec)
330 {
331 return maybe_fail(ec);
332 }
333
334 bool
335 on_uint64(
336 uint64_t,
337 string_view,
338 error_code& ec)
339 {
340 return maybe_fail(ec);
341 }
342
343 bool
344 on_double(
345 double,
346 string_view,
347 error_code& ec)
348 {
349 return maybe_fail(ec);
350 }
351
352 bool
353 on_bool(
354 bool,
355 error_code& ec)
356 {
357 return maybe_fail(ec);
358 }
359
360 bool
361 on_null(error_code& ec)
362 {
363 return maybe_fail(ec);
364 }
365
366 bool
367 on_comment_part(
368 string_view,
369 error_code& ec)
370 {
371 return maybe_fail(ec);
372 }
373
374 bool
375 on_comment(
376 string_view,
377 error_code& ec)
378 {
379 return maybe_fail(ec);
380 }
381 };
382
383 basic_parser<handler> p_;
384
385 public:
386 fail_parser()
387 : p_(parse_options())
388 {
389 }
390
391 explicit
392 fail_parser(
393 std::size_t n,
394 parse_options po = parse_options())
395 : p_(po)
396 {
397 p_.handler().n = n;
398 }
399
400 explicit
401 fail_parser(parse_options po)
402 : p_(po)
403 {
404 }
405
406 void
407 reset()
408 {
409 p_.reset();
410 }
411
412 bool
413 done() const noexcept
414 {
415 return p_.done();
416 }
417
418 std::size_t
419 write_some(
420 bool more,
421 char const* data,
422 std::size_t size,
423 error_code& ec)
424 {
425 return p_.write_some(
426 more, data, size, ec);
427 }
428
429 std::size_t
430 write(
431 bool more,
432 char const* data,
433 std::size_t size,
434 error_code& ec)
435 {
436 auto const n = p_.write_some(
437 more, data, size, ec);
438 if(! ec && n < size)
439 ec = error::extra_data;
440 return n;
441 }
442 };
443
444 //----------------------------------------------------------
445
446 struct test_exception
447 : std::exception
448 {
449 char const*
450 what() const noexcept
451 {
452 return "test exception";
453 }
454 };
455
456 // Exercises every exception path
457 class throw_parser
458 {
459 struct handler
460 {
461 constexpr static std::size_t max_object_size = std::size_t(-1);
462 constexpr static std::size_t max_array_size = std::size_t(-1);
463 constexpr static std::size_t max_key_size = std::size_t(-1);
464 constexpr static std::size_t max_string_size = std::size_t(-1);
465
466 std::size_t n;
467
468 handler()
469 : n(std::size_t(-1))
470 {
471 }
472
473 bool
474 maybe_throw()
475 {
476 if(n && --n > 0)
477 return true;
478 throw test_exception{};
479 }
480
481 bool
482 on_document_begin(
483 error_code&)
484 {
485 return maybe_throw();
486 }
487
488 bool
489 on_document_end(
490 error_code&)
491 {
492 return maybe_throw();
493 }
494
495 bool
496 on_object_begin(
497 error_code&)
498 {
499 return maybe_throw();
500 }
501
502 bool
503 on_object_end(
504 std::size_t,
505 error_code&)
506 {
507 return maybe_throw();
508 }
509
510 bool
511 on_array_begin(
512 error_code&)
513 {
514 return maybe_throw();
515 }
516
517 bool
518 on_array_end(
519 std::size_t,
520 error_code&)
521 {
522 return maybe_throw();
523 }
524
525 bool
526 on_key_part(
527 string_view,
528 std::size_t,
529 error_code&)
530 {
531 return maybe_throw();
532 }
533
534 bool
535 on_key(
536 string_view,
537 std::size_t,
538 error_code&)
539 {
540 return maybe_throw();
541 }
542
543 bool
544 on_string_part(
545 string_view,
546 std::size_t,
547 error_code&)
548 {
549 return maybe_throw();
550 }
551
552 bool
553 on_string(
554 string_view,
555 std::size_t,
556 error_code&)
557 {
558 return maybe_throw();
559 }
560
561 bool
562 on_number_part(
563 string_view,
564 error_code&)
565 {
566 return maybe_throw();
567 }
568
569 bool
570 on_int64(
571 int64_t,
572 string_view,
573 error_code&)
574 {
575 return maybe_throw();
576 }
577
578 bool
579 on_uint64(
580 uint64_t,
581 string_view,
582 error_code&)
583 {
584 return maybe_throw();
585 }
586
587 bool
588 on_double(
589 double,
590 string_view,
591 error_code&)
592 {
593 return maybe_throw();
594 }
595
596 bool
597 on_bool(
598 bool,
599 error_code&)
600 {
601 return maybe_throw();
602 }
603
604 bool
605 on_null(error_code&)
606 {
607 return maybe_throw();
608 }
609
610 bool
611 on_comment_part(
612 string_view,
613 error_code&)
614 {
615 return maybe_throw();
616 }
617
618 bool
619 on_comment(
620 string_view,
621 error_code&)
622 {
623 return maybe_throw();
624 }
625 };
626
627 basic_parser<handler> p_;
628
629 public:
630 throw_parser()
631 : p_(parse_options())
632 {
633 }
634
635 explicit
636 throw_parser(
637 std::size_t n,
638 parse_options po = parse_options())
639 : p_(po)
640 {
641 p_.handler().n = n;
642 }
643
644 explicit
645 throw_parser(parse_options po)
646 : p_(po)
647 {
648 }
649
650 void
651 reset() noexcept
652 {
653 p_.reset();
654 }
655
656 std::size_t
657 write(
658 bool more,
659 char const* data,
660 std::size_t size,
661 error_code& ec)
662 {
663 auto const n = p_.write_some(
664 more, data, size, ec);
665 if(! ec && n < size)
666 ec = error::extra_data;
667 return n;
668 }
669 };
670
671 //----------------------------------------------------------
672
673 // wrap an iterator to make an input iterator
674 template<class FwdIt>
675 class input_iterator
676 {
677 FwdIt it_;
678
679 public:
680 using value_type = typename std::iterator_traits<FwdIt>::value_type;
681 using pointer = typename std::iterator_traits<FwdIt>::pointer;
682 using reference = typename std::iterator_traits<FwdIt>::reference;
683 using difference_type = typename std::iterator_traits<FwdIt>::difference_type;
684 using iterator_category = std::input_iterator_tag;
685
686 input_iterator() = default;
687 input_iterator(input_iterator const&) = default;
688 input_iterator& operator=(
689 input_iterator const&) = default;
690
691 input_iterator(FwdIt it)
692 : it_(it)
693 {
694 }
695
696 input_iterator&
697 operator++() noexcept
698 {
699 ++it_;
700 return *this;
701 }
702
703 input_iterator
704 operator++(int) noexcept
705 {
706 auto tmp = *this;
707 ++*this;
708 return tmp;
709 }
710
711 pointer
712 operator->() const noexcept
713 {
714 return it_.operator->();
715 }
716
717 reference
718 operator*() const noexcept
719 {
720 return *it_;
721 }
722
723 bool
724 operator==(input_iterator other) const noexcept
725 {
726 return it_ == other.it_;
727 }
728
729 bool
730 operator!=(input_iterator other) const noexcept
731 {
732 return it_ != other.it_;
733 }
734 };
735
736 template<class FwdIt>
737 input_iterator<FwdIt>
738 make_input_iterator(FwdIt it)
739 {
740 return input_iterator<FwdIt>(it);
741 }
742
743 //----------------------------------------------------------
744
745 inline
746 bool
747 equal_storage(
748 value const& v,
749 storage_ptr const& sp);
750
751 inline
752 bool
753 equal_storage(
754 object const& o,
755 storage_ptr const& sp)
756 {
757 if(*o.storage() != *sp)
758 return false;
759 for(auto const& e : o)
760 if(! equal_storage(e.value(), sp))
761 return false;
762 return true;
763 }
764
765 inline
766 bool
767 equal_storage(
768 array const& a,
769 storage_ptr const& sp)
770 {
771 if(*a.storage() != *sp)
772 return false;
773 for(auto const& v : a)
774 if(! equal_storage(v, sp))
775 return false;
776 return true;
777 }
778
779 bool
780 equal_storage(
781 value const& v,
782 storage_ptr const& sp)
783 {
784 switch(v.kind())
785 {
786 case json::kind::object:
787 if(*v.as_object().storage() != *sp)
788 return false;
789 return equal_storage(v.as_object(), sp);
790
791 case json::kind::array:
792 if(*v.as_array().storage() != *sp)
793 return false;
794 return equal_storage(v.as_array(), sp);
795
796 case json::kind::string:
797 return *v.as_string().storage() == *sp;
798
799 case json::kind::int64:
800 case json::kind::uint64:
801 case json::kind::double_:
802 case json::kind::bool_:
803 case json::kind::null:
804 break;
805 }
806
807 return *v.storage() == *sp;
808 }
809
810 inline
811 void
812 check_storage(
813 object const& o,
814 storage_ptr const& sp)
815 {
816 BOOST_TEST(equal_storage(o, sp));
817 }
818
819 inline
820 void
821 check_storage(
822 array const& a,
823 storage_ptr const& sp)
824 {
825 BOOST_TEST(equal_storage(a, sp));
826 }
827
828 inline
829 void
830 check_storage(
831 value const& v,
832 storage_ptr const& sp)
833 {
834 BOOST_TEST(equal_storage(v, sp));
835 }
836
837 //----------------------------------------------------------
838
839 namespace detail {
840
841 inline
842 void
843 to_string_test(
844 string& dest,
845 json::value const& jv)
846 {
847 switch(jv.kind())
848 {
849 case kind::object:
850 {
851 dest.push_back('{');
852 auto const& obj(
853 jv.get_object());
854 auto it = obj.begin();
855 if(it != obj.end())
856 {
857 goto obj_first;
858 while(it != obj.end())
859 {
860 dest.push_back(',');
861 obj_first:
862 dest.push_back('\"');
863 dest.append(it->key());
864 dest.push_back('\"');
865 dest.push_back(':');
866 to_string_test(
867 dest, it->value());
868 ++it;
869 }
870 }
871 dest.push_back('}');
872 break;
873 }
874
875 case kind::array:
876 {
877 dest.push_back('[');
878 auto const& arr(
879 jv.get_array());
880 auto it = arr.begin();
881 if(it != arr.end())
882 {
883 goto arr_first;
884 while(it != arr.end())
885 {
886 dest.push_back(',');
887 arr_first:
888 to_string_test(
889 dest, *it);
890 ++it;
891 }
892 }
893 dest.push_back(']');
894 break;
895 }
896
897 case kind::string:
898 #if 1
899 // safe, but doesn't handle escsapes
900 dest.push_back('\"');
901 dest.append(jv.get_string());
902 dest.push_back('\"');
903 #else
904 dest.append(serialize(jv));
905 #endif
906 break;
907
908 case kind::int64:
909 {
910 char buf[detail::max_number_chars];
911 auto const n =
912 detail::format_int64(
913 buf, jv.as_int64());
914 dest.append(string_view(buf).substr(0, n));
915 break;
916 }
917
918 case kind::uint64:
919 {
920 char buf[detail::max_number_chars];
921 auto const n =
922 detail::format_uint64(
923 buf, jv.as_uint64());
924 dest.append(string_view(buf).substr(0, n));
925 break;
926 }
927
928 case kind::double_:
929 {
930 char buf[detail::max_number_chars];
931 auto const n =
932 detail::format_double(
933 buf, jv.as_double());
934 dest.append(string_view(buf).substr(0, n));
935 break;
936 }
937
938 case kind::bool_:
939 if(jv.as_bool())
940 dest.append("true");
941 else
942 dest.append("false");
943 break;
944
945 case kind::null:
946 dest.append("null");
947 break;
948
949 default:
950 // should never get here
951 dest.append("?");
952 break;
953 }
954 }
955
956 } // detail
957
958 inline
959 string
960 to_string_test(
961 json::value const& jv)
962 {
963 string s;
964 s.reserve(1024);
965 detail::to_string_test(s, jv);
966 return s;
967 }
968
969 //----------------------------------------------------------
970
971 inline
972 bool
973 equal(
974 value const& lhs,
975 value const& rhs)
976 {
977 if(lhs.kind() != rhs.kind())
978 return false;
979 switch(lhs.kind())
980 {
981 case kind::object:
982 {
983 auto const& obj1 =
984 lhs.get_object();
985 auto const& obj2 =
986 rhs.get_object();
987 auto n = obj1.size();
988 if(obj2.size() != n)
989 return false;
990 auto it1 = obj1.begin();
991 auto it2 = obj2.begin();
992 while(n--)
993 {
994 if( it1->key() !=
995 it2->key())
996 return false;
997 if(! equal(
998 it1->value(),
999 it2->value()))
1000 return false;
1001 ++it1;
1002 ++it2;
1003 }
1004 return true;
1005 }
1006
1007 case kind::array:
1008 {
1009 auto const& arr1 =
1010 lhs.get_array();
1011 auto const& arr2 =
1012 rhs.get_array();
1013 auto n = arr1.size();
1014 if(arr2.size() != n)
1015 return false;
1016 auto it1 = arr1.begin();
1017 auto it2 = arr2.begin();
1018 while(n--)
1019 if(! equal(*it1++, *it2++))
1020 return false;
1021 return true;
1022 }
1023
1024 case kind::string:
1025 return
1026 lhs.get_string() ==
1027 rhs.get_string();
1028
1029 case kind::double_:
1030 return
1031 lhs.get_double() ==
1032 rhs.get_double();
1033
1034 case kind::int64:
1035 return
1036 lhs.get_int64() ==
1037 rhs.get_int64();
1038
1039 case kind::uint64:
1040 return
1041 lhs.get_uint64() ==
1042 rhs.get_uint64();
1043
1044 case kind::bool_:
1045 return
1046 lhs.get_bool() ==
1047 rhs.get_bool();
1048
1049 case kind::null:
1050 return true;
1051 }
1052
1053 return false;
1054 }
1055
1056 //----------------------------------------------------------
1057
1058 namespace detail {
1059
1060 inline
1061 void
1062 check_array_impl(int, value const&)
1063 {
1064 }
1065
1066 template<class Arg>
1067 void
1068 check_array_impl(
1069 int i, value const& jv,
1070 Arg const& arg)
1071 {
1072 BOOST_TEST(equal(jv.at(i), arg));
1073 }
1074
1075 template<
1076 class Arg0,
1077 class Arg1,
1078 class... Argn>
1079 void
1080 check_array_impl(
1081 int i, value const& jv,
1082 Arg0 const& arg0,
1083 Arg1 const& arg1,
1084 Argn const&... argn)
1085 {
1086 BOOST_TEST(equal(jv.at(i), arg0));
1087 BOOST_TEST(equal(jv.at(i + 1), arg1));
1088 check_array_impl(i + 2, jv, argn...);
1089 }
1090
1091 } // detail
1092
1093 template<class... Argn>
1094 static
1095 void
1096 check_array(
1097 value const& jv,
1098 Argn const&... argn)
1099 {
1100 if(! BOOST_TEST(jv.is_array()))
1101 return;
1102 if(! BOOST_TEST(sizeof...(argn) ==
1103 jv.get_array().size()))
1104 return;
1105 detail::check_array_impl(0, jv, argn...);
1106 }
1107
1108 //----------------------------------------------------------
1109
1110 BOOST_JSON_NS_END
1111
1112 #endif