mirror of
				https://github.com/boostorg/unordered.git
				synced 2025-10-31 07:41:36 +01:00 
			
		
		
		
	We no longer support any of the compilers that require it. I'd be very surprised if anything was working on them.
		
			
				
	
	
		
			349 lines
		
	
	
		
			10 KiB
		
	
	
	
		
			C++
		
	
	
	
	
	
			
		
		
	
	
			349 lines
		
	
	
		
			10 KiB
		
	
	
	
		
			C++
		
	
	
	
	
	
| 
 | |
| // Copyright 2006-2009 Daniel James.
 | |
| // Distributed under the Boost Software License, Version 1.0. (See accompanying
 | |
| // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
 | |
| 
 | |
| #if !defined(BOOST_UNORDERED_EXCEPTION_TEST_HEADER)
 | |
| #define BOOST_UNORDERED_EXCEPTION_TEST_HEADER
 | |
| 
 | |
| #include "./count.hpp"
 | |
| #include "./test.hpp"
 | |
| 
 | |
| #include <boost/preprocessor/cat.hpp>
 | |
| #include <boost/preprocessor/seq/elem.hpp>
 | |
| #include <boost/preprocessor/seq/for_each_product.hpp>
 | |
| 
 | |
| #define UNORDERED_EXCEPTION_TEST_CASE(name, test_func, type)                   \
 | |
|   UNORDERED_AUTO_TEST (name) {                                                 \
 | |
|     test_func<type> fixture;                                                   \
 | |
|     ::test::lightweight::exception_safety(                                     \
 | |
|       fixture, BOOST_STRINGIZE(test_func<type>));                              \
 | |
|   }
 | |
| 
 | |
| #define UNORDERED_EXCEPTION_TEST_CASE_REPEAT(name, test_func, n, type)         \
 | |
|   UNORDERED_AUTO_TEST (name) {                                                 \
 | |
|     for (unsigned i = 0; i < n; ++i) {                                         \
 | |
|       test_func<type> fixture;                                                 \
 | |
|       ::test::lightweight::exception_safety(                                   \
 | |
|         fixture, BOOST_STRINGIZE(test_func<type>));                            \
 | |
|     }                                                                          \
 | |
|   }
 | |
| 
 | |
| #define UNORDERED_EPOINT_IMPL ::test::lightweight::epoint
 | |
| 
 | |
| #define UNORDERED_EXCEPTION_TEST_POSTFIX RUN_TESTS()
 | |
| 
 | |
| #define EXCEPTION_TESTS(test_seq, param_seq)                                   \
 | |
|   BOOST_PP_SEQ_FOR_EACH_PRODUCT(EXCEPTION_TESTS_OP, (test_seq)((1))(param_seq))
 | |
| 
 | |
| #define EXCEPTION_TESTS_REPEAT(n, test_seq, param_seq)                         \
 | |
|   BOOST_PP_SEQ_FOR_EACH_PRODUCT(EXCEPTION_TESTS_OP, (test_seq)((n))(param_seq))
 | |
| 
 | |
| #define EXCEPTION_TESTS_OP(r, product)                                         \
 | |
|   UNORDERED_EXCEPTION_TEST_CASE_REPEAT(                                        \
 | |
|     BOOST_PP_CAT(BOOST_PP_SEQ_ELEM(0, product),                                \
 | |
|       BOOST_PP_CAT(_, BOOST_PP_SEQ_ELEM(2, product))),                         \
 | |
|     BOOST_PP_SEQ_ELEM(0, product), BOOST_PP_SEQ_ELEM(1, product),              \
 | |
|     BOOST_PP_SEQ_ELEM(2, product))
 | |
| 
 | |
| #define UNORDERED_SCOPE(scope_name)                                            \
 | |
|   for (::test::scope_guard unordered_test_guard(BOOST_STRINGIZE(scope_name));  \
 | |
|        !unordered_test_guard.dismissed(); unordered_test_guard.dismiss())
 | |
| 
 | |
| #define UNORDERED_EPOINT(name)                                                 \
 | |
|   if (::test::exceptions_enabled) {                                            \
 | |
|     UNORDERED_EPOINT_IMPL(name);                                               \
 | |
|   }
 | |
| 
 | |
| #define ENABLE_EXCEPTIONS                                                      \
 | |
|   ::test::exceptions_enable BOOST_PP_CAT(ENABLE_EXCEPTIONS_, __LINE__)(true)
 | |
| 
 | |
| #define DISABLE_EXCEPTIONS                                                     \
 | |
|   ::test::exceptions_enable BOOST_PP_CAT(ENABLE_EXCEPTIONS_, __LINE__)(false)
 | |
| 
 | |
