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