1 | |
2 | // Copyright 2006-2009 Daniel James. |
3 | // Distributed under the Boost Software License, Version 1.0. (See accompanying |
4 | // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) |
5 | |
6 | #if !defined(BOOST_UNORDERED_TEST_TEST_HEADER) |
7 | #define |
8 | |
9 | #include <boost/core/lightweight_test.hpp> |
10 | #include <boost/core/lightweight_test_trait.hpp> |
11 | #include <boost/preprocessor/cat.hpp> |
12 | #include <boost/preprocessor/stringize.hpp> |
13 | |
14 | #include <boost/type_traits/is_nothrow_move_assignable.hpp> |
15 | #include <boost/type_traits/is_nothrow_move_constructible.hpp> |
16 | #include <boost/type_traits/is_nothrow_swappable.hpp> |
17 | #include <boost/type_traits/make_void.hpp> |
18 | |
19 | #define UNORDERED_AUTO_TEST(x) \ |
20 | struct BOOST_PP_CAT(x, _type) : public ::test::registered_test_base \ |
21 | { \ |
22 | BOOST_PP_CAT(x, _type) \ |
23 | () : ::test::registered_test_base(BOOST_PP_STRINGIZE(x)) \ |
24 | { \ |
25 | ::test::get_state().add_test(this); \ |
26 | } \ |
27 | void run(); \ |
28 | }; \ |
29 | BOOST_PP_CAT(x, _type) x; \ |
30 | void BOOST_PP_CAT(x, _type)::run() |
31 | |
32 | #define RUN_TESTS() \ |
33 | int main(int, char**) \ |
34 | { \ |
35 | BOOST_UNORDERED_TEST_COMPILER_INFO() \ |
36 | ::test::get_state().run_tests(); \ |
37 | return boost::report_errors(); \ |
38 | } |
39 | |
40 | #define RUN_TESTS_QUIET() \ |
41 | int main(int, char**) \ |
42 | { \ |
43 | BOOST_UNORDERED_TEST_COMPILER_INFO() \ |
44 | ::test::get_state().run_tests(true); \ |
45 | return boost::report_errors(); \ |
46 | } |
47 | |
48 | #define UNORDERED_SUB_TEST(x) \ |
49 | for (int UNORDERED_SUB_TEST_VALUE = ::test::get_state().start_sub_test(x); \ |
50 | UNORDERED_SUB_TEST_VALUE; \ |
51 | UNORDERED_SUB_TEST_VALUE = \ |
52 | ::test::get_state().end_sub_test(x, UNORDERED_SUB_TEST_VALUE)) |
53 | |
54 | namespace test { |
55 | |
56 | struct registered_test_base |
57 | { |
58 | registered_test_base* next; |
59 | char const* name; |
60 | explicit registered_test_base(char const* n) : name(n) {} |
61 | virtual void run() = 0; |
62 | virtual ~registered_test_base() {} |
63 | }; |
64 | |
65 | struct state |
66 | { |
67 | bool is_quiet; |
68 | registered_test_base* first_test; |
69 | registered_test_base* last_test; |
70 | |
71 | state() : is_quiet(false), first_test(0), last_test(0) {} |
72 | |
73 | void add_test(registered_test_base* test) |
74 | { |
75 | if (last_test) { |
76 | last_test->next = test; |
77 | } else { |
78 | first_test = test; |
79 | } |
80 | last_test = test; |
81 | } |
82 | |
83 | void run_tests(bool quiet = false) |
84 | { |
85 | is_quiet = quiet; |
86 | |
87 | for (registered_test_base* i = first_test; i; i = i->next) { |
88 | int error_count = boost::detail::test_errors(); |
89 | if (!quiet) { |
90 | BOOST_LIGHTWEIGHT_TEST_OSTREAM << "Running " << i->name << "\n" |
91 | << std::flush; |
92 | } |
93 | i->run(); |
94 | BOOST_LIGHTWEIGHT_TEST_OSTREAM << std::flush; |
95 | if (quiet && error_count != boost::detail::test_errors()) { |
96 | BOOST_LIGHTWEIGHT_TEST_OSTREAM << "Error in: " << i->name << "\n" |
97 | << std::flush; |
98 | } |
99 | } |
100 | } |
101 | |
102 | int start_sub_test(char const* name) |
103 | { |
104 | if (!is_quiet) { |
105 | BOOST_LIGHTWEIGHT_TEST_OSTREAM << "Sub-test: " << name << "\n" |
106 | << std::flush; |
107 | } |
108 | // Add one because it's used as a loop condition. |
109 | return boost::detail::test_errors() + 1; |
110 | } |
111 | |
112 | int end_sub_test(char const* name, int value) |
113 | { |
114 | if (is_quiet && value != boost::detail::test_errors() + 1) { |
115 | BOOST_LIGHTWEIGHT_TEST_OSTREAM << "Error in sub-test: " << name << "\n" |
116 | << std::flush; |
117 | } |
118 | return 0; |
119 | } |
120 | }; |
121 | |
122 | // Get the currnet translation unit's test state. |
123 | static inline state& get_state() |
124 | { |
125 | static state instance; |
126 | return instance; |
127 | } |
128 | } // namespace test |
129 | |
130 | #if defined(__cplusplus) |
131 | #define BOOST_UNORDERED_CPLUSPLUS __cplusplus |
132 | #else |
133 | #define BOOST_UNORDERED_CPLUSPLUS "(not defined)" |
134 | #endif |
135 | |
136 | #define BOOST_UNORDERED_TEST_COMPILER_INFO() \ |
137 | { \ |
138 | BOOST_LIGHTWEIGHT_TEST_OSTREAM \ |
139 | << "Compiler: " << BOOST_COMPILER << "\n" \ |
140 | << "Library: " << BOOST_STDLIB << "\n" \ |
141 | << "__cplusplus: " << BOOST_UNORDERED_CPLUSPLUS << "\n\n" \ |
142 | << std::flush; \ |
143 | } |
144 | |
145 | #include <boost/preprocessor/cat.hpp> |
146 | #include <boost/preprocessor/seq/fold_left.hpp> |
147 | #include <boost/preprocessor/seq/for_each_product.hpp> |
148 | #include <boost/preprocessor/seq/seq.hpp> |
149 | #include <boost/preprocessor/seq/to_tuple.hpp> |
150 | |
151 | // Run test with every combination of the parameters (a sequence of sequences) |
152 | #define UNORDERED_TEST(name, parameters) \ |
153 | BOOST_PP_SEQ_FOR_EACH_PRODUCT(UNORDERED_TEST_OP, ((name))((1))parameters) |
154 | |
155 | #define UNORDERED_TEST_REPEAT(name, n, parameters) \ |
156 | BOOST_PP_SEQ_FOR_EACH_PRODUCT(UNORDERED_TEST_OP, ((name))((n))parameters) |
157 | |
158 | #define UNORDERED_TEST_OP(r, product) \ |
159 | UNORDERED_TEST_OP2(BOOST_PP_SEQ_ELEM(0, product), \ |
160 | BOOST_PP_SEQ_ELEM(1, product), \ |
161 | BOOST_PP_SEQ_TAIL(BOOST_PP_SEQ_TAIL(product))) |
162 | |
163 | #define UNORDERED_TEST_OP2(name, n, params) \ |
164 | UNORDERED_AUTO_TEST ( \ |
165 | BOOST_PP_SEQ_FOLD_LEFT(UNORDERED_TEST_OP_JOIN, name, params)) { \ |
166 | for (int i = 0; i < n; ++i) \ |
167 | name BOOST_PP_SEQ_TO_TUPLE(params); \ |
168 | } |
169 | |
170 | #define UNORDERED_TEST_OP_JOIN(s, state, elem) \ |
171 | BOOST_PP_CAT(state, BOOST_PP_CAT(_, elem)) |
172 | |
173 | #define UNORDERED_MULTI_TEST(name, impl, parameters) \ |
174 | UNORDERED_MULTI_TEST_REPEAT(name, impl, 1, parameters) |
175 | |
176 | #define UNORDERED_MULTI_TEST_REPEAT(name, impl, n, parameters) \ |
177 | UNORDERED_AUTO_TEST (name) { \ |
178 | BOOST_PP_SEQ_FOR_EACH_PRODUCT( \ |
179 | UNORDERED_MULTI_TEST_OP, ((impl))((n))parameters) \ |
180 | } |
181 | |
182 | #define UNORDERED_MULTI_TEST_OP(r, product) \ |
183 | UNORDERED_MULTI_TEST_OP2(BOOST_PP_SEQ_ELEM(0, product), \ |
184 | BOOST_PP_SEQ_ELEM(1, product), \ |
185 | BOOST_PP_SEQ_TAIL(BOOST_PP_SEQ_TAIL(product))) |
186 | |
187 | // Need to wrap UNORDERED_SUB_TEST in a block to avoid an msvc bug. |
188 | // https://support.microsoft.com/en-gb/help/315481/bug-too-many-unnested-loops-incorrectly-causes-a-c1061-compiler-error-in-visual-c |
189 | #define UNORDERED_MULTI_TEST_OP2(name, n, params) \ |
190 | { \ |
191 | UNORDERED_SUB_TEST(BOOST_PP_STRINGIZE( \ |
192 | BOOST_PP_SEQ_FOLD_LEFT(UNORDERED_TEST_OP_JOIN, name, params))) \ |
193 | { \ |
194 | for (int i = 0; i < n; ++i) \ |
195 | name BOOST_PP_SEQ_TO_TUPLE(params); \ |
196 | } \ |
197 | } |
198 | |
199 | #endif |
200 | |