]> git.proxmox.com Git - ceph.git/blame - ceph/src/boost/libs/json/test/object.cpp
import quincy beta 17.1.0
[ceph.git] / ceph / src / boost / libs / json / test / object.cpp
CommitLineData
20effc67
TL
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// Test that header file is self-contained.
11#include <boost/json/object.hpp>
12
13#include <boost/json/monotonic_resource.hpp>
14#include <boost/json/parse.hpp>
15#include <boost/json/serialize.hpp>
16
17#include <cmath>
18#include <string>
19#include <type_traits>
20#include <vector>
21
22#include "test.hpp"
23#include "test_suite.hpp"
24
25BOOST_JSON_NS_BEGIN
26
27BOOST_STATIC_ASSERT( std::is_nothrow_destructible<object>::value );
28BOOST_STATIC_ASSERT( std::is_nothrow_move_constructible<object>::value );
29
30class object_test
31{
32public:
33 static
34 constexpr
35 std::size_t
36 size0_ =
37 detail::small_object_size_ - 2;
38
39 static
40 constexpr
41 std::size_t
42 size1_ = size0_ + 4;
43
44 test_suite::log_type log;
45 string_view const str_;
46
47 using init_list =
48 std::initializer_list<
49 std::pair<string_view, value_ref>>;
50
51#define DECLARE_INIT_LISTS \
52 init_list i0_ = { \
53 { "0", 0 }, { "1", 1 }, { "2", 2 }, { "3", 3 }, { "4", 4 }, \
54 { "5", 5 }, { "6", 6 }, { "7", 7 }, { "8", 8 }, { "9", 9 }, \
55 { "10", 10 }, { "11", 11 }, { "12", 12 }, { "13", 13 }, { "14", 14 }, \
56 { "15", 15 } }; \
57 init_list i1_ = { \
58 { "0", 0 }, { "1", 1 }, { "2", 2 }, { "3", 3 }, { "4", 4 }, \
59 { "5", 5 }, { "6", 6 }, { "7", 7 }, { "8", 8 }, { "9", 9 }, \
60 { "10", 10 }, { "11", 11 }, { "12", 12 }, { "13", 13 }, { "14", 14 }, \
61 { "15", 15 }, { "16", 16 }, { "17", 17 }, { "18", 18 }, { "19", 19 } }
62
63 string_view const s0_ =
64 R"({"0":0,"1":1,"2":2,"3":3,"4":4,)"
65 R"("5":5,"6":6,"7":7,"8":8,"9":9,)"
66 R"("10":10,"11":11,"12":12,"13":13,"14":14,)"
67 R"("15":15})";
68
69 string_view const s1_ =
70 R"({"0":0,"1":1,"2":2,"3":3,"4":4,)"
71 R"("5":5,"6":6,"7":7,"8":8,"9":9,)"
72 R"("10":10,"11":11,"12":12,"13":13,"14":14,)"
73 R"("15":15,"16":16,"17":17,"18":18,"19":19})";
74
75 object_test()
76 : str_("abcdefghijklmnopqrstuvwxyz")
77 {
78 // ensure this string does
79 // not fit in the SBO area.
80 BOOST_ASSERT(str_.size() >
81 string().capacity());
82
83 DECLARE_INIT_LISTS;
84
85 BOOST_TEST(
86 i0_.size() == size0_);
87 BOOST_TEST(
88 i1_.size() == size1_);
89 }
90
91 template<class T, class U, class = void>
92 struct is_equal_comparable : std::false_type {};
93
94 template<class T, class U>
95 struct is_equal_comparable<T, U, detail::void_t<decltype(
96 std::declval<T const&>() == std::declval<U const&>()
97 )>> : std::true_type {};
98
99 template<class T, class U, class = void>
100 struct is_unequal_comparable : std::false_type {};
101
102 template<class T, class U>
103 struct is_unequal_comparable<T, U, detail::void_t<decltype(
104 std::declval<T const&>() != std::declval<U const&>()
105 )>> : std::true_type {};
106
107 BOOST_STATIC_ASSERT( std::is_constructible<object::iterator, object::iterator>::value);
108 BOOST_STATIC_ASSERT(! std::is_constructible<object::iterator, object::const_iterator>::value);
109
110 BOOST_STATIC_ASSERT( std::is_constructible<object::const_iterator, object::iterator>::value);
111 BOOST_STATIC_ASSERT( std::is_constructible<object::const_iterator, object::const_iterator>::value);
112
113 BOOST_STATIC_ASSERT( std::is_assignable<object::iterator&, object::iterator>::value);
114 BOOST_STATIC_ASSERT(! std::is_assignable<object::iterator&, object::const_iterator>::value);
115
116 BOOST_STATIC_ASSERT( std::is_assignable<object::const_iterator&, object::iterator>::value);
117 BOOST_STATIC_ASSERT( std::is_assignable<object::const_iterator&, object::const_iterator>::value);
118
119 BOOST_STATIC_ASSERT(is_equal_comparable<object::iterator, object::iterator>::value);
120 BOOST_STATIC_ASSERT(is_equal_comparable<object::iterator, object::const_iterator>::value);
121
122 BOOST_STATIC_ASSERT(is_equal_comparable<object::const_iterator, object::iterator>::value);
123 BOOST_STATIC_ASSERT(is_equal_comparable<object::const_iterator, object::const_iterator>::value);
124
125 BOOST_STATIC_ASSERT(is_unequal_comparable<object::iterator, object::iterator>::value);
126 BOOST_STATIC_ASSERT(is_unequal_comparable<object::iterator, object::const_iterator>::value);
127
128 BOOST_STATIC_ASSERT(is_unequal_comparable<object::const_iterator, object::iterator>::value);
129 BOOST_STATIC_ASSERT(is_unequal_comparable<object::const_iterator, object::const_iterator>::value);
130
131 BOOST_STATIC_ASSERT( std::is_constructible<object::reverse_iterator, object::reverse_iterator>::value);
132 // std::reverse_iterator ctor is not SFINAEd
133 //BOOST_STATIC_ASSERT(! std::is_constructible<object::reverse_iterator, object::const_reverse_iterator>::value);
134
135 BOOST_STATIC_ASSERT( std::is_constructible<object::const_reverse_iterator, object::reverse_iterator>::value);
136 BOOST_STATIC_ASSERT( std::is_constructible<object::const_reverse_iterator, object::const_reverse_iterator>::value);
137
138 BOOST_STATIC_ASSERT( std::is_assignable<object::reverse_iterator&, object::reverse_iterator>::value);
139 // std::reverse_iterator assignment is not SFINAEd
140 //BOOST_STATIC_ASSERT(! std::is_assignable<object::reverse_iterator&, object::const_reverse_iterator>::value);
141
142 BOOST_STATIC_ASSERT( std::is_assignable<object::const_reverse_iterator&, object::reverse_iterator>::value);
143 BOOST_STATIC_ASSERT( std::is_assignable<object::const_reverse_iterator&, object::const_reverse_iterator>::value);
144
145 BOOST_STATIC_ASSERT(is_equal_comparable<object::reverse_iterator, object::reverse_iterator>::value);
146 BOOST_STATIC_ASSERT(is_equal_comparable<object::reverse_iterator, object::const_reverse_iterator>::value);
147
148 BOOST_STATIC_ASSERT(is_equal_comparable<object::const_reverse_iterator, object::reverse_iterator>::value);
149 BOOST_STATIC_ASSERT(is_equal_comparable<object::const_reverse_iterator, object::const_reverse_iterator>::value);
150
151 BOOST_STATIC_ASSERT(is_unequal_comparable<object::reverse_iterator, object::reverse_iterator>::value);
152 BOOST_STATIC_ASSERT(is_unequal_comparable<object::reverse_iterator, object::const_reverse_iterator>::value);
153
154 BOOST_STATIC_ASSERT(is_unequal_comparable<object::const_reverse_iterator, object::reverse_iterator>::value);
155 BOOST_STATIC_ASSERT(is_unequal_comparable<object::const_reverse_iterator, object::const_reverse_iterator>::value);
156
157 static
158 void
159 check(
160 object const& o,
161 string_view s,
162 std::size_t capacity = 0)
163 {
164 BOOST_TEST(
165 parse(serialize(o)).as_object() ==
166 parse(s).as_object());
167 if(capacity != 0)
168 BOOST_TEST(o.capacity() == capacity);
169 }
170
171 static
172 void
173 check(
174 object const& o,
175 std::size_t capacity)
176 {
177 BOOST_TEST(! o.empty());
178 BOOST_TEST(o.size() == 3);
179 BOOST_TEST(
180 o.capacity() == capacity);
181 BOOST_TEST(o.at("a").as_int64() == 1);
182 BOOST_TEST(o.at("b").as_bool());
183 BOOST_TEST(o.at("c").as_string() == "hello");
184 check_storage(o, o.storage());
185 }
186
187 void
188 testDtor()
189 {
190 // ~object()
191 {
192 object o;
193 }
194 }
195
196 void
197 testCtors()
198 {
199 DECLARE_INIT_LISTS;
200
201 // object(detail::unchecked_object&&)
202 {
203 // small
204 {
205 value const jv = parse(s0_);
206 check(jv.as_object(), s0_, i0_.size());
207 }
208
209 // small, duplicate
210 {
211 value const jv = parse(
212 R"({"0":0,"1":1,"2":2,"3":3,"4":4,)"
213 R"("5":5,"6":6,"7":7,"8":8,"9":9,)"
214 R"("10":10,"11":11,"12":12,"13":13,"14":14,)"
215 R"("15":15,"10":10})");
216 check(jv.as_object(), s0_, i0_.size() + 1);
217 }
218
219 // large
220 {
221 value const jv = parse(s1_);
222 check(jv.as_object(), s1_, i1_.size());
223 }
224
225 // large, duplicate
226 {
227 value const jv = parse(
228 R"({"0":0,"1":1,"2":2,"3":3,"4":4,)"
229 R"("5":5,"6":6,"7":7,"8":8,"9":9,)"
230 R"("10":10,"11":11,"12":12,"13":13,"14":14,)"
231 R"("15":15,"16":16,"17":17,"18":18,"19":19,"10":10})");
232 check(jv.as_object(), s1_, i1_.size() + 1);
233 }
234 }
235
236 // object()
237 {
238 object o;
239 BOOST_TEST(o.empty());
240 BOOST_TEST(o.size() == 0);
241 BOOST_TEST(o.capacity() == 0);
242 }
243
244 // object(storage_ptr)
245 fail_loop([&](storage_ptr const& sp)
246 {
247 object o(sp);
248 check_storage(o, sp);
249 BOOST_TEST(o.empty());
250 BOOST_TEST(o.size() == 0);
251 BOOST_TEST(o.capacity() == 0);
252 });
253
254 // object(std::size_t, storage_ptr)
255 {
256 // small
257 {
258 object o(size0_);
259 BOOST_TEST(o.empty());
260 BOOST_TEST(o.size() == 0);
261 BOOST_TEST(o.capacity() == size0_);
262 }
263
264 // small
265 fail_loop([&](storage_ptr const& sp)
266 {
267 object o(size0_, sp);
268 check_storage(o, sp);
269 BOOST_TEST(o.empty());
270 BOOST_TEST(o.size() == 0);
271 BOOST_TEST(o.capacity() == size0_);
272 });
273
274 // large
275 {
276 object o(size1_);
277 BOOST_TEST(o.empty());
278 BOOST_TEST(o.size() == 0);
279 BOOST_TEST(o.capacity() == size1_);
280 }
281
282 // large
283 fail_loop([&](storage_ptr const& sp)
284 {
285 object o(size1_, sp);
286 check_storage(o, sp);
287 BOOST_TEST(o.empty());
288 BOOST_TEST(o.size() == 0);
289 BOOST_TEST(o.capacity() == size1_);
290 });
291 }
292
293 // object(InputIt, InputIt, size_type, storage_ptr)
294 {
295 // small
296 {
297 object o(i0_.begin(), i0_.end());
298 check(o, s0_, i0_.size());
299 }
300
301 // small, ForwardIterator
302 fail_loop([&](storage_ptr const& sp)
303 {
304 object o(i0_.begin(), i0_.end(), size0_ + 1, sp);
305 BOOST_TEST(! o.empty());
306 check(o, s0_, size0_ + 1);
307 check_storage(o, sp);
308 });
309
310 // small, InputIterator
311 fail_loop([&](storage_ptr const& sp)
312 {
313 object o(
314 make_input_iterator(i0_.begin()),
315 make_input_iterator(i0_.end()), size0_ + 1, sp);
316 BOOST_TEST(! o.empty());
317 BOOST_TEST(o.capacity() == size0_ + 1);
318 check(o, s0_, size0_ + 1);
319 check_storage(o, sp);
320 });
321
322 // large
323 {
324 object o(i1_.begin(), i1_.end());
325 check(o, s1_, i1_.size());
326 }
327
328 // large, ForwardIterator
329 fail_loop([&](storage_ptr const& sp)
330 {
331 object o(i1_.begin(), i1_.end(), size1_ + 1, sp);
332 BOOST_TEST(! o.empty());
333 BOOST_TEST(o.capacity() == size1_ + 1);
334 check(o, s1_, size1_ + 1);
335 check_storage(o, sp);
336 });
337
338 // large, InputIterator
339 fail_loop([&](storage_ptr const& sp)
340 {
341 object o(
342 make_input_iterator(i1_.begin()),
343 make_input_iterator(i1_.end()), size1_ + 1, sp);
344 BOOST_TEST(! o.empty());
345 BOOST_TEST(o.capacity() == size1_ + 1);
346 check(o, s1_, size1_ + 1);
347 check_storage(o, sp);
348 });
349 }
350
351 // object(object&&)
352 {
353 object o1(i0_);
354 check(o1, s0_);
355 auto const sp =
356 storage_ptr{};
357 object o2(std::move(o1));
358 BOOST_TEST(o1.empty());
359 BOOST_TEST(o1.size() == 0);
360 check(o2, s0_);
361 check_storage(o1, sp);
362 check_storage(o2, sp);
363 }
364
365 // object(object&&, storage_ptr)
366 {
367 // small
368 fail_loop([&](storage_ptr const& sp)
369 {
370 object o1(i0_);
371 object o2(std::move(o1), sp);
372 BOOST_TEST(! o1.empty());
373 check(o2, s0_, i0_.size());
374 check_storage(o1,
375 storage_ptr{});
376 check_storage(o2, sp);
377 });
378
379 // large
380 fail_loop([&](storage_ptr const& sp)
381 {
382 object o1(i1_);
383 object o2(std::move(o1), sp);
384 BOOST_TEST(! o1.empty());
385 check(o2, s1_, i1_.size());
386 check_storage(o1,
387 storage_ptr{});
388 check_storage(o2, sp);
389 });
390 }
391
392 // object(pilfered<object>)
393 {
394 {
395 auto const sp =
396 make_shared_resource<unique_resource>();
397 object o1(i0_, sp);
398 object o2(pilfer(o1));
399 BOOST_TEST(
400 o1.storage() == storage_ptr());
401 BOOST_TEST(
402 *o2.storage() == *sp);
403 BOOST_TEST(o1.empty());
404 check(o2, s0_, i0_.size());
405 }
406
407 // ensure pilfered-from objects
408 // are trivially destructible
409 {
410 object o1(make_shared_resource<
411 monotonic_resource>());
412 object o2(pilfer(o1));
413 BOOST_TEST(o1.storage().get() ==
414 storage_ptr().get());
415 }
416 }
417
418 auto const sp =
419 make_shared_resource<
420 unique_resource>();
421 auto const sp0 = storage_ptr{};
422
423 // object(object const&)
424 {
425 // small
426 {
427 object o1(i0_);
428 object o2(o1);
429 BOOST_TEST(! o1.empty());
430 check(o2, s0_, i0_.size());
431 }
432
433 // large
434 {
435 object o1(i1_);
436 object o2(o1);
437 BOOST_TEST(! o1.empty());
438 check(o2, s1_, i1_.size());
439 }
440 }
441
442 // object(object const&, storage_ptr)
443 {
444 // small
445 fail_loop([&](storage_ptr const& sp)
446 {
447 object o1(i0_);
448 object o2(o1, sp);
449 BOOST_TEST(! o1.empty());
450 check(o2, s0_, i0_.size());
451 check_storage(o2, sp);
452 });
453
454 // large
455 fail_loop([&](storage_ptr const& sp)
456 {
457 object o1(i1_);
458 object o2(o1, sp);
459 BOOST_TEST(! o1.empty());
460 check(o2, s1_, i1_.size());
461 check_storage(o2, sp);
462 });
463 }
464
465 // object(initializer_list, storage_ptr)
466 {
467 // small
468 {
469 object o(i0_);
470 check(o, s0_, i0_.size());
471 }
472
473 // small
474 fail_loop([&](storage_ptr const& sp)
475 {
476 object o(i0_, sp);
477 check(o, s0_, i0_.size());
478 check_storage(o, sp);
479 });
480
481 // large
482 {
483 object o(i1_);
484 check(o, s1_, i1_.size());
485 }
486
487 // large
488 fail_loop([&](storage_ptr const& sp)
489 {
490 object o(i1_, sp);
491 check(o, s1_, i1_.size());
492 check_storage(o, sp);
493 });
494 }
495
496 // object(initializer_list, std::size_t, storage_ptr)
497 {
498 // small
499 {
500 object o(i0_, size0_ + 1);
501 check(o, s0_, size0_ + 1);
502 }
503
504 // small
505 fail_loop([&](storage_ptr const& sp)
506 {
507 object o(i0_, size0_ + 1, sp);
508 BOOST_TEST(
509 *o.storage() == *sp);
510 check(o, s0_, size0_ + 1);
511 });
512 }
513
514 // operator=(object const&)
515 {
516 {
517 object o1(i0_);
518 object o2;
519 o2 = o1;
520 check(o1, s0_, i0_.size());
521 check(o2, s0_, i0_.size());
522 check_storage(o1,
523 storage_ptr{});
524 check_storage(o2,
525 storage_ptr{});
526 }
527
528 fail_loop([&](storage_ptr const& sp)
529 {
530 object o1(i0_);
531 object o2(sp);
532 o2 = o1;
533 check(o1, s0_, i0_.size());
534 check(o2, s0_, i0_.size());
535 check_storage(o1,
536 storage_ptr{});
537 check_storage(o2, sp);
538 });
539
540 // self-assign
541 {
542 object o1(i0_);
543 object const& o2(o1);
544 o1 = o2;
545 check(o1, s0_, i0_.size());
546 }
547
548 // copy from child
549 {
550 object o({
551 {"a", 1}, {"b",
552 { {"a", 1}, {"b", true}, {"c", "hello"} }
553 }, {"c", "hello"}});
554 o = o["b"].as_object();
555 check(o, 3);
556 }
557 }
558
559 // operator=(object&&)
560 {
561 {
562 object o1({
563 {"a", 1},
564 {"b", true},
565 {"c", "hello"}});
566 object o2;
567 o2 = std::move(o1);
568 check(o2, 3);
569 BOOST_TEST(o1.empty());
570 check_storage(o1,
571 storage_ptr{});
572 check_storage(o2,
573 storage_ptr{});
574 }
575
576 fail_loop([&](storage_ptr const& sp)
577 {
578 object o1({
579 {"a", 1},
580 {"b", true},
581 {"c", "hello"}});
582 object o2(sp);
583 o2 = std::move(o1);
584 check(o1, 3);
585 check(o2, 3);
586 check_storage(o1,
587 storage_ptr{});
588 check_storage(o2, sp);
589 });
590
591 // self-move
592 {
593 object o1({
594 {"a", 1},
595 {"b", true},
596 {"c", "hello"}});
597 object const& o2(o1);
598 o1 = std::move(o2);
599 check(o1, 3);
600 }
601
602 // move from child
603 {
604 object o({
605 {"a", 1}, {"b",
606 { {"a", 1}, {"b", true}, {"c", "hello"} }
607 }, {"c", "hello"}});
608 o = std::move(o["b"].as_object());
609 check(o, 3);
610 }
611 }
612
613 // operator=(initializer_list)
614 {
615 {
616 object o;
617 o = {
618 {"a", 1},
619 {"b", true},
620 {"c", "hello"} },
621 check(o, 3);
622 check_storage(o,
623 storage_ptr{});
624 }
625
626 fail_loop([&](storage_ptr const& sp)
627 {
628 object o(sp);
629 o = {
630 {"a", 1},
631 {"b", true},
632 {"c", "hello"} },
633 BOOST_TEST(
634 *o.storage() == *sp);
635 check(o, 3);
636 check_storage(o, sp);
637 });
638
639 // assign from child
640 {
641 object o = {
642 { "k1", 1 },
643 { "k2", 2 },
644 { "k3", 3 } };
645 o = { { "k2", o["k2"] } };
646 BOOST_TEST(
647 o == object({ { "k2", 2 } }));
648 }
649 }
650 }
651
652 void
653 testIterators()
654 {
655 object o({
656 {"a", 1},
657 {"b", true},
658 {"c", "hello"}});
659 auto const& co = o;
660 object no;
661 auto const& cno = no;
662
663 // empty container
664 {
665 BOOST_TEST(no.begin() == no.end());
666 BOOST_TEST(cno.begin() == cno.end());
667 BOOST_TEST(no.cbegin() == no.cend());
668 }
669
670 // begin()
671 {
672 auto it = o.begin();
673 BOOST_TEST(it->key() == "a"); ++it;
674 BOOST_TEST(it->key() == "b"); it++;
675 BOOST_TEST(it->key() == "c"); ++it;
676 BOOST_TEST(it == o.end());
677 }
678
679 // begin() const
680 {
681 auto it = co.begin();
682 BOOST_TEST(it->key() == "a"); ++it;
683 BOOST_TEST(it->key() == "b"); it++;
684 BOOST_TEST(it->key() == "c"); ++it;
685 BOOST_TEST(it == co.end());
686 }
687
688 // cbegin()
689 {
690 auto it = o.cbegin();
691 BOOST_TEST(it->key() == "a"); ++it;
692 BOOST_TEST(it->key() == "b"); it++;
693 BOOST_TEST(it->key() == "c"); ++it;
694 BOOST_TEST(it == o.cend());
695 }
696
697 // end()
698 {
699 auto it = o.end();
700 --it; BOOST_TEST(it->key() == "c");
701 it--; BOOST_TEST(it->key() == "b");
702 --it; BOOST_TEST(it->key() == "a");
703 BOOST_TEST(it == o.begin());
704 }
705
706 // end() const
707 {
708 auto it = co.end();
709 --it; BOOST_TEST(it->key() == "c");
710 it--; BOOST_TEST(it->key() == "b");
711 --it; BOOST_TEST(it->key() == "a");
712 BOOST_TEST(it == co.begin());
713 }
714
715 // cend()
716 {
717 auto it = o.cend();
718 --it; BOOST_TEST(it->key() == "c");
719 it--; BOOST_TEST(it->key() == "b");
720 --it; BOOST_TEST(it->key() == "a");
721 BOOST_TEST(it == o.cbegin());
722 }
723
724 // rbegin()
725 {
726 auto it = o.rbegin();
727 BOOST_TEST(it->key() == "c"); ++it;
728 BOOST_TEST(it->key() == "b"); it++;
729 BOOST_TEST(it->key() == "a"); ++it;
730 BOOST_TEST(it == o.rend());
731 }
732
733 // rbegin() const
734 {
735 auto it = co.rbegin();
736 BOOST_TEST(it->key() == "c"); ++it;
737 BOOST_TEST(it->key() == "b"); it++;
738 BOOST_TEST(it->key() == "a"); ++it;
739 BOOST_TEST(it == co.rend());
740 }
741
742 // crbegin()
743 {
744 auto it = o.crbegin();
745 BOOST_TEST(it->key() == "c"); ++it;
746 BOOST_TEST(it->key() == "b"); it++;
747 BOOST_TEST(it->key() == "a"); ++it;
748 BOOST_TEST(it == o.crend());
749 }
750
751 // rend()
752 {
753 auto it = o.rend();
754 --it; BOOST_TEST(it->key() == "a");
755 it--; BOOST_TEST(it->key() == "b");
756 --it; BOOST_TEST(it->key() == "c");
757 BOOST_TEST(it == o.rbegin());
758 }
759
760 // rend() const
761 {
762 auto it = co.rend();
763 --it; BOOST_TEST(it->key() == "a");
764 it--; BOOST_TEST(it->key() == "b");
765 --it; BOOST_TEST(it->key() == "c");
766 BOOST_TEST(it == co.rbegin());
767 }
768
769 // crend()
770 {
771 auto it = o.crend();
772 --it; BOOST_TEST(it->key() == "a");
773 it--; BOOST_TEST(it->key() == "b");
774 --it; BOOST_TEST(it->key() == "c");
775 BOOST_TEST(it == o.crbegin());
776 }
777 }
778
779 //------------------------------------------------------
780
781 void
782 testCapacity()
783 {
784 BOOST_TEST(
785 object{}.size() < object{}.max_size());
786 }
787
788 //------------------------------------------------------
789
790 void
791 testModifiers()
792 {
793 DECLARE_INIT_LISTS;
794
795 // clear
796 {
797 // empty
798 {
799 object o;
800 o.clear();
801 BOOST_TEST(o.empty());
802 }
803
804 // small
805 {
806 object o(i0_);
807 BOOST_TEST(! o.empty());
808 o.clear();
809 BOOST_TEST(o.empty());
810 }
811
812 // large
813 {
814 object o(i1_);
815 BOOST_TEST(! o.empty());
816 o.clear();
817 BOOST_TEST(o.empty());
818 }
819 }
820
821 // insert(P&&)
822 {
823 fail_loop([&](storage_ptr const& sp)
824 {
825 object o(sp);
826 auto result = o.insert(
827 std::make_pair("x", 1));
828 BOOST_TEST(result.second);
829 BOOST_TEST(result.first->key() == "x");
830 BOOST_TEST(result.first->value().as_int64() == 1);
831 });
832
833 fail_loop([&](storage_ptr const& sp)
834 {
835 object o(sp);
836 auto const p = std::make_pair("x", 1);
837 auto result = o.insert(p);
838 BOOST_TEST(result.second);
839 BOOST_TEST(result.first->key() == "x");
840 BOOST_TEST(result.first->value().as_int64() == 1);
841 });
842
843 fail_loop([&](storage_ptr const& sp)
844 {
845 object o({
846 {"a", 1},
847 {"b", 2},
848 {"c", 3}}, sp);
849 auto const result = o.insert(
850 std::make_pair("b", 4));
851 BOOST_TEST(
852 result.first->value().as_int64() == 2);
853 BOOST_TEST(! result.second);
854 });
855
856 // insert child
857 {
858 object o = {
859 { "k1", 1 },
860 { "k2", 2 },
861 { "k3", 3 } };
862 o.insert(std::pair<
863 string_view, value&>(
864 "k4", o["k2"]));
865 BOOST_TEST(o == object({
866 { "k1", 1 },
867 { "k2", 2 },
868 { "k3", 3 },
869 { "k4", 2 }}));
870 }
871 }
872
873 // insert(InputIt, InputIt)
874 {
875 // small
876 {
877 // ForwardIterator
878 fail_loop([&](storage_ptr const& sp)
879 {
880 object o(sp);
881 o.insert(i0_.begin(), i0_.end());
882 check(o, s0_);
883 });
884
885 // InputIterator
886 fail_loop([&](storage_ptr const& sp)
887 {
888 object o(sp);
889 o.insert(
890 make_input_iterator(i0_.begin()),
891 make_input_iterator(i0_.end()));
892 check(o, s0_);
893 });
894
895 // existing duplicate key, ForwardIterator
896 {
897 object o({{"0",0},{"1",1},{"2",2}});
898 init_list i = {{"2",nullptr},{"3",3}};
899 o.insert(i.begin(), i.end());
900 BOOST_TEST(o.capacity() <=
901 detail::small_object_size_);
902 check(o, R"({"0":0,"1":1,"2":2,"3":3})");
903 }
904
905 // existing duplicate key, InputIterator
906 {
907 object o({{"0",0},{"1",1},{"2",2}});
908 init_list i = {{"2",nullptr},{"3",3}};
909 o.insert(
910 make_input_iterator(i.begin()),
911 make_input_iterator(i.end()));
912 BOOST_TEST(o.capacity() <=
913 detail::small_object_size_);
914 check(o, R"({"0":0,"1":1,"2":2,"3":3})");
915 }
916
917 // new duplicate key, ForwardIterator
918 {
919 object o({{"0",0},{"1",1},{"2",2}});
920 init_list i = {{"3",3},{"4",4},{"3",5}};
921 o.insert(i.begin(), i.end());
922 BOOST_TEST(o.capacity() <=
923 detail::small_object_size_);
924 check(o, R"({"0":0,"1":1,"2":2,"3":3,"4":4})");
925 }
926
927 // new duplicate key, InputIterator
928 {
929 object o({{"0",0},{"1",1},{"2",2}});
930 init_list i = {{"3",3},{"4",4},{"3",5}};
931 o.insert(
932 make_input_iterator(i.begin()),
933 make_input_iterator(i.end()));
934 BOOST_TEST(o.capacity() <=
935 detail::small_object_size_);
936 check(o, R"({"0":0,"1":1,"2":2,"3":3,"4":4})");
937 }
938 }
939
940 // large, ForwardIterator
941 fail_loop([&](storage_ptr const& sp)
942 {
943 object o(sp);
944 o.insert(i1_.begin(), i1_.end());
945 check(o, s1_);
946 });
947
948 // large, InputIterator
949 fail_loop([&](storage_ptr const& sp)
950 {
951 object o(sp);
952 o.insert(
953 make_input_iterator(i1_.begin()),
954 make_input_iterator(i1_.end()));
955 check(o, s1_);
956 });
957 }
958
959 // insert(initializer_list)
960 {
961 // small
962 fail_loop([&](storage_ptr const& sp)
963 {
964 object o(sp);
965 o.insert(i0_);
966 check(o, s0_);
967 });
968
969 // small, existing duplicate
970 fail_loop([&](storage_ptr const& sp)
971 {
972 object o({{"0",0},{"1",1},/*{"2",2},*/{"3",3},{"4",4}}, sp);
973 BOOST_TEST(o.capacity() <= detail::small_object_size_);
974 o.insert({{"2",2},{"3",3}});
975 BOOST_TEST(o.capacity() <= detail::small_object_size_);
976 check(o, R"({"0":0,"1":1,"2":2,"3":3,"4":4})");
977 });
978
979 // small, new duplicate
980 fail_loop([&](storage_ptr const& sp)
981 {
982 object o({{"0",0},{"1",1},/*{"2",2},{"3",3},*/{"4",4}}, sp);
983 BOOST_TEST(o.capacity() <= detail::small_object_size_);
984 o.insert({{"2",2},{"3",3},{"2",2}});
985 BOOST_TEST(o.capacity() <= detail::small_object_size_);
986 check(o, R"({"0":0,"1":1,"2":2,"3":3,"4":4})");
987 });
988
989 // large
990 fail_loop([&](storage_ptr const& sp)
991 {
992 object o(sp);
993 o.insert(i1_);
994 check(o, s1_);
995 });
996
997 // large, existing duplicate
998 fail_loop([&](storage_ptr const& sp)
999 {
1000 object o({
1001 {"0",0},{"1",1},{"2",2},{"3",3},{"4",4},
1002 {"5",5},{"6",6},{"7",7},{"8",8},{"9",9},
1003 /*{"10",10},*/{"11",11},{"12",12},{"13",13},{"14",14},
1004 {"15",15},{"16",16},{"17",17},{"18",18},{"19",19}}, sp);
1005 BOOST_TEST(o.capacity() > detail::small_object_size_);
1006 o.insert({{"10",10},{"11",11}});
1007 BOOST_TEST(o.capacity() > detail::small_object_size_);
1008 check(o, s1_);
1009 });
1010
1011 // large, new duplicate
1012 fail_loop([&](storage_ptr const& sp)
1013 {
1014 object o({
1015 {"0",0},{"1",1},{"2",2},{"3",3},{"4",4},
1016 {"5",5},{"6",6},{"7",7},{"8",8},{"9",9},
1017 /*{"10",10},{"11",11},*/{"12",12},{"13",13},{"14",14},
1018 {"15",15},{"16",16},{"17",17},{"18",18},{"19",19}},
1019 detail::small_object_size_ + 1, sp);
1020 BOOST_TEST(o.capacity() > detail::small_object_size_);
1021 o.insert({{"10",10},{"11",11},{"10",10}});
1022 BOOST_TEST(o.capacity() > detail::small_object_size_);
1023 check(o, s1_);
1024 });
1025
1026 // do rollback in ~revert_insert
1027 fail_loop([&](storage_ptr const& sp)
1028 {
1029 object o(sp);
1030 o.insert({
1031 { "a", { 1, 2, 3, 4 } } });
1032 });
1033
1034 // insert child
1035 {
1036 object o = {
1037 { "k1", 1 },
1038 { "k2", 2 },
1039 { "k3", 3 } };
1040 o.insert({
1041 { "k4", o["k2"] } });
1042 BOOST_TEST(o == object({
1043 { "k1", 1 },
1044 { "k2", 2 },
1045 { "k3", 3 },
1046 { "k4", 2 }}));
1047 }
1048 }
1049
1050 // insert_or_assign(key, o);
1051 {
1052 fail_loop([&](storage_ptr const& sp)
1053 {
1054 object o({{"a", 1}}, sp);
1055 o.insert_or_assign("a", str_);
1056 BOOST_TEST(o["a"].is_string());
1057 });
1058
1059 fail_loop([&](storage_ptr const& sp)
1060 {
1061 object o({
1062 {"a", 1},
1063 {"b", 2},
1064 {"c", 3}}, sp);
1065 o.insert_or_assign("d", str_);
1066 BOOST_TEST(o["d"].is_string());
1067 BOOST_TEST(o.size() == 4);
1068 });
1069
1070 fail_loop([&](storage_ptr const& sp)
1071 {
1072 object o({{"a", 1}}, sp);
1073 o.insert_or_assign("b", true);
1074 o.insert_or_assign("c", "hello");
1075 check(o, 3);
1076 });
1077
1078 fail_loop([&](storage_ptr const& sp)
1079 {
1080 object o({{"a", 1}}, sp);
1081 BOOST_TEST(
1082 ! o.insert_or_assign("a", 2).second);
1083 BOOST_TEST(o["a"].as_int64() == 2);
1084 });
1085
1086 // insert child
1087 {
1088 object o = {
1089 { "k1", 1 },
1090 { "k2", 2 },
1091 { "k3", 3 } };
1092 o.insert_or_assign(
1093 "k4", o["k2"]);
1094 BOOST_TEST(o == object({
1095 { "k1", 1 },
1096 { "k2", 2 },
1097 { "k3", 3 },
1098 { "k4", 2 }}));
1099 }
1100 }
1101
1102 // emplace(key, arg)
1103 {
1104 fail_loop([&](storage_ptr const& sp)
1105 {
1106 object o(sp);
1107 o.emplace("a", 1);
1108 o.emplace("b", true);
1109 o.emplace("c", "hello");
1110 check(o, 3);
1111 });
1112
1113 // emplace child
1114 {
1115 object o = {
1116 { "k1", 1 },
1117 { "k2", 2 },
1118 { "k3", 3 } };
1119 o.emplace(
1120 "k4", o["k2"]);
1121 BOOST_TEST(o == object({
1122 { "k1", 1 },
1123 { "k2", 2 },
1124 { "k3", 3 },
1125 { "k4", 2 }}));
1126 }
1127 }
1128
1129 // erase(pos)
1130 {
1131 // small
1132 {
1133 object o(i0_);
1134 auto it = o.erase(o.find("10"));
1135 BOOST_TEST(it->key() == "15");
1136 BOOST_TEST(
1137 it->value().as_int64() == 15);
1138 BOOST_TEST(serialize(o) ==
1139 R"({"0":0,"1":1,"2":2,"3":3,"4":4,)"
1140 R"("5":5,"6":6,"7":7,"8":8,"9":9,)"
1141 R"("15":15,"11":11,"12":12,"13":13,"14":14})");
1142 }
1143
1144 // large
1145 {
1146 object o(i1_);
1147 auto it = o.erase(o.find("10"));
1148 BOOST_TEST(it->key() == "19");
1149 BOOST_TEST(
1150 it->value().as_int64() == 19);
1151 BOOST_TEST(serialize(o) ==
1152 R"({"0":0,"1":1,"2":2,"3":3,"4":4,)"
1153 R"("5":5,"6":6,"7":7,"8":8,"9":9,)"
1154 R"("19":19,"11":11,"12":12,"13":13,"14":14,)"
1155 R"("15":15,"16":16,"17":17,"18":18})");
1156 }
1157 }
1158
1159 // erase(key)
1160 {
1161 {
1162 object o({
1163 {"a", 1},
1164 {"b", true},
1165 {"c", "hello"}});
1166 BOOST_TEST(o.erase("b2") == 0);
1167 check(o, 3);
1168 }
1169
1170 {
1171 object o({
1172 {"a", 1},
1173 {"b", true},
1174 {"b2", 2},
1175 {"c", "hello"}});
1176 BOOST_TEST(o.erase("b2") == 1);
1177 check(o, 4);
1178 }
1179 }
1180
1181 // swap(object&)
1182 {
1183 {
1184 object o1 = {{"a",1}, {"b",true}, {"c", "hello"}};
1185 object o2 = {{"d",{1,2,3}}};
1186 swap(o1, o2);
1187 BOOST_TEST(o1.size() == 1);
1188 BOOST_TEST(o2.size() == 3);
1189 BOOST_TEST(o1.count("d") == 1);
1190 }
1191
1192 fail_loop([&](storage_ptr const& sp)
1193 {
1194 object o1 = {{"a",1}, {"b",true}, {"c", "hello"}};
1195 object o2({{"d",{1,2,3}}}, sp);
1196 swap(o1, o2);
1197 BOOST_TEST(o1.size() == 1);
1198 BOOST_TEST(o2.size() == 3);
1199 BOOST_TEST(o1.count("d") == 1);
1200 });
1201
1202 fail_loop([&](storage_ptr const& sp)
1203 {
1204 object o1({{"d",{1,2,3}}}, sp);
1205 object o2 = {{"a",1}, {"b",true}, {"c", "hello"}};
1206 swap(o1, o2);
1207 BOOST_TEST(o1.size() == 3);
1208 BOOST_TEST(o2.size() == 1);
1209 BOOST_TEST(o2.count("d") == 1);
1210 });
1211 }
1212 }
1213
1214 //------------------------------------------------------
1215
1216 void
1217 testLookup()
1218 {
1219 object o0;
1220 object o1({
1221 {"a", 1},
1222 {"b", true},
1223 {"c", "hello"}});
1224 auto const& co0 = o0;
1225 auto const& co1 = o1;
1226
1227 // at(key)
1228 {
1229 BOOST_TEST(
1230 o1.at("a").is_number());
1231 BOOST_TEST_THROWS((o1.at("d")),
1232 std::out_of_range);
1233 }
1234
1235 // at(key) const
1236 {
1237 BOOST_TEST(
1238 co1.at("a").is_number());
1239 BOOST_TEST_THROWS((co1.at("d")),
1240 std::out_of_range);
1241 }
1242
1243 // operator[&](key)
1244 {
1245 object o({
1246 {"a", 1},
1247 {"b", true},
1248 {"c", "hello"}});
1249 BOOST_TEST(o.count("d") == 0);;
1250 BOOST_TEST(o["a"].is_number());
1251 BOOST_TEST(o["d"].is_null());
1252 BOOST_TEST(o.count("d") == 1);
1253 }
1254
1255 // count(key)
1256 {
1257 BOOST_TEST(o1.count("a") == 1);
1258 BOOST_TEST(o1.count("d") == 0);
1259 BOOST_TEST(o1.count("e") == 0);
1260 }
1261
1262 // find(key)
1263 // find(key) const
1264 {
1265 BOOST_TEST(
1266 o0.find("") == o0.end());
1267 BOOST_TEST(
1268 o1.find("a")->key() == "a");
1269 BOOST_TEST(
1270 o1.find("e") == o1.end());
1271
1272 BOOST_TEST(
1273 co0.find("") == co0.end());
1274 BOOST_TEST(
1275 co1.find("a")->key() == "a");
1276 BOOST_TEST(
1277 co1.find("e") == o1.end());
1278 }
1279
1280 // contains(key)
1281 {
1282 BOOST_TEST(o1.contains("a"));
1283 BOOST_TEST(! o1.contains("e"));
1284 BOOST_TEST(! object().contains(""));
1285 }
1286
1287 // if_contains(key)
1288 // if_contains(key) const
1289 {
1290 BOOST_TEST(o1.if_contains("a")->is_int64());
1291 BOOST_TEST(o1.if_contains("e") == nullptr);
1292 BOOST_TEST(co1.if_contains("a")->is_int64());
1293 BOOST_TEST(co1.if_contains("e") == nullptr);
1294
1295 *o1.if_contains("a") = 2;
1296 BOOST_TEST(co1.if_contains("a")->as_int64() == 2);
1297 }
1298 }
1299
1300 void
1301 testHashPolicy()
1302 {
1303 // reserve(size_type)
1304 {
1305 {
1306 object o;
1307 for(std::size_t i = 0; i < 10; ++i)
1308 o.emplace(std::to_string(i), i);
1309 o.reserve(15);
1310 BOOST_TEST(o.capacity() >= 15);
1311 o.reserve(20);
1312 BOOST_TEST(o.capacity() >= 20);
1313 }
1314
1315 {
1316 object o;
1317 o.reserve(3);
1318 BOOST_TEST(o.capacity() == 3);
1319 o.reserve(7);
1320 BOOST_TEST(o.capacity() == 7);
1321 }
1322 }
1323 }
1324
1325 //------------------------------------------------------
1326
1327 void
1328 testImplementation()
1329 {
1330 // insert duplicate keys
1331 {
1332 object o({
1333 {"a", 1},
1334 {"b", true},
1335 {"b", {1,2,3}},
1336 {"c", "hello"}});
1337 BOOST_TEST(o.at("a").as_int64() == 1);
1338 BOOST_TEST(o.at("b").as_bool() == true);
1339 BOOST_TEST(o.at("c").as_string() == "hello");
1340 }
1341
1342 // destroy key_value_pair array with need_free=false
1343 {
1344 monotonic_resource mr;
1345 object o({
1346 {"a", 1},
1347 {"b", true},
1348 {"b", {1,2,3}},
1349 {"c", "hello"}}, &mr);
1350 }
1351 }
1352
1353 static
1354 string_view
1355 make_key(
1356 std::size_t i,
1357 char* buf)
1358 {
1359 int constexpr base = 62;
1360 char const* const alphabet =
1361 "0123456789"
1362 "ABCDEFGHIJKLMNOPQRSTUVWXYZ"
1363 "abcdefghijklmnopqrstuvwxyz";
1364 char* dest = buf;
1365 do
1366 {
1367 *dest++ = alphabet[i%base];
1368 i /= base;
1369 }
1370 while(i);
1371 return { buf, static_cast<
1372 std::size_t>(dest-buf) };
1373 }
1374
1375 void
1376 testCollisions()
1377 {
1378 int constexpr buckets =
1379 detail::small_object_size_ + 1;
1380 int constexpr collisions = 3;
1381
1382 //DECLARE_INIT_LISTS;
1383
1384 // find a set of keys that collide
1385 std::vector<std::string> v;
1386 object o;
1387 o.reserve(buckets);
1388 {
1389 BOOST_TEST(
1390 o.capacity() == buckets);
1391 char buf[26];
1392 auto const match =
1393 o.t_->digest("0") % buckets;
1394 v.push_back("0");
1395 std::size_t i = 1;
1396 for(;;)
1397 {
1398 auto s = make_key(i, buf);
1399 if((o.t_->digest(s) %
1400 buckets) == match)
1401 {
1402 v.push_back(std::string(
1403 s.data(), s.size()));
1404 if(v.size() >= collisions)
1405 break;
1406 }
1407 ++i;
1408 }
1409 }
1410
1411 // ensure collisions are distinguishable
1412 {
1413 o.clear();
1414 BOOST_TEST(
1415 (o.t_->digest(v[0]) % buckets) ==
1416 (o.t_->digest(v[1]) % buckets));
1417 BOOST_TEST(
1418 (o.t_->digest(v[1]) % buckets) ==
1419 (o.t_->digest(v[2]) % buckets));
1420 o.emplace(v[0], 1);
1421 o.emplace(v[1], 2);
1422 o.emplace(v[2], 3);
1423 BOOST_TEST(o.at(v[0]).to_number<int>() == 1);
1424 BOOST_TEST(o.at(v[1]).to_number<int>() == 2);
1425 BOOST_TEST(o.at(v[2]).to_number<int>() == 3);
1426 }
1427
1428 // erase k1
1429 {
1430 o.clear();
1431 o.emplace(v[0], 1);
1432 o.emplace(v[1], 2);
1433 o.emplace(v[2], 3);
1434 o.erase(v[0]);
1435 BOOST_TEST(o.at(v[1]).to_number<int>() == 2);
1436 BOOST_TEST(o.at(v[2]).to_number<int>() == 3);
1437 }
1438
1439 // erase k2
1440 {
1441 o.clear();
1442 o.emplace(v[0], 1);
1443 o.emplace(v[1], 2);
1444 o.emplace(v[2], 3);
1445 o.erase(v[1]);
1446 BOOST_TEST(o.at(v[0]).to_number<int>() == 1);
1447 BOOST_TEST(o.at(v[2]).to_number<int>() == 3);
1448 }
1449
1450 // erase k3
1451 {
1452 o.clear();
1453 o.emplace(v[0], 1);
1454 o.emplace(v[1], 2);
1455 o.emplace(v[2], 3);
1456 o.erase(v[2]);
1457 BOOST_TEST(o.at(v[0]).to_number<int>() == 1);
1458 BOOST_TEST(o.at(v[1]).to_number<int>() == 2);
1459 }
1460 }
1461
1462 void
1463 testEquality()
1464 {
1465 BOOST_TEST(object({}) == object({}));
1466 BOOST_TEST(object({}) != object({{"1",1},{"2",2}}));
1467 BOOST_TEST(object({{"1",1},{"2",2},{"3",3}}) == object({{"1",1},{"2",2},{"3",3}}));
1468 BOOST_TEST(object({{"1",1},{"2",2},{"3",3}}) != object({{"1",1},{"2",2}}));
1469 BOOST_TEST(object({{"1",1},{"2",2},{"3",3}}) == object({{"3",3},{"2",2},{"1",1}}));
1470 }
1471
1472 void
1473 run()
1474 {
1475 testDtor();
1476 testCtors();
1477 testIterators();
1478 testCapacity();
1479 testModifiers();
1480 testLookup();
1481 testHashPolicy();
1482 testImplementation();
1483 testCollisions();
1484 testEquality();
1485 }
1486};
1487
1488TEST_SUITE(object_test, "boost.json.object");
1489
1490BOOST_JSON_NS_END