exception_test.hpp 10 KB

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