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)
6 #if !defined(BOOST_UNORDERED_EXCEPTION_TEST_HEADER)
7 #define BOOST_UNORDERED_EXCEPTION_TEST_HEADER
12 #include <boost/preprocessor/cat.hpp>
13 #include <boost/preprocessor/seq/elem.hpp>
14 #include <boost/preprocessor/seq/for_each_product.hpp>
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>)); \
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>)); \
32 #define UNORDERED_EPOINT_IMPL ::test::lightweight::epoint
34 #define UNORDERED_EXCEPTION_TEST_POSTFIX RUN_TESTS()
36 #define EXCEPTION_TESTS(test_seq, param_seq) \
37 BOOST_PP_SEQ_FOR_EACH_PRODUCT(EXCEPTION_TESTS_OP, (test_seq)((1))(param_seq))
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))
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))
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())
53 #define UNORDERED_EPOINT(name) \
54 if (::test::exceptions_enabled) { \
55 UNORDERED_EPOINT_IMPL(name); \
58 #define ENABLE_EXCEPTIONS \
59 ::test::exceptions_enable BOOST_PP_CAT(ENABLE_EXCEPTIONS_, __LINE__)(true)
61 #define DISABLE_EXCEPTIONS \
62 ::test::exceptions_enable BOOST_PP_CAT(ENABLE_EXCEPTIONS_, __LINE__)(false)
65 static char const* scope = "";
66 bool exceptions_enabled = false;
70 scope_guard& operator=(scope_guard const&);
71 scope_guard(scope_guard const&);
73 char const* old_scope_;
78 scope_guard(char const* name)
79 : old_scope_(scope), scope_(name), dismissed_(false)
90 void dismiss() { dismissed_ = true; }
92 bool dismissed() const { return dismissed_; }
95 class exceptions_enable
97 exceptions_enable& operator=(exceptions_enable const&);
98 exceptions_enable(exceptions_enable const&);
104 exceptions_enable(bool enable)
105 : old_value_(exceptions_enabled), released_(false)
107 exceptions_enabled = enable;
113 exceptions_enabled = old_value_;
121 exceptions_enabled = old_value_;
127 struct exception_base
134 template <class T> void store(T const&) {}
135 template <class T> void test(T const&) const {}
137 data_type init() const { return data_type(); }
138 void check BOOST_PREVENT_MACRO_SUBSTITUTION() const {}
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&)
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&)
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)
162 template <class T> T const& constant(T const& x) { return x; }
164 template <class Test> class test_runner
167 bool exception_in_check_;
169 test_runner(test_runner const&);
170 test_runner& operator=(test_runner const&);
173 test_runner(Test const& t) : test_(t), exception_in_check_(false) {}
177 test::check_instances check;
179 BOOST_DEDUCED_TYPENAME Test::data_type x(test_.init());
180 BOOST_DEDUCED_TYPENAME Test::strong_type strong;
184 call_ignore_extra_parameters<Test,
185 BOOST_DEDUCED_TYPENAME Test::data_type,
186 BOOST_DEDUCED_TYPENAME Test::strong_type>(
187 &Test::run, test_, x, strong);
191 call_ignore_extra_parameters<Test,
192 BOOST_DEDUCED_TYPENAME Test::data_type const,
193 BOOST_DEDUCED_TYPENAME Test::strong_type const>(
194 &Test::check, test_, constant(x), constant(strong));
196 exception_in_check_ = true;
203 if (exception_in_check_) {
204 BOOST_ERROR("Unexcpected exception in test_runner check call.");
209 // Quick exception testing based on lightweight test
211 namespace lightweight {
212 static int iteration;
215 struct test_exception
218 test_exception(char const* n) : name(n) {}
225 void epoint(char const* name)
228 if (count == iteration) {
229 throw test_exception(name);
233 template <class Test>
234 void exception_safety(Test const& f, char const* /*name*/)
236 test_runner<Test> runner(f);
239 bool success = false;
240 unsigned int failure_count = 0;
241 char const* error_msg = 0;
243 int error_count = boost::detail::test_errors();
250 } catch (test_failure) {
251 error_msg = "test_failure caught.";
253 } catch (test_exception e) {
254 if (error_count != boost::detail::test_errors()) {
255 BOOST_LIGHTWEIGHT_TEST_OSTREAM
256 << "Iteration: " << iteration
257 << " Error found for epoint: " << e.name << std::endl;
260 error_msg = "Unexpected exception.";
264 if (error_count != boost::detail::test_errors()) {
267 } while (!success && failure_count < 5);
270 BOOST_ERROR(error_msg);
276 // An alternative way to run exception tests.
277 // See merge_exception_tests.cpp for an example.
279 struct exception_looper
282 unsigned int failure_count;
283 char const* error_msg;
286 exception_looper() : success(false), failure_count(0), error_msg(0) {}
288 void start() { iteration = 0; }
290 bool loop_condition() const
292 return !error_msg && !success && failure_count < 5;
295 void start_iteration()
297 error_count = boost::detail::test_errors();
302 void successful_run() { success = true; }
304 void test_failure_caught(test_failure const&)
306 error_msg = "test_failure caught.";
309 void test_exception_caught(test_exception const& e)
311 if (error_count != boost::detail::test_errors()) {
312 BOOST_LIGHTWEIGHT_TEST_OSTREAM
313 << "Iteration: " << iteration
314 << " Error found for epoint: " << e.name << std::endl;
318 void unexpected_exception_caught()
320 error_msg = "Unexpected exception.";
326 BOOST_ERROR(error_msg);
331 #define EXCEPTION_LOOP(op) \
332 test::lightweight::exception_looper looper; \
334 while (looper.loop_condition()) { \
335 looper.start_iteration(); \
338 looper.successful_run(); \
339 } catch (test::lightweight::test_failure e) { \
340 looper.test_failure_caught(e); \
341 } catch (test::lightweight::test_exception e) { \
342 looper.test_exception_caught(e); \
344 looper.unexpected_exception_caught(); \