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_EXCEPTION_TEST_HEADER)
7#define BOOST_UNORDERED_EXCEPTION_TEST_HEADER
8
9#include "./count.hpp"
10#include "./test.hpp"
11
12#include <boost/preprocessor/cat.hpp>
13#include <boost/preprocessor/seq/elem.hpp>
14#include <boost/preprocessor/seq/for_each_product.hpp>
15
16#define UNORDERED_EXCEPTION_TEST_CASE(name, test_func, type) \
17 UNORDERED_AUTO_TEST (name) { \
18 test_func<type> fixture; \
19 ::test::lightweight::exception_safety( \
20 fixture, BOOST_STRINGIZE(test_func<type>)); \
21 }
22
23#define UNORDERED_EXCEPTION_TEST_CASE_REPEAT(name, test_func, n, type) \
24 UNORDERED_AUTO_TEST (name) { \
25 for (unsigned i = 0; i < n; ++i) { \
26 test_func<type> fixture; \
27 ::test::lightweight::exception_safety( \
28 fixture, BOOST_STRINGIZE(test_func<type>)); \
29 } \
30 }
31
32#define UNORDERED_EPOINT_IMPL ::test::lightweight::epoint
33
34#define UNORDERED_EXCEPTION_TEST_POSTFIX RUN_TESTS()
35
36#define EXCEPTION_TESTS(test_seq, param_seq) \
37 BOOST_PP_SEQ_FOR_EACH_PRODUCT(EXCEPTION_TESTS_OP, (test_seq)((1))(param_seq))
38
39#define EXCEPTION_TESTS_REPEAT(n, test_seq, param_seq) \
40 BOOST_PP_SEQ_FOR_EACH_PRODUCT(EXCEPTION_TESTS_OP, (test_seq)((n))(param_seq))
41
42#define EXCEPTION_TESTS_OP(r, product) \
43 UNORDERED_EXCEPTION_TEST_CASE_REPEAT( \
44 BOOST_PP_CAT(BOOST_PP_SEQ_ELEM(0, product), \
45 BOOST_PP_CAT(_, BOOST_PP_SEQ_ELEM(2, product))), \
46 BOOST_PP_SEQ_ELEM(0, product), BOOST_PP_SEQ_ELEM(1, product), \
47 BOOST_PP_SEQ_ELEM(2, product))
48
49#define UNORDERED_SCOPE(scope_name) \
50 for (::test::scope_guard unordered_test_guard(BOOST_STRINGIZE(scope_name)); \
51 !unordered_test_guard.dismissed(); unordered_test_guard.dismiss())
52
53#define UNORDERED_EPOINT(name) \
54 if (::test::exceptions_enabled) { \
55 UNORDERED_EPOINT_IMPL(name); \
56 }
57
58#define ENABLE_EXCEPTIONS \
59 ::test::exceptions_enable BOOST_PP_CAT(ENABLE_EXCEPTIONS_, __LINE__)(true)
60
61#define DISABLE_EXCEPTIONS \
62 ::test::exceptions_enable BOOST_PP_CAT(ENABLE_EXCEPTIONS_, __LINE__)(false)
63
64namespace test {
65 static char const* scope = "";
66 bool exceptions_enabled = false;
67
68 class scope_guard
69 {
70 scope_guard& operator=(scope_guard const&);
71 scope_guard(scope_guard const&);
72
73 char const* old_scope_;
74 char const* scope_;
75 bool dismissed_;
76
77 public:
78 scope_guard(char const* name)
79 : old_scope_(scope), scope_(name), dismissed_(false)
80 {
81 scope = scope_;
82 }
83
84 ~scope_guard()
85 {
86 if (dismissed_)
87 scope = old_scope_;
88 }
89
90 void dismiss() { dismissed_ = true; }
91
92 bool dismissed() const { return dismissed_; }
93 };
94
95 class exceptions_enable
96 {
97 exceptions_enable& operator=(exceptions_enable const&);
98 exceptions_enable(exceptions_enable const&);
99
100 bool old_value_;
101 bool released_;
102
103 public:
104 exceptions_enable(bool enable)
105 : old_value_(exceptions_enabled), released_(false)
106 {
107 exceptions_enabled = enable;
108 }
109
110 ~exceptions_enable()
111 {
112 if (!released_) {
113 exceptions_enabled = old_value_;
114 released_ = true;
115 }
116 }
117
118 void release()
119 {
120 if (!released_) {
121 exceptions_enabled = old_value_;
122 released_ = true;
123 }
124 }
125 };
126
127 struct exception_base
128 {
129 struct data_type
130 {
131 };
132 struct strong_type
133 {
134 template <class T> void store(T const&) {}
135 template <class T> void test(T const&) const {}
136 };
137 data_type init() const { return data_type(); }
138 void check BOOST_PREVENT_MACRO_SUBSTITUTION() const {}
139 };
140
141 template <class T, class P1, class P2, class T2>
142 inline void call_ignore_extra_parameters(
143 void (T::*fn)() const, T2 const& obj, P1&, P2&)
144 {
145 (obj.*fn)();
146 }
147
148 template <class T, class P1, class P2, class T2>
149 inline void call_ignore_extra_parameters(
150 void (T::*fn)(P1&) const, T2 const& obj, P1& p1, P2&)
151 {
152 (obj.*fn)(p1);
153 }
154
155 template <class T, class P1, class P2, class T2>
156 inline void call_ignore_extra_parameters(
157 void (T::*fn)(P1&, P2&) const, T2 const& obj, P1& p1, P2& p2)
158 {
159 (obj.*fn)(p1, p2);
160 }
161
162 template <class T> T const& constant(T const& x) { return x; }
163
164 template <class Test> class test_runner
165 {
166 Test const& test_;
167 bool exception_in_check_;
168
169 test_runner(test_runner const&);
170 test_runner& operator=(test_runner const&);
171
172 public:
173 test_runner(Test const& t) : test_(t), exception_in_check_(false) {}
174 void run()
175 {
176 DISABLE_EXCEPTIONS;
177 test::check_instances check;
178 test::scope = "";
179 typename Test::data_type x(test_.init());
180 typename Test::strong_type strong;
181 strong.store(x);
182 try {
183 ENABLE_EXCEPTIONS;
184 call_ignore_extra_parameters<Test, typename Test::data_type,
185 typename Test::strong_type>(&Test::run, test_, x, strong);
186 } catch (...) {
187 try {
188 DISABLE_EXCEPTIONS;
189 call_ignore_extra_parameters<Test, typename Test::data_type const,
190 typename Test::strong_type const>(
191 &Test::check, test_, constant(x), constant(strong));
192 } catch (...) {
193 exception_in_check_ = true;
194 }
195 throw;
196 }
197 }
198 void end()
199 {
200 if (exception_in_check_) {
201 BOOST_ERROR("Unexcpected exception in test_runner check call.");
202 }
203 }
204 };
205
206 // Quick exception testing based on lightweight test
207
208 namespace lightweight {
209 static int iteration;
210 static int count;
211
212 struct test_exception
213 {
214 char const* name;
215 test_exception(char const* n) : name(n) {}
216 };
217
218 struct test_failure
219 {
220 };
221
222 void epoint(char const* name)
223 {
224 ++count;
225 if (count == iteration) {
226 throw test_exception(name);
227 }
228 }
229
230 template <class Test>
231 void exception_safety(Test const& f, char const* /*name*/)
232 {
233 test_runner<Test> runner(f);
234
235 iteration = 0;
236 bool success = false;
237 unsigned int failure_count = 0;
238 char const* error_msg = 0;
239 do {
240 int error_count = boost::detail::test_errors();
241 ++iteration;
242 count = 0;
243
244 try {
245 runner.run();
246 success = true;
247 } catch (test_failure) {
248 error_msg = "test_failure caught.";
249 break;
250 } catch (test_exception e) {
251 if (error_count != boost::detail::test_errors()) {
252 BOOST_LIGHTWEIGHT_TEST_OSTREAM
253 << "Iteration: " << iteration
254 << " Error found for epoint: " << e.name << std::endl;
255 }
256 } catch (...) {
257 error_msg = "Unexpected exception.";
258 break;
259 }
260
261 if (error_count != boost::detail::test_errors()) {
262 ++failure_count;
263 }
264 } while (!success && failure_count < 5);
265
266 if (error_msg) {
267 BOOST_ERROR(error_msg);
268 }
269 runner.end();
270 }
271
272 //
273 // An alternative way to run exception tests.
274 // See merge_exception_tests.cpp for an example.
275
276 struct exception_looper
277 {
278 bool success;
279 unsigned int failure_count;
280 char const* error_msg;
281 int error_count;
282
283 exception_looper() : success(false), failure_count(0), error_msg(0) {}
284
285 void start() { iteration = 0; }
286
287 bool loop_condition() const
288 {
289 return !error_msg && !success && failure_count < 5;
290 }
291
292 void start_iteration()
293 {
294 error_count = boost::detail::test_errors();
295 ++iteration;
296 count = 0;
297 }
298
299 void successful_run() { success = true; }
300
301 void test_failure_caught(test_failure const&)
302 {
303 error_msg = "test_failure caught.";
304 }
305
306 void test_exception_caught(test_exception const& e)
307 {
308 if (error_count != boost::detail::test_errors()) {
309 BOOST_LIGHTWEIGHT_TEST_OSTREAM
310 << "Iteration: " << iteration
311 << " Error found for epoint: " << e.name << std::endl;
312 }
313 }
314
315 void unexpected_exception_caught()
316 {
317 error_msg = "Unexpected exception.";
318 }
319
320 void end()
321 {
322 if (error_msg) {
323 BOOST_ERROR(error_msg);
324 }
325 }
326 };
327
328#define EXCEPTION_LOOP(op) \
329 test::lightweight::exception_looper looper; \
330 looper.start(); \
331 while (looper.loop_condition()) { \
332 looper.start_iteration(); \
333 try { \
334 op; \
335 looper.successful_run(); \
336 } catch (test::lightweight::test_failure e) { \
337 looper.test_failure_caught(e); \
338 } catch (test::lightweight::test_exception e) { \
339 looper.test_exception_caught(e); \
340 } catch (...) { \
341 looper.unexpected_exception_caught(); \
342 } \
343 } \
344 looper.end();
345 }
346}
347
348#endif
349

source code of boost/libs/unordered/test/helpers/exception_test.hpp