| namespace test {
 | |
|   static char const* scope = "";
 | |
|   bool exceptions_enabled = false;
 | |
| 
 | |
|   class scope_guard
 | |
|   {
 | |
|     scope_guard& operator=(scope_guard const&);
 | |
|     scope_guard(scope_guard const&);
 | |
| 
 | |
|     char const* old_scope_;
 | |
|     char const* scope_;
 | |
|     bool dismissed_;
 | |
| 
 | |
|   public:
 | |
|     scope_guard(char const* name)
 | |
|         : old_scope_(scope), scope_(name), dismissed_(false)
 | |
|     {
 | |
|       scope = scope_;
 | |
|     }
 | |
| 
 | |
|     ~scope_guard()
 | |
|     {
 | |
|       if (dismissed_)
 | |
|         scope = old_scope_;
 | |
|     }
 | |
| 
 | |
|     void dismiss() { dismissed_ = true; }
 | |
| 
 | |
|     bool dismissed() const { return dismissed_; }
 | |
|   };
 | |
| 
 | |
|   class exceptions_enable
 | |
|   {
 | |
|     exceptions_enable& operator=(exceptions_enable const&);
 | |
|     exceptions_enable(exceptions_enable const&);
 | |
| 
 | |
|     bool old_value_;
 | |
|     bool released_;
 | |
| 
 | |
|   public:
 | |
|     exceptions_enable(bool enable)
 | |
|         : old_value_(exceptions_enabled), released_(false)
 | |
|     {
 | |
|       exceptions_enabled = enable;
 | |
|     }
 | |
| 
 | |
|     ~exceptions_enable()
 | |
|     {
 | |
|       if (!released_) {
 | |
|         exceptions_enabled = old_value_;
 | |
|         released_ = true;
 | |
|       }
 | |
|     }
 | |
| 
 | |
|     void release()
 | |
|     {
 | |
|       if (!released_) {
 | |
|         exceptions_enabled = old_value_;
 | |
|         released_ = true;
 | |
|       }
 | |
|     }
 | |
|   };
 | |
| 
 | |
|   struct exception_base
 | |
|   {
 | |
|     struct data_type
 | |
|     {
 | |
|     };
 | |
|     struct strong_type
 | |
|     {
 | |
|       template <class T> void store(T const&) {}
 | |
|       template <class T> void test(T const&) const {}
 | |
|     };
 | |
|     data_type init() const { return data_type(); }
 | |
|     void check BOOST_PREVENT_MACRO_SUBSTITUTION() const {}
 | |
|   };
 | |
| 
 | |
|   template <class T, class P1, class P2, class T2>
 | |
|   inline void call_ignore_extra_parameters(
 | |
|     void (T::*fn)() const, T2 const& obj, P1&, P2&)
 | |
|   {
 | |
|     (obj.*fn)();
 | |
|   }
 | |
| 
 | |
|   template <class T, class P1, class P2, class T2>
 | |
|   inline void call_ignore_extra_parameters(
 | |
|     void (T::*fn)(P1&) const, T2 const& obj, P1& p1, P2&)
 | |
|   {
 | |
|     (obj.*fn)(p1);
 | |
|   }
 | |
| 
 | |
|   template <class T, class P1, class P2, class T2>
 | |
|   inline void call_ignore_extra_parameters(
 | |
|     void (T::*fn)(P1&, P2&) const, T2 const& obj, P1& p1, P2& p2)
 | |
|   {
 | |
|     (obj.*fn)(p1, p2);
 | |
|   }
 | |
| 
 | |
|   template <class T> T const& constant(T const& x) { return x; }
 | |
| 
 | |
|   template <class Test> class test_runner
 | |
|   {
 | |
|     Test const& test_;
 | |
|     bool exception_in_check_;
 | |
| 
 | |
|     test_runner(test_runner const&);
 | |
|     test_runner& operator=(test_runner const&);
 | |
| 
 | |
|   public:
 | |
|     test_runner(Test const& t) : test_(t), exception_in_check_(false) {}
 | |
|     void run()
 | |
|     {
 | |
|       DISABLE_EXCEPTIONS;
 | |
|       test::check_instances check;
 | |
|       test::scope = "";
 | |
|       typename Test::data_type x(test_.init());
 | |
|       typename Test::strong_type strong;
 | |
|       strong.store(x);
 | |
|       try {
 | |
|         ENABLE_EXCEPTIONS;
 | |
|         call_ignore_extra_parameters<Test, typename Test::data_type,
 | |
|           typename Test::strong_type>(&Test::run, test_, x, strong);
 | |
|       } catch (...) {
 | |
|         try {
 | |
|           DISABLE_EXCEPTIONS;
 | |
|           call_ignore_extra_parameters<Test, typename Test::data_type const,
 | |
|             typename Test::strong_type const>(
 | |
|             &Test::check, test_, constant(x), constant(strong));
 | |
|         } catch (...) {
 | |
|           exception_in_check_ = true;
 | |
|         }
 | |
|         throw;
 | |
|       }
 | |
|     }
 | |
|     void end()
 | |
|     {
 | |
|       if (exception_in_check_) {
 | |
|         BOOST_ERROR("Unexcpected exception in test_runner check call.");
 | |
|       }
 | |
|     }
 | |
|   };
 | |
| 
 | |
|   // Quick exception testing based on lightweight test
 | |
| 
 | |
|   namespace lightweight {
 | |
|     static int iteration;
 | |
|     static int count;
 | |
| 
 | |
|     struct test_exception
 | |
|     {
 | |
|       char const* name;
 | |
|       test_exception(char const* n) : name(n) {}
 | |
|     };
 | |
| 
 | |
|     struct test_failure
 | |
|     {
 | |
|     };
 | |
| 
 | |
|     void epoint(char const* name)
 | |
|     {
 | |
|       ++count;
 | |
|       if (count == iteration) {
 | |
|         throw test_exception(name);
 | |
|       }
 | |
|     }
 | |
| 
 | |
|     template <class Test>
 | |
|     void exception_safety(Test const& f, char const* /*name*/)
 | |
|     {
 | |
|       test_runner<Test> runner(f);
 | |
| 
 | |
|       iteration = 0;
 | |
|       bool success = false;
 | |
|       unsigned int failure_count = 0;
 | |
|       char const* error_msg = 0;
 | |
|       do {
 | |
|         int error_count = boost::detail::test_errors();
 | |
|         ++iteration;
 | |
|         count = 0;
 | |
| 
 | |
|         try {
 | |
|           runner.run();
 | |
|           success = true;
 | |
|         } catch (test_failure) {
 | |
|           error_msg = "test_failure caught.";
 | |
|           break;
 | |
|         } catch (test_exception e) {
 | |
|           if (error_count != boost::detail::test_errors()) {
 | |
|             BOOST_LIGHTWEIGHT_TEST_OSTREAM
 | |
|               << "Iteration: " << iteration
 | |
|               << " Error found for epoint: " << e.name << std::endl;
 | |
|           }
 | |
|         } catch (...) {
 | |
|           error_msg = "Unexpected exception.";
 | |
|           break;
 | |
|         }
 | |
| 
 | |
|         if (error_count != boost::detail::test_errors()) {
 | |
|           ++failure_count;
 | |
|         }
 | |
|       } while (!success && failure_count < 5);
 | |
| 
 | |
|       if (error_msg) {
 | |
|         BOOST_ERROR(error_msg);
 | |
|       }
 | |
|       runner.end();
 | |
|     }
 | |
| 
 | |
|     //
 | |
|     // An alternative way to run exception tests.
 | |
|     // See merge_exception_tests.cpp for an example.
 | |
| 
 | |
|     struct exception_looper
 | |
|     {
 | |
|       bool success;
 | |
|       unsigned int failure_count;
 | |
|       char const* error_msg;
 | |
|       int error_count;
 | |
| 
 | |
|       exception_looper() : success(false), failure_count(0), error_msg(0) {}
 | |
| 
 | |
|       void start() { iteration = 0; }
 | |
| 
 | |
|       bool loop_condition() const
 | |
|       {
 | |
|         return !error_msg && !success && failure_count < 5;
 | |
|       }
 | |
| 
 | |
|       void start_iteration()
 | |
|       {
 | |
|         error_count = boost::detail::test_errors();
 | |
|         ++iteration;
 | |
|         count = 0;
 | |
|       }
 | |
| 
 | |
|       void successful_run() { success = true; }
 | |
| 
 | |
|       void test_failure_caught(test_failure const&)
 | |
|       {
 | |
|         error_msg = "test_failure caught.";
 | |
|       }
 | |
| 
 | |
|       void test_exception_caught(test_exception const& e)
 | |
|       {
 | |
|         if (error_count != boost::detail::test_errors()) {
 | |
|           BOOST_LIGHTWEIGHT_TEST_OSTREAM
 | |
|             << "Iteration: " << iteration
 | |
|             << " Error found for epoint: " << e.name << std::endl;
 | |
|         }
 | |
|       }
 | |
| 
 | |
|       void unexpected_exception_caught()
 | |
|       {
 | |
|         error_msg = "Unexpected exception.";
 | |
|       }
 | |
| 
 | |
|       void end()
 | |
|       {
 | |
|         if (error_msg) {
 | |
|           BOOST_ERROR(error_msg);
 | |
|         }
 | |
|       }
 | |
|     };
 | |
| 
 | |
| #define EXCEPTION_LOOP(op)                                                     \
 | |
|   test::lightweight::exception_looper looper;                                  \
 | |
|   looper.start();                                                              \
 | |
|   while (looper.loop_condition()) {                                            \
 | |
|     looper.start_iteration();                                                  \
 | |
|     try {                                                                      \
 | |
|       op;                                                                      \
 | |
|       looper.successful_run();                                                 \
 | |
|     } catch (test::lightweight::test_failure e) {                              \
 | |
|       looper.test_failure_caught(e);                                           \
 | |
|     } catch (test::lightweight::test_exception e) {                            \
 | |
|       looper.test_exception_caught(e);                                         \
 | |
|     } catch (...) {                                                            \
 | |
|       looper.unexpected_exception_caught();                                    \
 | |
|     }                                                                          \
 | |
|   }                                                                            \
 | |
|   looper.end();
 | |
|   }
 | |
| }
 | |
| 
 | |
| #endif
 |