rippled
Loading...
Searching...
No Matches
aged_associative_container_test.cpp
1#include <xrpl/beast/clock/manual_clock.h>
2#include <xrpl/beast/container/aged_map.h>
3#include <xrpl/beast/container/aged_multimap.h>
4#include <xrpl/beast/container/aged_multiset.h>
5#include <xrpl/beast/container/aged_set.h>
6#include <xrpl/beast/container/aged_unordered_map.h>
7#include <xrpl/beast/container/aged_unordered_multimap.h>
8#include <xrpl/beast/container/aged_unordered_multiset.h>
9#include <xrpl/beast/container/aged_unordered_set.h>
10#include <xrpl/beast/unit_test.h>
11
12#include <list>
13#include <vector>
14
15#ifndef BEAST_AGED_UNORDERED_NO_ALLOC_DEFAULTCTOR
16#ifdef _MSC_VER
17#define BEAST_AGED_UNORDERED_NO_ALLOC_DEFAULTCTOR 0
18#else
19#define BEAST_AGED_UNORDERED_NO_ALLOC_DEFAULTCTOR 1
20#endif
21#endif
22
23#ifndef BEAST_CONTAINER_EXTRACT_NOREF
24#ifdef _MSC_VER
25#define BEAST_CONTAINER_EXTRACT_NOREF 1
26#else
27#define BEAST_CONTAINER_EXTRACT_NOREF 1
28#endif
29#endif
30
31namespace beast {
32
34{
35public:
36 template <class T>
37 struct CompT
38 {
39 explicit CompT(int)
40 {
41 }
42
43 CompT(CompT const&)
44 {
45 }
46
47 bool
48 operator()(T const& lhs, T const& rhs) const
49 {
50 return m_less(lhs, rhs);
51 }
52
53 private:
54 CompT() = delete;
56 };
57
58 template <class T>
59 class HashT
60 {
61 public:
62 explicit HashT(int)
63 {
64 }
65
67 operator()(T const& t) const
68 {
69 return m_hash(t);
70 }
71
72 private:
73 HashT() = delete;
75 };
76
77 template <class T>
78 struct EqualT
79 {
80 public:
81 explicit EqualT(int)
82 {
83 }
84
85 bool
86 operator()(T const& lhs, T const& rhs) const
87 {
88 return m_eq(lhs, rhs);
89 }
90
91 private:
92 EqualT() = delete;
94 };
95
96 template <class T>
97 struct AllocT
98 {
99 using value_type = T;
100
101 // using std::true_type::type = propagate_on_container_swap :;
102
103 template <class U>
104 struct rebind
105 {
107 };
108
109 explicit AllocT(int)
110 {
111 }
112
113 AllocT(AllocT const&) = default;
114
115 template <class U>
117 {
118 }
119
120 template <class U>
121 bool
122 operator==(AllocT<U> const&) const
123 {
124 return true;
125 }
126
127 template <class U>
128 bool
129 operator!=(AllocT<U> const& o) const
130 {
131 return !(*this == o);
132 }
133
134 T*
135 allocate(std::size_t n, T const* = 0)
136 {
137 return static_cast<T*>(::operator new(n * sizeof(T)));
138 }
139
140 void
142 {
143 ::operator delete(p);
144 }
145
146#if !BEAST_AGED_UNORDERED_NO_ALLOC_DEFAULTCTOR
148 {
149 }
150#else
151 private:
152 AllocT() = delete;
153#endif
154 };
155
156 //--------------------------------------------------------------------------
157
158 // ordered
159 template <class Base, bool IsUnordered>
160 class MaybeUnordered : public Base
161 {
162 public:
165
166 protected:
167 static std::string
169 {
170 return "";
171 }
172 };
173
174 // unordered
175 template <class Base>
176 class MaybeUnordered<Base, true> : public Base
177 {
178 public:
183
184 protected:
185 static std::string
187 {
188 return "unordered_";
189 }
190 };
191
192 // unique
193 template <class Base, bool IsMulti>
194 class MaybeMulti : public Base
195 {
196 public:
197 protected:
198 static std::string
200 {
201 return "";
202 }
203 };
204
205 // multi
206 template <class Base>
207 class MaybeMulti<Base, true> : public Base
208 {
209 public:
210 protected:
211 static std::string
213 {
214 return "multi";
215 }
216 };
217
218 // set
219 template <class Base, bool IsMap>
220 class MaybeMap : public Base
221 {
222 public:
223 using T = void;
224 using Value = typename Base::Key;
226
227 static typename Base::Key const&
228 extract(Value const& value)
229 {
230 return value; // NOLINT(bugprone-return-const-ref-from-parameter)
231 }
232
233 static Values
235 {
236 Values v{
237 "apple",
238 "banana",
239 "cherry",
240 "grape",
241 "orange",
242 };
243 return v;
244 }
245
246 protected:
247 static std::string
249 {
250 return "set";
251 }
252 };
253
254 // map
255 template <class Base>
256 class MaybeMap<Base, true> : public Base
257 {
258 public:
259 using T = int;
262
263 static typename Base::Key const&
264 extract(Value const& value)
265 {
266 return value.first;
267 }
268
269 static Values
271 {
272 Values v{
273 std::make_pair("apple", 1),
274 std::make_pair("banana", 2),
275 std::make_pair("cherry", 3),
276 std::make_pair("grape", 4),
277 std::make_pair("orange", 5)};
278 return v;
279 }
280
281 protected:
282 static std::string
284 {
285 return "map";
286 }
287 };
288
289 //--------------------------------------------------------------------------
290
291 // ordered
292 template <class Base, bool IsUnordered = Base::is_unordered::value>
293 struct ContType
294 {
295 template <
296 class Compare = std::less<typename Base::Key>,
297 class Allocator = std::allocator<typename Base::Value>>
299 Base::is_multi::value,
300 Base::is_map::value,
301 typename Base::Key,
302 typename Base::T,
303 typename Base::Clock,
304 Compare,
305 Allocator>;
306 };
307
308 // unordered
309 template <class Base>
310 struct ContType<Base, true>
311 {
312 template <
314 class KeyEqual = std::equal_to<typename Base::Key>,
315 class Allocator = std::allocator<typename Base::Value>>
317 Base::is_multi::value,
318 Base::is_map::value,
319 typename Base::Key,
320 typename Base::T,
321 typename Base::Clock,
322 Hash,
323 KeyEqual,
324 Allocator>;
325 };
326
327 //--------------------------------------------------------------------------
328
335
336 template <bool IsUnordered, bool IsMulti, bool IsMap>
338 : MaybeUnordered<MaybeMulti<MaybeMap<TestTraitsBase, IsMap>, IsMulti>, IsUnordered>
339 {
340 private:
341 using Base =
343
344 public:
345 using typename Base::Key;
346
350
353
354 static std::string
356 {
359 }
360 };
361
362 template <bool IsUnordered, bool IsMulti, bool IsMap>
363 struct TestTraits : TestTraitsHelper<IsUnordered, IsMulti, IsMap>,
364 ContType<TestTraitsHelper<IsUnordered, IsMulti, IsMap>>
365 {
366 };
367
368 template <class Cont>
369 static std::string
374
375 template <class Traits>
377 {
378 bool
379 operator()(typename Traits::Value const& lhs, typename Traits::Value const& rhs)
380 {
381 return Traits::extract(lhs) == Traits::extract(rhs);
382 }
383 };
384
385 template <class Cont>
387 make_list(Cont const& c)
388 {
389 return std::vector<typename Cont::value_type>(c.begin(), c.end());
390 }
391
392 //--------------------------------------------------------------------------
393
394 template <class Container, class Values>
396 checkMapContents(Container& c, Values const& v);
397
398 template <class Container, class Values>
399 typename std::enable_if<!(Container::is_map::value && !Container::is_multi::value)>::type
400 checkMapContents(Container, Values const&)
401 {
402 }
403
404 // unordered
405 template <class C, class Values>
407 checkUnorderedContentsRefRef(C&& c, Values const& v);
408
409 template <class C, class Values>
412 {
413 }
414
415 template <class C, class Values>
416 void
417 checkContentsRefRef(C&& c, Values const& v);
418
419 template <class Cont, class Values>
420 void
421 checkContents(Cont& c, Values const& v);
422
423 template <class Cont>
424 void
425 checkContents(Cont& c);
426
427 //--------------------------------------------------------------------------
428
429 // ordered
430 template <bool IsUnordered, bool IsMulti, bool IsMap>
433
434 // unordered
435 template <bool IsUnordered, bool IsMulti, bool IsMap>
438
439 // ordered
440 template <bool IsUnordered, bool IsMulti, bool IsMap>
443
444 // unordered
445 template <bool IsUnordered, bool IsMulti, bool IsMap>
448
449 // ordered
450 template <bool IsUnordered, bool IsMulti, bool IsMap>
453
454 // unordered
455 template <bool IsUnordered, bool IsMulti, bool IsMap>
458
459 //--------------------------------------------------------------------------
460
461 template <bool IsUnordered, bool IsMulti, bool IsMap>
462 void
463 testCopyMove();
464
465 //--------------------------------------------------------------------------
466
467 template <bool IsUnordered, bool IsMulti, bool IsMap>
468 void
469 testIterator();
470
471 // Unordered containers don't have reverse iterators
472 template <bool IsUnordered, bool IsMulti, bool IsMap>
475
476 template <bool IsUnordered, bool IsMulti, bool IsMap>
479 {
480 }
481
482 //--------------------------------------------------------------------------
483
484 template <class Container, class Values>
485 void
486 checkInsertCopy(Container& c, Values const& v);
487
488 template <class Container, class Values>
489 void
490 checkInsertMove(Container& c, Values const& v);
491
492 template <class Container, class Values>
493 void
494 checkInsertHintCopy(Container& c, Values const& v);
495
496 template <class Container, class Values>
497 void
498 checkInsertHintMove(Container& c, Values const& v);
499
500 template <class Container, class Values>
501 void
502 checkEmplace(Container& c, Values const& v);
503
504 template <class Container, class Values>
505 void
506 checkEmplaceHint(Container& c, Values const& v);
507
508 template <bool IsUnordered, bool IsMulti, bool IsMap>
509 void
511
512 //--------------------------------------------------------------------------
513
514 template <bool IsUnordered, bool IsMulti, bool IsMap>
515 void
517
518 //--------------------------------------------------------------------------
519
520 // map, unordered_map
521 template <bool IsUnordered, bool IsMulti, bool IsMap>
524
525 template <bool IsUnordered, bool IsMulti, bool IsMap>
528 {
529 }
530
531 //--------------------------------------------------------------------------
532
533 // Helpers for erase tests
534 template <class Container, class Values>
535 void
536 reverseFillAgedContainer(Container& c, Values const& v);
537
538 template <class Iter>
539 Iter
540 nextToEndIter(Iter const beginIter, Iter const endItr);
541
542 //--------------------------------------------------------------------------
543
544 template <class Container, class Iter>
545 bool
546 doElementErase(Container& c, Iter const beginItr, Iter const endItr);
547
548 template <bool IsUnordered, bool IsMulti, bool IsMap>
549 void
551
552 //--------------------------------------------------------------------------
553
554 template <class Container, class BeginEndSrc>
555 void
556 doRangeErase(Container& c, BeginEndSrc const& beginEndSrc);
557
558 template <bool IsUnordered, bool IsMulti, bool IsMap>
559 void
561
562 //--------------------------------------------------------------------------
563
564 // ordered
565 template <bool IsUnordered, bool IsMulti, bool IsMap>
567 testCompare();
568
569 template <bool IsUnordered, bool IsMulti, bool IsMap>
572 {
573 }
574
575 //--------------------------------------------------------------------------
576
577 // ordered
578 template <bool IsUnordered, bool IsMulti, bool IsMap>
581
582 // unordered
583 template <bool IsUnordered, bool IsMulti, bool IsMap>
586
587 //--------------------------------------------------------------------------
588
589 template <bool IsUnordered, bool IsMulti, bool IsMap>
590 void
592
593 template <bool IsUnordered, bool IsMulti>
594 void
596
597 template <bool IsUnordered>
598 void
600};
601
602//------------------------------------------------------------------------------
603
604// Check contents via at() and operator[]
605// map, unordered_map
606template <class Container, class Values>
609{
610 if (v.empty())
611 {
612 BEAST_EXPECT(c.empty());
613 BEAST_EXPECT(c.size() == 0);
614 return;
615 }
616
617 try
618 {
619 // Make sure no exception is thrown
620 for (auto const& e : v)
621 c.at(e.first);
622 for (auto const& e : v)
623 BEAST_EXPECT(c.operator[](e.first) == e.second);
624 }
625 catch (std::out_of_range const&)
626 {
627 fail("caught exception");
628 }
629}
630
631// unordered
632template <class C, class Values>
635{
636 using Cont = typename std::remove_reference<C>::type;
637 using Traits =
639 using size_type = typename Cont::size_type;
640 auto const hash(c.hash_function());
641 auto const key_eq(c.key_eq());
642 for (size_type i(0); i < c.bucket_count(); ++i)
643 {
644 auto const last(c.end(i));
645 for (auto iter(c.begin(i)); iter != last; ++iter)
646 {
647 auto const match(
648 std::find_if(v.begin(), v.end(), [iter](typename Values::value_type const& e) {
649 return Traits::extract(*iter) == Traits::extract(e);
650 }));
651 BEAST_EXPECT(match != v.end());
652 BEAST_EXPECT(key_eq(Traits::extract(*iter), Traits::extract(*match)));
653 BEAST_EXPECT(hash(Traits::extract(*iter)) == hash(Traits::extract(*match)));
654 }
655 }
656}
657
658template <class C, class Values>
659void
661{
662 using Cont = typename std::remove_reference<C>::type;
663 using size_type = typename Cont::size_type;
664
665 BEAST_EXPECT(c.size() == v.size());
666 BEAST_EXPECT(size_type(std::distance(c.begin(), c.end())) == v.size());
667 BEAST_EXPECT(size_type(std::distance(c.cbegin(), c.cend())) == v.size());
668 BEAST_EXPECT(
669 size_type(std::distance(c.chronological.begin(), c.chronological.end())) == v.size());
670 BEAST_EXPECT(
671 size_type(std::distance(c.chronological.cbegin(), c.chronological.cend())) == v.size());
672 BEAST_EXPECT(
673 size_type(std::distance(c.chronological.rbegin(), c.chronological.rend())) == v.size());
674 BEAST_EXPECT(
675 size_type(std::distance(c.chronological.crbegin(), c.chronological.crend())) == v.size());
676
678}
679
680template <class Cont, class Values>
681void
683{
685 checkContentsRefRef(const_cast<Cont const&>(c), v);
686 checkMapContents(c, v);
687}
688
689template <class Cont>
690void
692{
693 using Traits =
695 using Values = typename Traits::Values;
696 checkContents(c, Values());
697}
698
699//------------------------------------------------------------------------------
700//
701// Construction
702//
703//------------------------------------------------------------------------------
704
705// ordered
706template <bool IsUnordered, bool IsMulti, bool IsMap>
709{
711 using Comp = typename Traits::Comp;
712 using Alloc = typename Traits::Alloc;
713 using MyComp = typename Traits::MyComp;
714 using MyAlloc = typename Traits::MyAlloc;
715 typename Traits::ManualClock clock;
716
717 // testcase (Traits::name() + " empty");
718 testcase("empty");
719
720 {
721 typename Traits::template Cont<Comp, Alloc> c(clock);
722 checkContents(c);
723 }
724
725 {
726 typename Traits::template Cont<MyComp, Alloc> c(clock, MyComp(1));
727 checkContents(c);
728 }
729
730 {
731 typename Traits::template Cont<Comp, MyAlloc> c(clock, MyAlloc(1));
732 checkContents(c);
733 }
734
735 {
736 typename Traits::template Cont<MyComp, MyAlloc> c(clock, MyComp(1), MyAlloc(1));
737 checkContents(c);
738 }
739}
740
741// unordered
742template <bool IsUnordered, bool IsMulti, bool IsMap>
745{
746 using Traits = TestTraits<IsUnordered, IsMulti, IsMap>;
747 using Hash = typename Traits::Hash;
748 using Equal = typename Traits::Equal;
749 using Alloc = typename Traits::Alloc;
750 using MyHash = typename Traits::MyHash;
751 using MyEqual = typename Traits::MyEqual;
752 using MyAlloc = typename Traits::MyAlloc;
753 typename Traits::ManualClock clock;
754
755 // testcase (Traits::name() + " empty");
756 testcase("empty");
757 {
758 typename Traits::template Cont<Hash, Equal, Alloc> c(clock);
759 checkContents(c);
760 }
761
762 {
763 typename Traits::template Cont<MyHash, Equal, Alloc> c(clock, MyHash(1));
764 checkContents(c);
765 }
766
767 {
768 typename Traits::template Cont<Hash, MyEqual, Alloc> c(clock, MyEqual(1));
769 checkContents(c);
770 }
771
772 {
773 typename Traits::template Cont<Hash, Equal, MyAlloc> c(clock, MyAlloc(1));
774 checkContents(c);
775 }
776
777 {
778 typename Traits::template Cont<MyHash, MyEqual, Alloc> c(clock, MyHash(1), MyEqual(1));
779 checkContents(c);
780 }
781
782 {
783 typename Traits::template Cont<MyHash, Equal, MyAlloc> c(clock, MyHash(1), MyAlloc(1));
784 checkContents(c);
785 }
786
787 {
788 typename Traits::template Cont<Hash, MyEqual, MyAlloc> c(clock, MyEqual(1), MyAlloc(1));
789 checkContents(c);
790 }
791
792 {
793 typename Traits::template Cont<MyHash, MyEqual, MyAlloc> c(
794 clock, MyHash(1), MyEqual(1), MyAlloc(1));
795 checkContents(c);
796 }
797}
798
799// ordered
800template <bool IsUnordered, bool IsMulti, bool IsMap>
803{
805 using Comp = typename Traits::Comp;
806 using Alloc = typename Traits::Alloc;
807 using MyComp = typename Traits::MyComp;
808 using MyAlloc = typename Traits::MyAlloc;
809 typename Traits::ManualClock clock;
810 auto const v(Traits::values());
811
812 // testcase (Traits::name() + " range");
813 testcase("range");
814
815 {
816 typename Traits::template Cont<Comp, Alloc> c(v.begin(), v.end(), clock);
817 checkContents(c, v);
818 }
819
820 {
821 typename Traits::template Cont<MyComp, Alloc> c(v.begin(), v.end(), clock, MyComp(1));
822 checkContents(c, v);
823 }
824
825 {
826 typename Traits::template Cont<Comp, MyAlloc> c(v.begin(), v.end(), clock, MyAlloc(1));
827 checkContents(c, v);
828 }
829
830 {
831 typename Traits::template Cont<MyComp, MyAlloc> c(
832 v.begin(), v.end(), clock, MyComp(1), MyAlloc(1));
833 checkContents(c, v);
834 }
835
836 // swap
837
838 {
839 typename Traits::template Cont<Comp, Alloc> c1(v.begin(), v.end(), clock);
840 typename Traits::template Cont<Comp, Alloc> c2(clock);
841 std::swap(c1, c2);
842 checkContents(c2, v);
843 }
844}
845
846// unordered
847template <bool IsUnordered, bool IsMulti, bool IsMap>
850{
851 using Traits = TestTraits<IsUnordered, IsMulti, IsMap>;
852 using Hash = typename Traits::Hash;
853 using Equal = typename Traits::Equal;
854 using Alloc = typename Traits::Alloc;
855 using MyHash = typename Traits::MyHash;
856 using MyEqual = typename Traits::MyEqual;
857 using MyAlloc = typename Traits::MyAlloc;
858 typename Traits::ManualClock clock;
859 auto const v(Traits::values());
860
861 // testcase (Traits::name() + " range");
862 testcase("range");
863
864 {
865 typename Traits::template Cont<Hash, Equal, Alloc> c(v.begin(), v.end(), clock);
866 checkContents(c, v);
867 }
868
869 {
870 typename Traits::template Cont<MyHash, Equal, Alloc> c(
871 v.begin(), v.end(), clock, MyHash(1));
872 checkContents(c, v);
873 }
874
875 {
876 typename Traits::template Cont<Hash, MyEqual, Alloc> c(
877 v.begin(), v.end(), clock, MyEqual(1));
878 checkContents(c, v);
879 }
880
881 {
882 typename Traits::template Cont<Hash, Equal, MyAlloc> c(
883 v.begin(), v.end(), clock, MyAlloc(1));
884 checkContents(c, v);
885 }
886
887 {
888 typename Traits::template Cont<MyHash, MyEqual, Alloc> c(
889 v.begin(), v.end(), clock, MyHash(1), MyEqual(1));
890 checkContents(c, v);
891 }
892
893 {
894 typename Traits::template Cont<MyHash, Equal, MyAlloc> c(
895 v.begin(), v.end(), clock, MyHash(1), MyAlloc(1));
896 checkContents(c, v);
897 }
898
899 {
900 typename Traits::template Cont<Hash, MyEqual, MyAlloc> c(
901 v.begin(), v.end(), clock, MyEqual(1), MyAlloc(1));
902 checkContents(c, v);
903 }
904
905 {
906 typename Traits::template Cont<MyHash, MyEqual, MyAlloc> c(
907 v.begin(), v.end(), clock, MyHash(1), MyEqual(1), MyAlloc(1));
908 checkContents(c, v);
909 }
910}
911
912// ordered
913template <bool IsUnordered, bool IsMulti, bool IsMap>
916{
918 typename Traits::ManualClock const clock;
919
920 // testcase (Traits::name() + " init-list");
921 testcase("init-list");
922
923 // VFALCO TODO
924
925 pass();
926}
927
928// unordered
929template <bool IsUnordered, bool IsMulti, bool IsMap>
932{
933 using Traits = TestTraits<IsUnordered, IsMulti, IsMap>;
934 typename Traits::ManualClock const clock;
935
936 // testcase (Traits::name() + " init-list");
937 testcase("init-list");
938
939 // VFALCO TODO
940 pass();
941}
942
943//------------------------------------------------------------------------------
944//
945// Copy/Move construction and assign
946//
947//------------------------------------------------------------------------------
948
949template <bool IsUnordered, bool IsMulti, bool IsMap>
950void
952{
954 using Alloc = typename Traits::Alloc;
955 typename Traits::ManualClock clock;
956 auto const v(Traits::values());
957
958 // testcase (Traits::name() + " copy/move");
959 testcase("copy/move");
960
961 // copy
962
963 {
964 typename Traits::template Cont<> c(v.begin(), v.end(), clock);
965 typename Traits::template Cont<> c2(c);
966 checkContents(c, v);
967 checkContents(c2, v);
968 BEAST_EXPECT(c == c2);
969 unexpected(c != c2);
970 }
971
972 {
973 typename Traits::template Cont<> c(v.begin(), v.end(), clock);
974 typename Traits::template Cont<> c2(c, Alloc());
975 checkContents(c, v);
976 checkContents(c2, v);
977 BEAST_EXPECT(c == c2);
978 unexpected(c != c2);
979 }
980
981 {
982 typename Traits::template Cont<> c(v.begin(), v.end(), clock);
983 typename Traits::template Cont<> c2(clock);
984 c2 = c;
985 checkContents(c, v);
986 checkContents(c2, v);
987 BEAST_EXPECT(c == c2);
988 unexpected(c != c2);
989 }
990
991 // move
992
993 {
994 typename Traits::template Cont<> c(v.begin(), v.end(), clock);
995 typename Traits::template Cont<> c2(std::move(c));
996 checkContents(c2, v);
997 }
998
999 {
1000 typename Traits::template Cont<> c(v.begin(), v.end(), clock);
1001 typename Traits::template Cont<> c2(std::move(c), Alloc());
1002 checkContents(c2, v);
1003 }
1004
1005 {
1006 typename Traits::template Cont<> c(v.begin(), v.end(), clock);
1007 typename Traits::template Cont<> c2(clock);
1008 c2 = std::move(c);
1009 checkContents(c2, v);
1010 }
1011}
1012
1013//------------------------------------------------------------------------------
1014//
1015// Iterator construction and assignment
1016//
1017//------------------------------------------------------------------------------
1018
1019template <bool IsUnordered, bool IsMulti, bool IsMap>
1020void
1022{
1024 typename Traits::ManualClock clock;
1025 auto const v(Traits::values());
1026
1027 // testcase (Traits::name() + " iterators");
1028 testcase("iterator");
1029
1030 typename Traits::template Cont<> c{clock};
1031
1032 using iterator = decltype(c.begin());
1033 using const_iterator = decltype(c.cbegin());
1034
1035 // Should be able to construct or assign an iterator from an iterator.
1036 iterator const nnIt_0{c.begin()};
1037 iterator const nnIt_1{nnIt_0};
1038 BEAST_EXPECT(nnIt_0 == nnIt_1);
1039 iterator nnIt_2;
1040 nnIt_2 = nnIt_1;
1041 BEAST_EXPECT(nnIt_1 == nnIt_2);
1042
1043 // Should be able to construct or assign a const_iterator from a
1044 // const_iterator.
1045 const_iterator const ccIt_0{c.cbegin()};
1046 const_iterator const ccIt_1{ccIt_0};
1047 BEAST_EXPECT(ccIt_0 == ccIt_1);
1048 const_iterator ccIt_2;
1049 ccIt_2 = ccIt_1;
1050 BEAST_EXPECT(ccIt_1 == ccIt_2);
1051
1052 // Comparison between iterator and const_iterator is okay
1053 BEAST_EXPECT(nnIt_0 == ccIt_0);
1054 BEAST_EXPECT(ccIt_1 == nnIt_1);
1055
1056 // Should be able to construct a const_iterator from an iterator.
1057 const_iterator const ncIt_3{c.begin()};
1058 const_iterator const ncIt_4{nnIt_0};
1059 BEAST_EXPECT(ncIt_3 == ncIt_4);
1060 const_iterator ncIt_5;
1061 ncIt_5 = nnIt_2;
1062 BEAST_EXPECT(ncIt_5 == ncIt_4);
1063
1064 // None of these should compile because they construct or assign to a
1065 // non-const iterator with a const_iterator.
1066
1067 // iterator cnIt_0 {c.cbegin()};
1068
1069 // iterator cnIt_1 {ccIt_0};
1070
1071 // iterator cnIt_2;
1072 // cnIt_2 = ccIt_2;
1073}
1074
1075template <bool IsUnordered, bool IsMulti, bool IsMap>
1078{
1080 typename Traits::ManualClock clock;
1081 auto const v(Traits::values());
1082
1083 // testcase (Traits::name() + " reverse_iterators");
1084 testcase("reverse_iterator");
1085
1086 typename Traits::template Cont<> c{clock};
1087
1088 using iterator = decltype(c.begin());
1089 using reverse_iterator = decltype(c.rbegin());
1090 using const_reverse_iterator = decltype(c.crbegin());
1091
1092 // Naming decoder ring
1093 // constructed from ------+ +----- constructed type
1094 // /\/\ -- character pairs
1095 // xAyBit
1096 // r (reverse) or f (forward)--^-^
1097 // ^-^------ C (const) or N (non-const)
1098
1099 // Should be able to construct or assign a reverse_iterator from a
1100 // reverse_iterator.
1101 reverse_iterator const rNrNit_0{c.rbegin()};
1102 reverse_iterator const rNrNit_1{rNrNit_0};
1103 BEAST_EXPECT(rNrNit_0 == rNrNit_1);
1104 reverse_iterator xXrNit_2;
1105 xXrNit_2 = rNrNit_1;
1106 BEAST_EXPECT(rNrNit_1 == xXrNit_2);
1107
1108 // Should be able to construct or assign a const_reverse_iterator from a
1109 // const_reverse_iterator
1110 const_reverse_iterator const rCrCit_0{c.crbegin()};
1111 const_reverse_iterator const rCrCit_1{rCrCit_0};
1112 BEAST_EXPECT(rCrCit_0 == rCrCit_1);
1113 const_reverse_iterator xXrCit_2;
1114 xXrCit_2 = rCrCit_1;
1115 BEAST_EXPECT(rCrCit_1 == xXrCit_2);
1116
1117 // Comparison between reverse_iterator and const_reverse_iterator is okay
1118 BEAST_EXPECT(rNrNit_0 == rCrCit_0);
1119 BEAST_EXPECT(rCrCit_1 == rNrNit_1);
1120
1121 // Should be able to construct or assign a const_reverse_iterator from a
1122 // reverse_iterator
1123 const_reverse_iterator const rNrCit_0{c.rbegin()};
1124 const_reverse_iterator const rNrCit_1{rNrNit_0};
1125 BEAST_EXPECT(rNrCit_0 == rNrCit_1);
1126 xXrCit_2 = rNrNit_1;
1127 BEAST_EXPECT(rNrCit_1 == xXrCit_2);
1128
1129 // The standard allows these conversions:
1130 // o reverse_iterator is explicitly constructible from iterator.
1131 // o const_reverse_iterator is explicitly constructible from
1132 // const_iterator.
1133 // Should be able to construct or assign reverse_iterators from
1134 // non-reverse iterators.
1135 reverse_iterator const fNrNit_0{c.begin()};
1136 const_reverse_iterator const fNrCit_0{c.begin()};
1137 BEAST_EXPECT(fNrNit_0 == fNrCit_0);
1138 const_reverse_iterator const fCrCit_0{c.cbegin()};
1139 BEAST_EXPECT(fNrCit_0 == fCrCit_0);
1140
1141 // None of these should compile because they construct a non-reverse
1142 // iterator from a reverse_iterator.
1143 // iterator rNfNit_0 {c.rbegin()};
1144 // const_iterator rNfCit_0 {c.rbegin()};
1145 // const_iterator rCfCit_0 {c.crbegin()};
1146
1147 // You should not be able to assign an iterator to a reverse_iterator or
1148 // vise-versa. So the following lines should not compile.
1149 iterator const xXfNit_0;
1150 // xXfNit_0 = xXrNit_2;
1151 // xXrNit_2 = xXfNit_0;
1152}
1153
1154//------------------------------------------------------------------------------
1155//
1156// Modifiers
1157//
1158//------------------------------------------------------------------------------
1159
1160template <class Container, class Values>
1161void
1163{
1164 for (auto const& e : v)
1165 c.insert(e);
1166 checkContents(c, v);
1167}
1168
1169template <class Container, class Values>
1170void
1172{
1173 Values v2(v);
1174 for (auto& e : v2)
1175 c.insert(std::move(e));
1176 checkContents(c, v);
1177}
1178
1179template <class Container, class Values>
1180void
1182{
1183 for (auto const& e : v)
1184 c.insert(c.cend(), e);
1185 checkContents(c, v);
1186}
1187
1188template <class Container, class Values>
1189void
1191{
1192 Values v2(v);
1193 for (auto& e : v2)
1194 c.insert(c.cend(), std::move(e));
1195 checkContents(c, v);
1196}
1197
1198template <class Container, class Values>
1199void
1201{
1202 for (auto const& e : v)
1203 c.emplace(e);
1204 checkContents(c, v);
1205}
1206
1207template <class Container, class Values>
1208void
1210{
1211 for (auto const& e : v)
1212 c.emplace_hint(c.cend(), e);
1213 checkContents(c, v);
1214}
1215
1216template <bool IsUnordered, bool IsMulti, bool IsMap>
1217void
1219{
1221 typename Traits::ManualClock clock;
1222 auto const v(Traits::values());
1223 auto const l(make_list(v));
1224
1225 // testcase (Traits::name() + " modify");
1226 testcase("modify");
1227
1228 {
1229 typename Traits::template Cont<> c(clock);
1230 checkInsertCopy(c, v);
1231 }
1232
1233 {
1234 typename Traits::template Cont<> c(clock);
1235 checkInsertCopy(c, l);
1236 }
1237
1238 {
1239 typename Traits::template Cont<> c(clock);
1240 checkInsertMove(c, v);
1241 }
1242
1243 {
1244 typename Traits::template Cont<> c(clock);
1245 checkInsertMove(c, l);
1246 }
1247
1248 {
1249 typename Traits::template Cont<> c(clock);
1250 checkInsertHintCopy(c, v);
1251 }
1252
1253 {
1254 typename Traits::template Cont<> c(clock);
1255 checkInsertHintCopy(c, l);
1256 }
1257
1258 {
1259 typename Traits::template Cont<> c(clock);
1260 checkInsertHintMove(c, v);
1261 }
1262
1263 {
1264 typename Traits::template Cont<> c(clock);
1265 checkInsertHintMove(c, l);
1266 }
1267}
1268
1269//------------------------------------------------------------------------------
1270//
1271// Chronological ordering
1272//
1273//------------------------------------------------------------------------------
1274
1275template <bool IsUnordered, bool IsMulti, bool IsMap>
1276void
1278{
1280 typename Traits::ManualClock clock;
1281 auto const v(Traits::values());
1282
1283 // testcase (Traits::name() + " chronological");
1284 testcase("chronological");
1285
1286 typename Traits::template Cont<> c(v.begin(), v.end(), clock);
1287
1288 BEAST_EXPECT(
1289 std::equal(
1290 c.chronological.cbegin(),
1291 c.chronological.cend(),
1292 v.begin(),
1293 v.end(),
1295
1296 // Test touch() with a non-const iterator.
1297 for (auto iter(v.crbegin()); iter != v.crend(); ++iter)
1298 {
1299 using iterator = typename decltype(c)::iterator;
1300 iterator const found(c.find(Traits::extract(*iter)));
1301
1302 BEAST_EXPECT(found != c.cend());
1303 if (found == c.cend())
1304 return;
1305 c.touch(found);
1306 }
1307
1308 BEAST_EXPECT(
1309 std::equal(
1310 c.chronological.cbegin(),
1311 c.chronological.cend(),
1312 v.crbegin(),
1313 v.crend(),
1315
1316 // Test touch() with a const_iterator
1317 for (auto iter(v.cbegin()); iter != v.cend(); ++iter)
1318 {
1319 using const_iterator = typename decltype(c)::const_iterator;
1320 const_iterator const found(c.find(Traits::extract(*iter)));
1321
1322 BEAST_EXPECT(found != c.cend());
1323 if (found == c.cend())
1324 return;
1325 c.touch(found);
1326 }
1327
1328 BEAST_EXPECT(
1329 std::equal(
1330 c.chronological.cbegin(),
1331 c.chronological.cend(),
1332 v.cbegin(),
1333 v.cend(),
1335
1336 {
1337 // Because touch (reverse_iterator pos) is not allowed, the following
1338 // lines should not compile for any aged_container type.
1339 // c.touch (c.rbegin());
1340 // c.touch (c.crbegin());
1341 }
1342}
1343
1344//------------------------------------------------------------------------------
1345//
1346// Element creation via operator[]
1347//
1348//------------------------------------------------------------------------------
1349
1350// map, unordered_map
1351template <bool IsUnordered, bool IsMulti, bool IsMap>
1354{
1356 typename Traits::ManualClock clock;
1357 auto v(Traits::values());
1358
1359 // testcase (Traits::name() + " array create");
1360 testcase("array create");
1361
1362 {
1363 // Copy construct key
1364 typename Traits::template Cont<> c(clock);
1365 for (auto const& e : v)
1366 c[e.first] = e.second;
1367 checkContents(c, v);
1368 }
1369
1370 {
1371 // Move construct key
1372 typename Traits::template Cont<> c(clock);
1373 for (auto e : v)
1374 c[std::move(e.first)] = e.second;
1375 checkContents(c, v);
1376 }
1377}
1378
1379//------------------------------------------------------------------------------
1380//
1381// Helpers for erase tests
1382//
1383//------------------------------------------------------------------------------
1384
1385template <class Container, class Values>
1386void
1388{
1389 // Just in case the passed in container was not empty.
1390 c.clear();
1391
1392 // c.clock() returns an abstract_clock, so dynamic_cast to manual_clock.
1393 // VFALCO NOTE This is sketchy
1394 using ManualClock = TestTraitsBase::ManualClock;
1395 ManualClock& clk(dynamic_cast<ManualClock&>(c.clock()));
1396 clk.set(0);
1397
1398 Values rev(values);
1399 std::sort(rev.begin(), rev.end());
1400 std::reverse(rev.begin(), rev.end());
1401 for (auto& v : rev)
1402 {
1403 // Add values in reverse order so they are reversed chronologically.
1404 ++clk;
1405 c.insert(v);
1406 }
1407}
1408
1409// Get one iterator before endIter. We have to use operator++ because you
1410// cannot use operator-- with unordered container iterators.
1411template <class Iter>
1412Iter
1414{
1415 if (beginIter == endIter)
1416 {
1417 fail("Internal test failure. Cannot advance beginIter");
1418 return beginIter;
1419 }
1420
1421 //
1422 Iter nextToEnd = beginIter;
1423 do
1424 {
1425 nextToEnd = beginIter++;
1426 } while (beginIter != endIter);
1427 return nextToEnd;
1428}
1429
1430// Implementation for the element erase tests
1431//
1432// This test accepts:
1433// o the container from which we will erase elements
1434// o iterators into that container defining the range of the erase
1435//
1436// This implementation does not declare a pass, since it wants to allow
1437// the caller to examine the size of the container and the returned iterator
1438//
1439// Note that this test works on the aged_associative containers because an
1440// erase only invalidates references and iterators to the erased element
1441// (see 23.2.4/13). Therefore the passed-in end iterator stays valid through
1442// the whole test.
1443template <class Container, class Iter>
1444bool
1446 Container& c,
1447 Iter const beginItr,
1448 Iter const endItr)
1449{
1450 auto it(beginItr);
1451 size_t count = c.size();
1452 while (it != endItr)
1453 {
1454 auto expectIt = it;
1455 ++expectIt;
1456 it = c.erase(it);
1457
1458 if (it != expectIt)
1459 {
1460 fail("Unexpected returned iterator from element erase");
1461 return false;
1462 }
1463
1464 --count;
1465 if (count != c.size())
1466 {
1467 fail("Failed to erase element");
1468 return false;
1469 }
1470
1471 if (c.empty())
1472 {
1473 if (it != endItr)
1474 {
1475 fail("Erase of last element didn't produce end");
1476 return false;
1477 }
1478 }
1479 }
1480 return true;
1481}
1482
1483//------------------------------------------------------------------------------
1484//
1485// Erase of individual elements
1486//
1487//------------------------------------------------------------------------------
1488
1489template <bool IsUnordered, bool IsMulti, bool IsMap>
1490void
1492{
1494
1495 // testcase (Traits::name() + " element erase"
1496 testcase("element erase");
1497
1498 // Make and fill the container
1499 typename Traits::ManualClock clock;
1500 typename Traits::template Cont<> c{clock};
1501 reverseFillAgedContainer(c, Traits::values());
1502
1503 {
1504 // Test standard iterators
1505 auto tempContainer(c);
1506 if (!doElementErase(tempContainer, tempContainer.cbegin(), tempContainer.cend()))
1507 return; // Test failed
1508
1509 BEAST_EXPECT(tempContainer.empty());
1510 pass();
1511 }
1512 {
1513 // Test chronological iterators
1514 auto tempContainer(c);
1515 auto& chron(tempContainer.chronological);
1516 if (!doElementErase(tempContainer, chron.begin(), chron.end()))
1517 return; // Test failed
1518
1519 BEAST_EXPECT(tempContainer.empty());
1520 pass();
1521 }
1522 {
1523 // Test standard iterator partial erase
1524 auto tempContainer(c);
1525 BEAST_EXPECT(tempContainer.size() > 2);
1526 if (!doElementErase(
1527 tempContainer,
1528 ++tempContainer.begin(),
1529 nextToEndIter(tempContainer.begin(), tempContainer.end())))
1530 return; // Test failed
1531
1532 BEAST_EXPECT(tempContainer.size() == 2);
1533 pass();
1534 }
1535 {
1536 // Test chronological iterator partial erase
1537 auto tempContainer(c);
1538 BEAST_EXPECT(tempContainer.size() > 2);
1539 auto& chron(tempContainer.chronological);
1540 if (!doElementErase(
1541 tempContainer, ++chron.begin(), nextToEndIter(chron.begin(), chron.end())))
1542 return; // Test failed
1543
1544 BEAST_EXPECT(tempContainer.size() == 2);
1545 pass();
1546 }
1547 {
1548 auto tempContainer(c);
1549 BEAST_EXPECT(tempContainer.size() > 4);
1550 // erase(reverse_iterator) is not allowed. None of the following
1551 // should compile for any aged_container type.
1552 // c.erase (c.rbegin());
1553 // c.erase (c.crbegin());
1554 // c.erase(c.rbegin(), ++c.rbegin());
1555 // c.erase(c.crbegin(), ++c.crbegin());
1556 }
1557}
1558
1559// Implementation for the range erase tests
1560//
1561// This test accepts:
1562//
1563// o A container with more than 2 elements and
1564// o An object to ask for begin() and end() iterators in the passed container
1565//
1566// This peculiar interface allows either the container itself to be passed as
1567// the second argument or the container's "chronological" element. Both
1568// sources of iterators need to be tested on the container.
1569//
1570// The test locates iterators such that a range-based delete leaves the first
1571// and last elements in the container. It then validates that the container
1572// ended up with the expected contents.
1573//
1574template <class Container, class BeginEndSrc>
1575void
1576aged_associative_container_test_base::doRangeErase(Container& c, BeginEndSrc const& beginEndSrc)
1577{
1578 BEAST_EXPECT(c.size() > 2);
1579 auto itBeginPlusOne(beginEndSrc.begin());
1580 auto const valueFront = *itBeginPlusOne;
1581 ++itBeginPlusOne;
1582
1583 // Get one iterator before end()
1584 auto itBack(nextToEndIter(itBeginPlusOne, beginEndSrc.end()));
1585 auto const valueBack = *itBack;
1586
1587 // Erase all elements but first and last
1588 auto const retIter = c.erase(itBeginPlusOne, itBack);
1589
1590 BEAST_EXPECT(c.size() == 2);
1591 BEAST_EXPECT(valueFront == *(beginEndSrc.begin()));
1592 BEAST_EXPECT(valueBack == *(++beginEndSrc.begin()));
1593 BEAST_EXPECT(retIter == (++beginEndSrc.begin()));
1594}
1595
1596//------------------------------------------------------------------------------
1597//
1598// Erase range of elements
1599//
1600//------------------------------------------------------------------------------
1601
1602template <bool IsUnordered, bool IsMulti, bool IsMap>
1603void
1605{
1607
1608 // testcase (Traits::name() + " element erase"
1609 testcase("range erase");
1610
1611 // Make and fill the container
1612 typename Traits::ManualClock clock;
1613 typename Traits::template Cont<> c{clock};
1614 reverseFillAgedContainer(c, Traits::values());
1615
1616 // Not bothering to test range erase with reverse iterators.
1617 {
1618 auto tempContainer(c);
1619 doRangeErase(tempContainer, tempContainer);
1620 }
1621 {
1622 auto tempContainer(c);
1623 doRangeErase(tempContainer, tempContainer.chronological);
1624 }
1625}
1626
1627//------------------------------------------------------------------------------
1628//
1629// Container-wide comparison
1630//
1631//------------------------------------------------------------------------------
1632
1633// ordered
1634template <bool IsUnordered, bool IsMulti, bool IsMap>
1637{
1639 typename Traits::ManualClock clock;
1640 auto const v(Traits::values());
1641
1642 // testcase (Traits::name() + " array create");
1643 testcase("array create");
1644
1645 typename Traits::template Cont<> const c1(v.begin(), v.end(), clock);
1646
1647 typename Traits::template Cont<> c2(v.begin(), v.end(), clock);
1648 c2.erase(c2.cbegin());
1649
1650 expect(c1 != c2);
1651 unexpected(c1 == c2);
1652 expect(c1 < c2);
1653 expect(c1 <= c2);
1654 unexpected(c1 > c2);
1655 unexpected(c1 >= c2);
1656}
1657
1658//------------------------------------------------------------------------------
1659//
1660// Observers
1661//
1662//------------------------------------------------------------------------------
1663
1664// ordered
1665template <bool IsUnordered, bool IsMulti, bool IsMap>
1668{
1670 typename Traits::ManualClock clock;
1671
1672 // testcase (Traits::name() + " observers");
1673 testcase("observers");
1674
1675 typename Traits::template Cont<> const c(clock);
1676 c.key_comp();
1677 c.value_comp();
1678
1679 pass();
1680}
1681
1682// unordered
1683template <bool IsUnordered, bool IsMulti, bool IsMap>
1686{
1687 using Traits = TestTraits<IsUnordered, IsMulti, IsMap>;
1688 typename Traits::ManualClock clock;
1689
1690 // testcase (Traits::name() + " observers");
1691 testcase("observers");
1692
1693 typename Traits::template Cont<> const c(clock);
1694 c.hash_function();
1695 c.key_eq();
1696
1697 pass();
1698}
1699
1700//------------------------------------------------------------------------------
1701//
1702// Matrix
1703//
1704//------------------------------------------------------------------------------
1705
1706template <bool IsUnordered, bool IsMulti, bool IsMap>
1707void
1709{
1710 testConstructEmpty<IsUnordered, IsMulti, IsMap>();
1711 testConstructRange<IsUnordered, IsMulti, IsMap>();
1712 testConstructInitList<IsUnordered, IsMulti, IsMap>();
1713 testCopyMove<IsUnordered, IsMulti, IsMap>();
1714 testIterator<IsUnordered, IsMulti, IsMap>();
1715 testReverseIterator<IsUnordered, IsMulti, IsMap>();
1716 testModifiers<IsUnordered, IsMulti, IsMap>();
1717 testChronological<IsUnordered, IsMulti, IsMap>();
1718 testArrayCreate<IsUnordered, IsMulti, IsMap>();
1719 testElementErase<IsUnordered, IsMulti, IsMap>();
1720 testRangeErase<IsUnordered, IsMulti, IsMap>();
1721 testCompare<IsUnordered, IsMulti, IsMap>();
1722 testObservers<IsUnordered, IsMulti, IsMap>();
1723}
1724
1725//------------------------------------------------------------------------------
1726
1728{
1729public:
1730 // Compile time checks
1731
1733 using T = int;
1734
1735 static_assert(
1737 "bad alias: aged_set");
1738
1739 static_assert(
1741 value,
1742 "bad alias: aged_multiset");
1743
1744 static_assert(
1746 "bad alias: aged_map");
1747
1748 static_assert(
1750 value,
1751 "bad alias: aged_multimap");
1752
1753 static_assert(
1757 "bad alias: aged_unordered_set");
1758
1759 static_assert(
1763 "bad alias: aged_unordered_multiset");
1764
1765 static_assert(
1769 "bad alias: aged_unordered_map");
1770
1771 static_assert(
1775 "bad alias: aged_unordered_multimap");
1776
1777 void
1778 run() override
1779 {
1780 testMaybeUnorderedMultiMap<false, false, false>();
1781 }
1782};
1783
1785{
1786public:
1787 void
1788 run() override
1789 {
1790 testMaybeUnorderedMultiMap<false, false, true>();
1791 }
1792};
1793
1795{
1796public:
1797 void
1798 run() override
1799 {
1800 testMaybeUnorderedMultiMap<false, true, false>();
1801 }
1802};
1803
1805{
1806public:
1807 void
1808 run() override
1809 {
1810 testMaybeUnorderedMultiMap<false, true, true>();
1811 }
1812};
1813
1815{
1816public:
1817 void
1818 run() override
1819 {
1820 testMaybeUnorderedMultiMap<true, false, false>();
1821 }
1822};
1823
1825{
1826public:
1827 void
1828 run() override
1829 {
1830 testMaybeUnorderedMultiMap<true, false, true>();
1831 }
1832};
1833
1835{
1836public:
1837 void
1838 run() override
1839 {
1840 testMaybeUnorderedMultiMap<true, true, false>();
1841 }
1842};
1843
1845{
1846public:
1847 void
1848 run() override
1849 {
1850 testMaybeUnorderedMultiMap<true, true, true>();
1851 }
1852};
1853
1854BEAST_DEFINE_TESTSUITE(aged_set, beast, beast);
1855BEAST_DEFINE_TESTSUITE(aged_map, beast, beast);
1856BEAST_DEFINE_TESTSUITE(aged_multiset, beast, beast);
1857BEAST_DEFINE_TESTSUITE(aged_multimap, beast, beast);
1858BEAST_DEFINE_TESTSUITE(aged_unordered_set, beast, beast);
1859BEAST_DEFINE_TESTSUITE(aged_unordered_map, beast, beast);
1860BEAST_DEFINE_TESTSUITE(aged_unordered_multiset, beast, beast);
1861BEAST_DEFINE_TESTSUITE(aged_unordered_multimap, beast, beast);
1862
1863} // namespace beast
std::enable_if< IsMap &&!IsMulti >::type testArrayCreate()
std::enable_if<!std::remove_reference< C >::type::is_unordered::value >::type checkUnorderedContentsRefRef(C &&, Values const &)
std::enable_if<!(Container::is_map::value &&!Container::is_multi::value)>::type checkMapContents(Container, Values const &)
static std::vector< typename Cont::value_type > make_list(Cont const &c)
std::enable_if< Container::is_map::value &&!Container::is_multi::value >::type checkMapContents(Container &c, Values const &v)
bool doElementErase(Container &c, Iter const beginItr, Iter const endItr)
Iter nextToEndIter(Iter const beginIter, Iter const endItr)
std::enable_if< std::remove_reference< C >::type::is_unordered::value >::type checkUnorderedContentsRefRef(C &&c, Values const &v)
std::enable_if<!IsUnordered >::type testConstructInitList()
std::enable_if<!IsMap||IsMulti >::type testArrayCreate()
void doRangeErase(Container &c, BeginEndSrc const &beginEndSrc)
void run() override
Runs the suite.
void run() override
Runs the suite.
Associative container where each element is also indexed by time.
Associative container where each element is also indexed by time.
Manual clock implementation.
A testsuite class.
Definition suite.h:51
void pass()
Record a successful test condition.
Definition suite.h:497
bool unexpected(Condition shouldBeFalse, String const &reason)
Definition suite.h:485
testcase_t testcase
Memberspace for declaring test cases.
Definition suite.h:150
bool expect(Condition const &shouldBeTrue)
Evaluate a test condition.
Definition suite.h:224
void fail(String const &reason, char const *file, int line)
Record a failure.
Definition suite.h:519
T distance(T... args)
T equal(T... args)
T find_if(T... args)
T is_same_v
T make_pair(T... args)
T reverse(T... args)
T sort(T... args)
bool operator()(typename Traits::Value const &lhs, typename Traits::Value const &rhs)
T swap(T... args)