1e7ae2487b766325ce28e03919a55f0e5c20c52d
[platform/upstream/boost.git] / libs / unordered / test / helpers / exception_test.hpp
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 "./test.hpp"
10
11 #include <boost/preprocessor/seq/for_each_product.hpp>
12 #include <boost/preprocessor/seq/elem.hpp>
13 #include <boost/preprocessor/cat.hpp>
14
15 #   define UNORDERED_EXCEPTION_TEST_CASE(name, test_func, type)             \
16         UNORDERED_AUTO_TEST(name)                                           \
17         {                                                                   \
18             test_func< type > fixture;                                      \
19             ::test::lightweight::exception_safety(                          \
20                 fixture, BOOST_STRINGIZE(test_func<type>));                 \
21         }                                                                   \
22
23 #    define UNORDERED_EPOINT_IMPL ::test::lightweight::epoint
24
25 #define UNORDERED_EXCEPTION_TEST_POSTFIX RUN_TESTS()
26
27 #define RUN_EXCEPTION_TESTS(test_seq, param_seq)                            \
28     BOOST_PP_SEQ_FOR_EACH_PRODUCT(RUN_EXCEPTION_TESTS_OP,                   \
29         (test_seq)(param_seq))                                              \
30     RUN_TESTS()                                                             \
31
32 #define RUN_EXCEPTION_TESTS_OP(r, product)                                  \
33     UNORDERED_EXCEPTION_TEST_CASE(                                          \
34         BOOST_PP_CAT(BOOST_PP_SEQ_ELEM(0, product),                         \
35             BOOST_PP_CAT(_, BOOST_PP_SEQ_ELEM(1, product))                  \
36         ),                                                                  \
37         BOOST_PP_SEQ_ELEM(0, product),                                      \
38         BOOST_PP_SEQ_ELEM(1, product)                                       \
39     )                                                                       \
40
41 #define UNORDERED_SCOPE(scope_name)                                         \
42     for(::test::scope_guard unordered_test_guard(                           \
43             BOOST_STRINGIZE(scope_name));                                   \
44         !unordered_test_guard.dismissed();                                  \
45         unordered_test_guard.dismiss())                                     \
46
47 #define UNORDERED_EPOINT(name)                                              \
48     if(::test::exceptions_enabled) {                                        \
49         UNORDERED_EPOINT_IMPL(name);                                        \
50     }                                                                       \
51
52 #define ENABLE_EXCEPTIONS                                                   \
53     ::test::exceptions_enable BOOST_PP_CAT(                                 \
54         ENABLE_EXCEPTIONS_, __LINE__)(true)                                 \
55
56 #define DISABLE_EXCEPTIONS                                                  \
57     ::test::exceptions_enable BOOST_PP_CAT(                                 \
58         ENABLE_EXCEPTIONS_, __LINE__)(false)                                \
59
60 namespace test {
61     static char const* scope = "";
62     bool exceptions_enabled = false;
63
64     class scope_guard {
65         scope_guard& operator=(scope_guard const&);
66         scope_guard(scope_guard const&);
67
68         char const* old_scope_;
69         char const* scope_;
70         bool dismissed_;
71     public:
72         scope_guard(char const* name)
73             : old_scope_(scope),
74             scope_(name),
75             dismissed_(false)
76         {
77             scope = scope_;
78         }
79
80         ~scope_guard() {
81             if(dismissed_) scope = old_scope_;
82         }
83
84         void dismiss() {
85             dismissed_ = true;
86         }
87
88         bool dismissed() const {
89             return dismissed_;
90         }
91     };
92
93     class exceptions_enable
94     {
95         exceptions_enable& operator=(exceptions_enable const&);
96         exceptions_enable(exceptions_enable const&);
97
98         bool old_value_;
99     public:
100         exceptions_enable(bool enable)
101             : old_value_(exceptions_enabled)
102         {
103             exceptions_enabled = enable;
104         }
105
106         ~exceptions_enable()
107         {
108             exceptions_enabled = old_value_;
109         }
110     };
111
112     struct exception_base {
113         struct data_type {};
114         struct strong_type {
115             template <class T> void store(T const&) {}
116             template <class T> void test(T const&) const {}
117         };
118         data_type init() const { return data_type(); }
119         void check BOOST_PREVENT_MACRO_SUBSTITUTION() const {}
120     };
121
122     template <class T, class P1, class P2, class T2>
123     inline void call_ignore_extra_parameters(
124             void (T::*fn)() const, T2 const& obj,
125             P1&, P2&)
126     {
127         (obj.*fn)();
128     }
129
130     template <class T, class P1, class P2, class T2>
131     inline void call_ignore_extra_parameters(
132             void (T::*fn)(P1&) const, T2 const& obj,
133             P1& p1, P2&)
134     {
135         (obj.*fn)(p1);
136     }
137
138     template <class T, class P1, class P2, class T2>
139     inline void call_ignore_extra_parameters(
140             void (T::*fn)(P1&, P2&) const, T2 const& obj,
141             P1& p1, P2& p2)
142     {
143         (obj.*fn)(p1, p2);
144     }
145
146     template <class T>
147     T const& constant(T const& x) {
148         return x;
149     }
150
151     template <class Test>
152     class test_runner
153     {
154         Test const& test_;
155
156         test_runner(test_runner const&);
157         test_runner& operator=(test_runner const&);
158     public:
159         test_runner(Test const& t) : test_(t) {}
160         void operator()() const {
161             DISABLE_EXCEPTIONS;
162             test::scope = "";
163             BOOST_DEDUCED_TYPENAME Test::data_type x(test_.init());
164             BOOST_DEDUCED_TYPENAME Test::strong_type strong;
165             strong.store(x);
166             try {
167                 ENABLE_EXCEPTIONS;
168                 call_ignore_extra_parameters<
169                     Test,
170                     BOOST_DEDUCED_TYPENAME Test::data_type,
171                     BOOST_DEDUCED_TYPENAME Test::strong_type
172                 >(&Test::run, test_, x, strong);
173             }
174             catch(...) {
175                 call_ignore_extra_parameters<
176                     Test,
177                     BOOST_DEDUCED_TYPENAME Test::data_type const,
178                     BOOST_DEDUCED_TYPENAME Test::strong_type const
179                 >(&Test::check, test_, constant(x), constant(strong));
180                 throw;
181             }
182         }
183     };
184
185     // Quick exception testing based on lightweight test
186
187     namespace lightweight {
188         static int iteration;
189         static int count;
190
191         struct test_exception {
192             char const* name;
193             test_exception(char const* n) : name(n) {}
194         };
195
196         struct test_failure {
197         };
198
199         void epoint(char const* name) {
200             ++count;
201             if(count == iteration) {
202                 throw test_exception(name);
203             }
204         }
205
206         template <class Test>
207         void exception_safety(Test const& f, char const* /*name*/) {
208             test_runner<Test> runner(f);
209
210             iteration = 0;
211             bool success = false;
212             do {
213                 ++iteration;
214                 count = 0;
215
216                 try {
217                     runner();
218                     success = true;
219                 }
220                 catch(test_failure) {
221                     BOOST_ERROR("test_failure caught.");
222                     break;
223                 }
224                 catch(test_exception) {
225                     continue;
226                 }
227                 catch(...) {
228                     BOOST_ERROR("Unexpected exception.");
229                     break;
230                 }
231             } while(!success);
232         }
233     }
234 }
235
236 #endif