diff options
Diffstat (limited to 'boost/test')
43 files changed, 1127 insertions, 324 deletions
diff --git a/boost/test/data/monomorphic/collection.hpp b/boost/test/data/monomorphic/collection.hpp index 49e81458bf..71a4863f41 100644 --- a/boost/test/data/monomorphic/collection.hpp +++ b/boost/test/data/monomorphic/collection.hpp @@ -75,7 +75,7 @@ struct is_dataset<collection<C>> : mpl::true_ {}; //! @overload boost::unit_test::data::make() template<typename C> -inline typename std::enable_if<is_forward_iterable<C>::value,monomorphic::collection<C>>::type +inline typename std::enable_if<is_container_forward_iterable<C>::value,monomorphic::collection<C>>::type make( C&& c ) { return monomorphic::collection<C>( std::forward<C>(c) ); diff --git a/boost/test/data/monomorphic/fwd.hpp b/boost/test/data/monomorphic/fwd.hpp index cf6d3b0000..dcd1b84165 100644 --- a/boost/test/data/monomorphic/fwd.hpp +++ b/boost/test/data/monomorphic/fwd.hpp @@ -119,7 +119,7 @@ make(DataSet&& ds) //! @overload boost::unit_test::data::make() template<typename T> -inline typename std::enable_if<!is_forward_iterable<T>::value && +inline typename std::enable_if<!is_container_forward_iterable<T>::value && !monomorphic::is_dataset<T>::value && !is_array<typename remove_reference<T>::type>::value, monomorphic::singleton<T>>::type @@ -129,7 +129,7 @@ make( T&& v ); //! @overload boost::unit_test::data::make() template<typename C> -inline typename std::enable_if<is_forward_iterable<C>::value,monomorphic::collection<C>>::type +inline typename std::enable_if<is_container_forward_iterable<C>::value,monomorphic::collection<C>>::type make( C&& c ); //____________________________________________________________________________// diff --git a/boost/test/data/monomorphic/generate.hpp b/boost/test/data/monomorphic/generate.hpp index af3b5c0bb9..614ef3aad5 100644 --- a/boost/test/data/monomorphic/generate.hpp +++ b/boost/test/data/monomorphic/generate.hpp @@ -16,6 +16,8 @@ #include <boost/test/data/config.hpp> #include <boost/test/data/monomorphic/fwd.hpp> +#include <boost/core/ref.hpp> + #include <boost/test/detail/suppress_warnings.hpp> //____________________________________________________________________________// diff --git a/boost/test/data/monomorphic/grid.hpp b/boost/test/data/monomorphic/grid.hpp index 3e1b36abad..2cf66189a0 100644 --- a/boost/test/data/monomorphic/grid.hpp +++ b/boost/test/data/monomorphic/grid.hpp @@ -22,6 +22,8 @@ #include <boost/test/data/monomorphic/fwd.hpp> #include <boost/test/data/monomorphic/sample_merge.hpp> +#include <boost/mpl/identity.hpp> + #include <boost/test/detail/suppress_warnings.hpp> //____________________________________________________________________________// diff --git a/boost/test/data/monomorphic/singleton.hpp b/boost/test/data/monomorphic/singleton.hpp index 586487a6d7..b0abd0eabb 100644 --- a/boost/test/data/monomorphic/singleton.hpp +++ b/boost/test/data/monomorphic/singleton.hpp @@ -81,7 +81,7 @@ struct is_dataset<singleton<T>> : mpl::true_ {}; /// @overload boost::unit_test::data::make() template<typename T> -inline typename std::enable_if<!is_forward_iterable<T>::value && +inline typename std::enable_if<!is_container_forward_iterable<T>::value && !monomorphic::is_dataset<T>::value && !boost::is_array<typename boost::remove_reference<T>::type>::value, monomorphic::singleton<T> diff --git a/boost/test/data/test_case.hpp b/boost/test/data/test_case.hpp index dd9de141c4..2275f90fff 100644 --- a/boost/test/data/test_case.hpp +++ b/boost/test/data/test_case.hpp @@ -16,6 +16,7 @@ #include <boost/test/data/config.hpp> #include <boost/test/data/dataset.hpp> #include <boost/test/data/for_each_sample.hpp> +#include <boost/test/tree/test_unit.hpp> // Boost #include <boost/preprocessor/repetition/enum_params.hpp> diff --git a/boost/test/detail/fwd_decl.hpp b/boost/test/detail/fwd_decl.hpp index 944d52267d..d5c97fb706 100644 --- a/boost/test/detail/fwd_decl.hpp +++ b/boost/test/detail/fwd_decl.hpp @@ -26,6 +26,7 @@ class master_test_suite_t; class test_tree_visitor; class test_observer; +class test_unit_fixture; // singletons class unit_test_monitor_t; diff --git a/boost/test/detail/global_typedef.hpp b/boost/test/detail/global_typedef.hpp index b9cfeb5206..aeede00e9c 100644 --- a/boost/test/detail/global_typedef.hpp +++ b/boost/test/detail/global_typedef.hpp @@ -71,6 +71,21 @@ test_id_2_unit_type( test_unit_id id ) return (id & 0xFFFF0000) != 0 ? TUT_CASE : TUT_SUITE; } +//! Helper class for restoring the current test unit ID in a RAII manner +struct test_unit_id_restore { + test_unit_id_restore(test_unit_id& to_restore_, test_unit_id new_value) + : to_restore(to_restore_) + , bkup(to_restore_) { + to_restore = new_value; + } + ~test_unit_id_restore() { + to_restore = bkup; + } +private: + test_unit_id& to_restore; + test_unit_id bkup; +}; + //____________________________________________________________________________// } // namespace ut_detail diff --git a/boost/test/execution_monitor.hpp b/boost/test/execution_monitor.hpp index adfb0336ca..ed06ef254e 100644 --- a/boost/test/execution_monitor.hpp +++ b/boost/test/execution_monitor.hpp @@ -270,6 +270,7 @@ public: /// Simple model for the location of failure in a source code struct BOOST_TEST_DECL location { explicit location( char const* file_name = 0, size_t line_num = 0, char const* func = 0 ); + explicit location( const_string file_name, size_t line_num = 0, char const* func = 0 ); const_string m_file_name; ///< File name size_t m_line_num; ///< Line number diff --git a/boost/test/framework.hpp b/boost/test/framework.hpp index f94bcf125d..099c02969b 100644 --- a/boost/test/framework.hpp +++ b/boost/test/framework.hpp @@ -74,7 +74,7 @@ BOOST_TEST_DECL bool test_in_progress(); /// This function shuts down the framework and clears up its mono-state. /// /// It needs to be at the very end of test module execution -BOOST_TEST_DECL void shutdown(); +BOOST_TEST_DECL void shutdown(); /// @} /// @name Test unit registration @@ -132,12 +132,28 @@ BOOST_TEST_DECL void clear(); /// @param[in] to test observer object to add BOOST_TEST_DECL void register_observer( test_observer& to ); -/// Excldes the observer object form the framework's list of test observers +/// Excludes the observer object form the framework's list of test observers /// @param[in] to test observer object to exclude BOOST_TEST_DECL void deregister_observer( test_observer& to ); /// @} +/// @name Global fixtures registration +/// @{ + +/// Adds a new global fixture to be setup before any other tests starts and tore down after +/// any other tests finished. +/// Test unit fixture lifetime should exceed the testing execution timeframe +/// @param[in] tuf fixture to add +BOOST_TEST_DECL void register_global_fixture( test_unit_fixture& tuf ); + +/// Removes a test global fixture from the framework +/// +/// Test unit fixture lifetime should exceed the testing execution timeframe +/// @param[in] tuf fixture to remove +BOOST_TEST_DECL void deregister_global_fixture( test_unit_fixture& tuf ); +/// @} + /// @name Assertion/uncaught exception context support /// @{ /// Context accessor @@ -178,6 +194,15 @@ BOOST_TEST_DECL context_generator get_context(); /// @returns a reference the master test suite instance BOOST_TEST_DECL master_test_suite_t& master_test_suite(); +/// This function provides an access to the test unit currently being executed. + +/// The difference with current_test_case is about the time between a test-suite +/// is being set up or torn down (fixtures) and when the test-cases of that suite start. + +/// This function is only valid during test execution phase. +/// @see current_test_case_id, current_test_case +BOOST_TEST_DECL test_unit const& current_test_unit(); + /// This function provides an access to the test case currently being executed. /// This function is only valid during test execution phase. @@ -231,6 +256,8 @@ BOOST_TEST_DECL void assertion_result( unit_test::assertion_resul BOOST_TEST_DECL void exception_caught( execution_exception const& ); /// Reports aborted test unit to all test observers BOOST_TEST_DECL void test_unit_aborted( test_unit const& ); +/// Reports aborted test module to all test observers +BOOST_TEST_DECL void test_aborted( ); /// @} namespace impl { diff --git a/boost/test/impl/compiler_log_formatter.ipp b/boost/test/impl/compiler_log_formatter.ipp index a4e045cae0..0e83448b14 100644 --- a/boost/test/impl/compiler_log_formatter.ipp +++ b/boost/test/impl/compiler_log_formatter.ipp @@ -52,7 +52,7 @@ namespace { std::string test_phase_identifier() { - return framework::test_in_progress() ? framework::current_test_case().full_name() : std::string( "Test setup" ); + return framework::test_in_progress() ? framework::current_test_unit().full_name() : std::string( "Test setup" ); } } // local namespace @@ -260,21 +260,29 @@ compiler_log_formatter::print_prefix( std::ostream& output, const_string file_na void compiler_log_formatter::entry_context_start( std::ostream& output, log_level l ) { - output << (l == log_successful_tests ? "\nAssertion" : "\nFailure" ) << " occurred in a following context:"; + if( l == log_messages ) { + output << "\n[context:"; + } + else { + output << (l == log_successful_tests ? "\nAssertion" : "\nFailure" ) << " occurred in a following context:"; + } } //____________________________________________________________________________// void -compiler_log_formatter::entry_context_finish( std::ostream& output ) +compiler_log_formatter::entry_context_finish( std::ostream& output, log_level l ) { + if( l == log_messages ) { + output << "]"; + } output.flush(); } //____________________________________________________________________________// void -compiler_log_formatter::log_entry_context( std::ostream& output, const_string context_descr ) +compiler_log_formatter::log_entry_context( std::ostream& output, log_level l, const_string context_descr ) { output << "\n " << context_descr; } diff --git a/boost/test/impl/execution_monitor.ipp b/boost/test/impl/execution_monitor.ipp index 0c5690ca89..94b6f9fbe7 100644 --- a/boost/test/impl/execution_monitor.ipp +++ b/boost/test/impl/execution_monitor.ipp @@ -1342,6 +1342,12 @@ execution_exception::location::location( char const* file_name, size_t line_num, , m_function( func ) {} +execution_exception::location::location(const_string file_name, size_t line_num, char const* func ) +: m_file_name( file_name ) +, m_line_num( line_num ) +, m_function( func ) +{} + //____________________________________________________________________________// // ************************************************************************** // diff --git a/boost/test/impl/framework.ipp b/boost/test/impl/framework.ipp index a35e8a54ac..ca35ce1c2a 100644 --- a/boost/test/impl/framework.ipp +++ b/boost/test/impl/framework.ipp @@ -27,6 +27,7 @@ #include <boost/test/results_collector.hpp> #include <boost/test/progress_monitor.hpp> #include <boost/test/results_reporter.hpp> +#include <boost/test/test_framework_init_observer.hpp> #include <boost/test/tree/observer.hpp> #include <boost/test/tree/test_unit.hpp> @@ -56,6 +57,9 @@ #include <cstdlib> #include <ctime> #include <numeric> +#ifdef BOOST_NO_CXX98_RANDOM_SHUFFLE +#include <iterator> +#endif #ifdef BOOST_NO_STDC_NAMESPACE namespace std { using ::time; using ::srand; } @@ -68,6 +72,7 @@ namespace std { using ::time; using ::srand; } namespace boost { namespace unit_test { namespace framework { + namespace impl { // ************************************************************************** // @@ -435,6 +440,46 @@ parse_filters( test_unit_id master_tu_id, test_unit_id_list& tu_to_enable, test_ //____________________________________________________________________________// +#ifdef BOOST_NO_CXX98_RANDOM_SHUFFLE + +// a poor man's implementation of random_shuffle +template< class RandomIt, class RandomFunc > +void random_shuffle( RandomIt first, RandomIt last, RandomFunc &r ) +{ + typedef typename std::iterator_traits<RandomIt>::difference_type difference_type; + difference_type n = last - first; + for (difference_type i = n-1; i > 0; --i) { + difference_type j = r(i+1); + if (j != i) { + using std::swap; + swap(first[i], first[j]); + } + } +} + +#endif + + +// A simple handle for registering the global fixtures to the master test suite +// without deleting an existing static object (the global fixture itself) when the program +// terminates (shared_ptr). +class global_fixture_handle : public test_unit_fixture { +public: + global_fixture_handle(test_unit_fixture* fixture) : m_global_fixture(fixture) {} + ~global_fixture_handle() {} + + virtual void setup() { + m_global_fixture->setup(); + } + virtual void teardown() { + m_global_fixture->teardown(); + } + +private: + test_unit_fixture* m_global_fixture; +}; + + } // namespace impl // ************************************************************************** // @@ -446,7 +491,7 @@ unsigned const TIMEOUT_EXCEEDED = static_cast<unsigned>( -1 ); class state { public: state() - : m_curr_test_case( INV_TEST_UNIT_ID ) + : m_curr_test_unit( INV_TEST_UNIT_ID ) , m_next_test_case_id( MIN_TEST_CASE_ID ) , m_next_test_suite_id( MIN_TEST_SUITE_ID ) , m_test_in_progress( false ) @@ -603,7 +648,7 @@ public: } }; - // Executed the test tree with the root at specified test unit + // Executes the test tree with the root at specified test unit execution_result execute_test_tree( test_unit_id tu_id, unsigned timeout = 0, random_generator_helper const * const p_random_generator = 0) @@ -642,9 +687,15 @@ public: // 30. Execute setup fixtures if any; any failure here leads to test unit abortion BOOST_TEST_FOREACH( test_unit_fixture_ptr, F, tu.p_fixtures.get() ) { + ut_detail::test_unit_id_restore restore_current_test_unit(m_curr_test_unit, tu.p_id); result = unit_test_monitor.execute_and_translate( boost::bind( &test_unit_fixture::setup, F ) ); if( result != unit_test_monitor_t::test_ok ) break; + test_results const& test_rslt = unit_test::results_collector.results( m_curr_test_unit ); + if( test_rslt.aborted() ) { + result = unit_test_monitor_t::precondition_failure; + break; + } } // This is the time we are going to spend executing the test unit @@ -688,7 +739,11 @@ public: const random_generator_helper& rand_gen = p_random_generator ? *p_random_generator : random_generator_helper(); +#ifdef BOOST_NO_CXX98_RANDOM_SHUFFLE + impl::random_shuffle( children_with_the_same_rank.begin(), children_with_the_same_rank.end(), rand_gen ); +#else std::random_shuffle( children_with_the_same_rank.begin(), children_with_the_same_rank.end(), rand_gen ); +#endif BOOST_TEST_FOREACH( test_unit_id, chld, children_with_the_same_rank ) { unsigned chld_timeout = child_timeout( timeout, tu_timer.elapsed() ); @@ -710,8 +765,7 @@ public: m_context_idx = 0; // setup current test case - test_unit_id bkup = m_curr_test_case; - m_curr_test_case = tc.p_id; + ut_detail::test_unit_id_restore restore_current_test_unit(m_curr_test_unit, tc.p_id); // execute the test case body result = unit_test_monitor.execute_and_translate( tc.p_test_func, timeout ); @@ -720,8 +774,7 @@ public: // cleanup leftover context m_context.clear(); - // restore state and abort if necessary - m_curr_test_case = bkup; + // restore state (scope exit) and abort if necessary } } @@ -729,6 +782,7 @@ public: if( !unit_test_monitor.is_critical_error( result ) ) { // execute teardown fixtures if any in reverse order BOOST_TEST_REVERSE_FOREACH( test_unit_fixture_ptr, F, tu.p_fixtures.get() ) { + ut_detail::test_unit_id_restore restore_current_test_unit(m_curr_test_unit, tu.p_id); result = (std::min)( result, unit_test_monitor.execute_and_translate( boost::bind( &test_unit_fixture::teardown, F ), 0 ) ); if( unit_test_monitor.is_critical_error( result ) ) @@ -787,7 +841,7 @@ public: master_test_suite_t* m_master_test_suite; std::vector<test_suite*> m_auto_test_suites; - test_unit_id m_curr_test_case; + test_unit_id m_curr_test_unit; test_unit_store m_test_units; test_unit_id m_next_test_case_id; @@ -799,6 +853,8 @@ public: context_data m_context; int m_context_idx; + std::set<test_unit_fixture*> m_global_fixtures; + boost::execution_monitor m_aux_em; std::map<output_format, runtime_config::stream_holder> m_log_sinks; @@ -1043,6 +1099,7 @@ init( init_unit_test_func init_func, int argc, char* argv[] ) // 40. Register default test observers register_observer( results_collector ); register_observer( unit_test_log ); + register_observer( framework_init_observer ); if( runtime_config::get<bool>( runtime_config::btrt_show_progress ) ) { progress_monitor.set_stream( std::cout ); // defaults to stdout @@ -1236,6 +1293,30 @@ deregister_observer( test_observer& to ) //____________________________________________________________________________// // ************************************************************************** // +// ************** register_global_fixture ************** // +// ************************************************************************** // + +void +register_global_fixture( test_unit_fixture& tuf ) +{ + impl::s_frk_state().m_global_fixtures.insert( &tuf ); +} + +//____________________________________________________________________________// + +// ************************************************************************** // +// ************** deregister_global_fixture ************** // +// ************************************************************************** // + +void +deregister_global_fixture( test_unit_fixture &tuf ) +{ + impl::s_frk_state().m_global_fixtures.erase( &tuf ); +} + +//____________________________________________________________________________// + +// ************************************************************************** // // ************** add_context ************** // // ************************************************************************** // @@ -1363,7 +1444,14 @@ current_auto_test_suite( test_suite* ts, bool push_or_pop ) test_case const& current_test_case() { - return get<test_case>( impl::s_frk_state().m_curr_test_case ); + return get<test_case>( impl::s_frk_state().m_curr_test_unit ); +} + + +test_unit const& +current_test_unit() +{ + return *impl::s_frk_state().m_test_units[impl::s_frk_state().m_curr_test_unit]; } //____________________________________________________________________________// @@ -1371,7 +1459,7 @@ current_test_case() test_unit_id current_test_case_id() { - return impl::s_frk_state().m_curr_test_case; + return impl::s_frk_state().m_curr_test_unit; } //____________________________________________________________________________// @@ -1396,6 +1484,17 @@ get( test_unit_id id, test_unit_type t ) // ************** framework::run ************** // // ************************************************************************** // +template <class Cont> +struct swap_on_delete { + swap_on_delete(Cont& c1, Cont& c2) : m_c1(c1), m_c2(c2){} + ~swap_on_delete() { + m_c1.swap(m_c2); + } + + Cont& m_c1; + Cont& m_c2; +}; + void run( test_unit_id id, bool continue_test ) { @@ -1414,39 +1513,90 @@ run( test_unit_id id, bool continue_test ) bool was_in_progress = framework::test_in_progress(); bool call_start_finish = !continue_test || !was_in_progress; - - impl::s_frk_state().m_test_in_progress = true; + bool init_ok = true; + const_string setup_error; if( call_start_finish ) { + // indicates the framework that no test is in progress now if observers need to be notified + impl::s_frk_state().m_test_in_progress = false; + // unit_test::framework_init_observer will get cleared first BOOST_TEST_FOREACH( test_observer*, to, impl::s_frk_state().m_observers ) { BOOST_TEST_I_TRY { - impl::s_frk_state().m_aux_em.vexecute( boost::bind( &test_observer::test_start, to, tcc.p_count ) ); + ut_detail::test_unit_id_restore restore_current_test_unit(impl::s_frk_state().m_curr_test_unit, id); + unit_test_monitor_t::error_level result = unit_test_monitor.execute_and_translate( boost::bind( &test_observer::test_start, to, tcc.p_count ) ); + if( init_ok ) { + if( result != unit_test_monitor_t::test_ok ) { + init_ok = false; + } + else { + if( unit_test::framework_init_observer.has_failed() ) { + init_ok = false; + } + } + } } BOOST_TEST_I_CATCH( execution_exception, ex ) { - BOOST_TEST_SETUP_ASSERT( false, ex.what() ); + if( init_ok ) { + // log only the first error + init_ok = false; + setup_error = ex.what(); + } + // break; // we should continue otherwise loggers may have improper structure (XML start missing for instance) } } } - unsigned seed = runtime_config::get<unsigned>( runtime_config::btrt_random_seed ); - switch( seed ) { - case 0: - break; - case 1: - seed = static_cast<unsigned>( std::rand() ^ std::time( 0 ) ); // better init using std::rand() ^ ... - default: - BOOST_TEST_FRAMEWORK_MESSAGE( "Test cases order is shuffled using seed: " << seed ); - std::srand( seed ); + if( init_ok ) { + + // attaching the global fixtures to the main entry point + test_unit& entry_test_unit = framework::get( id, TUT_ANY ); + std::vector<test_unit_fixture_ptr> v_saved_fixture(entry_test_unit.p_fixtures.value.begin(), + entry_test_unit.p_fixtures.value.end()); + + BOOST_TEST_FOREACH( test_unit_fixture*, tuf, impl::s_frk_state().m_global_fixtures ) { + entry_test_unit.p_fixtures.value.insert( entry_test_unit.p_fixtures.value.begin(), + test_unit_fixture_ptr(new impl::global_fixture_handle(tuf)) ); + } + + swap_on_delete< std::vector<test_unit_fixture_ptr> > raii_fixture(v_saved_fixture, entry_test_unit.p_fixtures.value); + + // now work in progress + impl::s_frk_state().m_test_in_progress = true; + unsigned seed = runtime_config::get<unsigned>( runtime_config::btrt_random_seed ); + switch( seed ) { + case 0: + break; + case 1: + seed = static_cast<unsigned>( std::rand() ^ std::time( 0 ) ); // better init using std::rand() ^ ... + default: + BOOST_TEST_FRAMEWORK_MESSAGE( "Test cases order is shuffled using seed: " << seed ); + std::srand( seed ); + } + + // executing the test tree + impl::s_frk_state().execute_test_tree( id ); + + // removing previously added global fixtures: dtor raii_fixture } - impl::s_frk_state().execute_test_tree( id ); + impl::s_frk_state().m_test_in_progress = false; + unit_test::framework_init_observer.clear(); if( call_start_finish ) { - BOOST_TEST_REVERSE_FOREACH( test_observer*, to, impl::s_frk_state().m_observers ) + // indicates the framework that no test is in progress anymore if observers need to be notified + // and this is a teardown, so assertions should not raise any exception otherwise an exception + // might be raised in a dtor of a global fixture + impl::s_frk_state().m_test_in_progress = false; + BOOST_TEST_REVERSE_FOREACH( test_observer*, to, impl::s_frk_state().m_observers ) { + ut_detail::test_unit_id_restore restore_current_test_unit(impl::s_frk_state().m_curr_test_unit, id); to->test_finish(); + } } impl::s_frk_state().m_test_in_progress = was_in_progress; + + // propagates the init/teardown error if any + BOOST_TEST_SETUP_ASSERT( init_ok && !unit_test::framework_init_observer.has_failed(), setup_error ); } //____________________________________________________________________________// @@ -1496,6 +1646,18 @@ test_unit_aborted( test_unit const& tu ) to->test_unit_aborted( tu ); } +// ************************************************************************** // +// ************** test_aborted ************** // +// ************************************************************************** // + +void +test_aborted( ) +{ + BOOST_TEST_FOREACH( test_observer*, to, impl::s_frk_state().m_observers ) + to->test_aborted( ); +} + + //____________________________________________________________________________// } // namespace framework diff --git a/boost/test/impl/junit_log_formatter.ipp b/boost/test/impl/junit_log_formatter.ipp index dd528bc903..0ec8d43832 100644 --- a/boost/test/impl/junit_log_formatter.ipp +++ b/boost/test/impl/junit_log_formatter.ipp @@ -69,6 +69,12 @@ inline std::string tu_name_normalize(std::string full_name) return full_name; } +inline std::string tu_name_remove_newlines(std::string full_name) +{ + full_name.erase(std::remove(full_name.begin(), full_name.end(), '\n'), full_name.end()); + return full_name; +} + const_string file_basename(const_string filename) { const_string path_sep( "\\/" ); @@ -86,7 +92,7 @@ const_string file_basename(const_string filename) { // ************************************************************************** // void -junit_log_formatter::log_start( std::ostream& ostr, counter_t test_cases_amount) +junit_log_formatter::log_start( std::ostream& /*ostr*/, counter_t /*test_cases_amount*/) { map_tests.clear(); list_path_to_root.clear(); @@ -96,6 +102,11 @@ junit_log_formatter::log_start( std::ostream& ostr, counter_t test_cases_amount) //____________________________________________________________________________// class junit_result_helper : public test_tree_visitor { +private: + typedef junit_impl::junit_log_helper::assertion_entry assertion_entry; + typedef std::vector< assertion_entry >::const_iterator vect_assertion_entry_citerator; + typedef std::list<std::string>::const_iterator list_str_citerator; + public: explicit junit_result_helper( std::ostream& stream, @@ -111,10 +122,19 @@ public: , m_display_build_info(display_build_info) { } - void add_log_entry(std::string const& entry_type, - test_case const& tc, - junit_impl::junit_log_helper::assertion_entry const& log) const + void add_log_entry(assertion_entry const& log) const { + std::string entry_type; + if( log.log_entry == assertion_entry::log_entry_failure ) { + entry_type = "failure"; + } + else if( log.log_entry == assertion_entry::log_entry_error ) { + entry_type = "error"; + } + else { + return; + } + m_stream << "<" << entry_type << " message" << utils::attr_value() << log.logentry_message @@ -159,24 +179,24 @@ public: } }; - std::list<std::string> build_skipping_chain(test_case const & tc) const + std::list<std::string> build_skipping_chain(test_unit const & tu) const { - // we enter here because we know that the tc has been skipped. - // either junit has not seen this tc, or it is indicated as disabled - assert(m_map_test.count(tc.p_id) == 0 || results_collector.results( tc.p_id ).p_skipped); + // we enter here because we know that the tu has been skipped. + // either junit has not seen this tu, or it is indicated as disabled + assert(m_map_test.count(tu.p_id) == 0 || results_collector.results( tu.p_id ).p_skipped); std::list<std::string> out; - test_unit_id id(tc.p_id); + test_unit_id id(tu.p_id); while( id != m_ts.p_id && id != INV_TEST_UNIT_ID) { - test_unit const& tu = boost::unit_test::framework::get( id, TUT_ANY ); - out.push_back("- disabled test unit: '" + tu.full_name() + "'\n"); + test_unit const& tu_hierarchy = boost::unit_test::framework::get( id, TUT_ANY ); + out.push_back("- disabled test unit: '" + tu_name_remove_newlines(tu_hierarchy.full_name()) + "'\n"); if(m_map_test.count(id) > 0) { // junit has seen the reason: this is enough for constructing the chain break; } - id = tu.p_parent_id; + id = tu_hierarchy.p_parent_id; } junit_log_formatter::map_trace_t::const_iterator it_element_stack(m_map_test.find(id)); if( it_element_stack != m_map_test.end() ) @@ -188,9 +208,9 @@ public: return out; } - std::string get_class_name(test_case const & tc) const { + std::string get_class_name(test_unit const & tu_class) const { std::string classname; - test_unit_id id(tc.p_parent_id); + test_unit_id id(tu_class.p_parent_id); while( id != m_ts.p_id && id != INV_TEST_UNIT_ID ) { test_unit const& tu = boost::unit_test::framework::get( id, TUT_ANY ); classname = tu_name_normalize(tu.p_name) + "." + classname; @@ -205,39 +225,47 @@ public: return classname; } - void write_testcase_header(test_case const & tc, - test_results const *tr = 0) const + void write_testcase_header(test_unit const & tu, + test_results const *tr, + int nb_assertions) const { - // - // test case header + std::string name; + std::string classname; - // total number of assertions - m_stream << "<testcase assertions" << utils::attr_value() << tr->p_assertions_passed + tr->p_assertions_failed; + if(tu.p_id == m_ts.p_id ) { + name = "boost_test"; + } + else { + classname = get_class_name(tu); + name = tu_name_normalize(tu.p_name); + } - // class name - const std::string classname = get_class_name(tc); + if( tu.p_type == TUT_SUITE ) { + name += "-setup-teardown"; + } + + m_stream << "<testcase assertions" << utils::attr_value() << nb_assertions; if(!classname.empty()) m_stream << " classname" << utils::attr_value() << classname; // test case name and time taken m_stream - << " name" << utils::attr_value() << tu_name_normalize(tc.p_name) + << " name" << utils::attr_value() << name << " time" << utils::attr_value() << double(tr->p_duration_microseconds) * 1E-6 << ">" << std::endl; } void write_testcase_system_out(junit_impl::junit_log_helper const &detailed_log, - test_case const * tc, - bool skipped, - test_results const *tr = 0) const + test_unit const * tu, + bool skipped) const { // system-out + all info/messages, the object skips the empty entries conditional_cdata_helper system_out_helper(m_stream, "system-out"); // indicate why the test has been skipped first if( skipped ) { - std::list<std::string> skipping_decision_chain = build_skipping_chain(*tc); - for(std::list<std::string>::const_iterator it(skipping_decision_chain.begin()), ite(skipping_decision_chain.end()); + std::list<std::string> skipping_decision_chain = build_skipping_chain(*tu); + for(list_str_citerator it(skipping_decision_chain.begin()), ite(skipping_decision_chain.end()); it != ite; ++it) { @@ -246,7 +274,7 @@ public: } // stdout - for(std::list<std::string>::const_iterator it(detailed_log.system_out.begin()), ite(detailed_log.system_out.end()); + for(list_str_citerator it(detailed_log.system_out.begin()), ite(detailed_log.system_out.end()); it != ite; ++it) { @@ -254,25 +282,24 @@ public: } // warning/info message last - for(std::vector< junit_impl::junit_log_helper::assertion_entry >::const_iterator it(detailed_log.assertion_entries.begin()); + for(vect_assertion_entry_citerator it(detailed_log.assertion_entries.begin()); it != detailed_log.assertion_entries.end(); ++it) { - if(it->log_entry != junit_impl::junit_log_helper::assertion_entry::log_entry_info) + if(it->log_entry != assertion_entry::log_entry_info) continue; system_out_helper(it->output); } } void write_testcase_system_err(junit_impl::junit_log_helper const &detailed_log, - test_case const * tc, - test_results const *tr = 0) const + test_unit const * tu, + test_results const *tr) const { // system-err output + test case informations - bool has_failed = (tr != 0) ? !tr->passed() : false; + bool has_failed = (tr != 0) ? !tr->p_skipped && !tr->passed() : false; if(!detailed_log.system_err.empty() || has_failed) { - conditional_cdata_helper system_err_helper(m_stream, "system-err"); std::ostringstream o; if(has_failed) { o << "Failures detected in:" << std::endl; @@ -281,58 +308,89 @@ public: o << "ERROR STREAM:" << std::endl; } - o << "- test case: " << tc->full_name() << std::endl; - if(!tc->p_description.value.empty()) - o << " '" << tc->p_description << "'"; - - o << std::endl - << "- file: " << file_basename(tc->p_file_name) << std::endl - << "- line: " << tc->p_line_num << std::endl - ; + if(tu->p_type == TUT_SUITE) { + if( tu->p_id == m_ts.p_id ) { + o << " boost.test global setup/teardown" << std::endl; + } else { + o << "- test suite: " << tu_name_remove_newlines(tu->full_name()) << std::endl; + } + } + else { + o << "- test case: " << tu_name_remove_newlines(tu->full_name()); + if(!tu->p_description.value.empty()) + o << " '" << tu->p_description << "'"; + + o << std::endl + << "- file: " << file_basename(tu->p_file_name) << std::endl + << "- line: " << tu->p_line_num << std::endl + ; + } if(!detailed_log.system_err.empty()) o << std::endl << "STDERR BEGIN: ------------" << std::endl; - system_err_helper(o.str()); - for(std::list<std::string>::const_iterator it(detailed_log.system_err.begin()), ite(detailed_log.system_err.end()); + for(list_str_citerator it(detailed_log.system_err.begin()), ite(detailed_log.system_err.end()); it != ite; ++it) { - system_err_helper(*it); + o << *it; } if(!detailed_log.system_err.empty()) o << std::endl << "STDERR END ------------" << std::endl; + + conditional_cdata_helper system_err_helper(m_stream, "system-err"); + system_err_helper(o.str()); + } + } + + int get_nb_assertions(junit_impl::junit_log_helper const &detailed_log, + test_unit const & tu, + test_results const *tr) const { + int nb_assertions(-1); + if( tu.p_type == TUT_SUITE ) { + nb_assertions = 0; + for(vect_assertion_entry_citerator it(detailed_log.assertion_entries.begin()); + it != detailed_log.assertion_entries.end(); + ++it) + { + if(it->log_entry != assertion_entry::log_entry_info) + nb_assertions++; + } + } + else { + nb_assertions = tr->p_assertions_passed + tr->p_assertions_failed; } + + return nb_assertions; } void output_detailed_logs(junit_impl::junit_log_helper const &detailed_log, - test_case const & tc, + test_unit const & tu, bool skipped, - test_results const *tr = 0) const + test_results const *tr) const { - write_testcase_header(tc, tr); + int nb_assertions = get_nb_assertions(detailed_log, tu, tr); + if(!nb_assertions && tu.p_type == TUT_SUITE) + return; + + write_testcase_header(tu, tr, nb_assertions); if( skipped ) { m_stream << "<skipped/>" << std::endl; } else { - for(std::vector< junit_impl::junit_log_helper::assertion_entry >::const_iterator it(detailed_log.assertion_entries.begin()); + for(vect_assertion_entry_citerator it(detailed_log.assertion_entries.begin()); it != detailed_log.assertion_entries.end(); ++it) { - if(it->log_entry == junit_impl::junit_log_helper::assertion_entry::log_entry_failure) { - add_log_entry("failure", tc, *it); - } - else if(it->log_entry == junit_impl::junit_log_helper::assertion_entry::log_entry_error) { - add_log_entry("error", tc, *it); - } + add_log_entry(*it); } } - write_testcase_system_out(detailed_log, &tc, skipped, tr); - write_testcase_system_err(detailed_log, &tc, tr); + write_testcase_system_out(detailed_log, &tu, skipped); + write_testcase_system_err(detailed_log, &tu, tr); m_stream << "</testcase>" << std::endl; } @@ -353,35 +411,45 @@ public: bool test_suite_start( test_suite const& ts ) { - // unique test suite, without s, nesting not supported in CI - if( m_ts.p_id != ts.p_id ) - return true; - test_results const& tr = results_collector.results( ts.p_id ); - m_stream << "<testsuite"; - m_stream - // << "disabled=\"" << tr.p_test_cases_skipped << "\" " - << " tests" << utils::attr_value() << tr.p_test_cases_passed - << " skipped" << utils::attr_value() << tr.p_test_cases_skipped - << " errors" << utils::attr_value() << tr.p_test_cases_aborted - << " failures" << utils::attr_value() << tr.p_test_cases_failed - << " id" << utils::attr_value() << m_id++ - << " name" << utils::attr_value() << tu_name_normalize(ts.p_name) - << " time" << utils::attr_value() << (tr.p_duration_microseconds * 1E-6) - << ">" << std::endl; - - if(m_display_build_info) - { - m_stream << "<properties>" << std::endl; - m_stream << "<property name=\"platform\" value" << utils::attr_value() << BOOST_PLATFORM << std::endl; - m_stream << "<property name=\"compiler\" value" << utils::attr_value() << BOOST_COMPILER << std::endl; - m_stream << "<property name=\"stl\" value" << utils::attr_value() << BOOST_STDLIB << std::endl; + // unique test suite, without s, nesting not supported in CI + if( m_ts.p_id == ts.p_id ) { + m_stream << "<testsuite"; + + m_stream + // << "disabled=\"" << tr.p_test_cases_skipped << "\" " + << " tests" << utils::attr_value() << tr.p_test_cases_passed + << " skipped" << utils::attr_value() << tr.p_test_cases_skipped + << " errors" << utils::attr_value() << tr.p_test_cases_aborted + << " failures" << utils::attr_value() << tr.p_test_cases_failed + << " id" << utils::attr_value() << m_id++ + << " name" << utils::attr_value() << tu_name_normalize(ts.p_name) + << " time" << utils::attr_value() << (tr.p_duration_microseconds * 1E-6) + << ">" << std::endl; + + if(m_display_build_info) + { + m_stream << "<properties>" << std::endl; + m_stream << "<property name=\"platform\" value" << utils::attr_value() << BOOST_PLATFORM << std::endl; + m_stream << "<property name=\"compiler\" value" << utils::attr_value() << BOOST_COMPILER << std::endl; + m_stream << "<property name=\"stl\" value" << utils::attr_value() << BOOST_STDLIB << std::endl; + + std::ostringstream o; + o << BOOST_VERSION/100000 << "." << BOOST_VERSION/100 % 1000 << "." << BOOST_VERSION % 100; + m_stream << "<property name=\"boost\" value" << utils::attr_value() << o.str() << std::endl; + m_stream << "</properties>" << std::endl; + } + } - std::ostringstream o; - o << BOOST_VERSION/100000 << "." << BOOST_VERSION/100 % 1000 << "." << BOOST_VERSION % 100; - m_stream << "<property name=\"boost\" value" << utils::attr_value() << o.str() << std::endl; - m_stream << "</properties>" << std::endl; + if( !tr.p_skipped ) { + // if we land here, then this is a chance that we are logging the fixture setup/teardown of a test-suite. + // the setup/teardown logging of a test-case is part of the test case. + // we do not care about the test-suite that were skipped (really??) + junit_log_formatter::map_trace_t::const_iterator it_find = m_map_test.find(ts.p_id); + if(it_find != m_map_test.end()) { + output_detailed_logs(it_find->second, ts, false, &tr); + } } return true; // indicates that the children should also be parsed @@ -389,13 +457,13 @@ public: virtual void test_suite_finish( test_suite const& ts ) { - if( m_ts.p_id != ts.p_id ) - return; + if( m_ts.p_id == ts.p_id ) { + write_testcase_system_out(runner_log, 0, false); + write_testcase_system_err(runner_log, 0, 0); - write_testcase_system_out(runner_log, 0, false, 0); - write_testcase_system_err(runner_log, 0, 0); - - m_stream << "</testsuite>"; + m_stream << "</testsuite>"; + return; + } } private: @@ -439,7 +507,7 @@ junit_log_formatter::log_finish( std::ostream& ostr ) //____________________________________________________________________________// void -junit_log_formatter::log_build_info( std::ostream& ostr ) +junit_log_formatter::log_build_info( std::ostream& /*ostr*/ ) { m_display_build_info = true; } @@ -447,7 +515,7 @@ junit_log_formatter::log_build_info( std::ostream& ostr ) //____________________________________________________________________________// void -junit_log_formatter::test_unit_start( std::ostream& ostr, test_unit const& tu ) +junit_log_formatter::test_unit_start( std::ostream& /*ostr*/, test_unit const& tu ) { list_path_to_root.push_back( tu.p_id ); map_tests.insert(std::make_pair(tu.p_id, junit_impl::junit_log_helper())); // current_test_case_id not working here @@ -458,7 +526,7 @@ junit_log_formatter::test_unit_start( std::ostream& ostr, test_unit const& tu ) //____________________________________________________________________________// void -junit_log_formatter::test_unit_finish( std::ostream& ostr, test_unit const& tu, unsigned long elapsed ) +junit_log_formatter::test_unit_finish( std::ostream& /*ostr*/, test_unit const& tu, unsigned long /*elapsed*/ ) { // the time is already stored in the result_reporter assert( tu.p_id == list_path_to_root.back() ); @@ -466,7 +534,7 @@ junit_log_formatter::test_unit_finish( std::ostream& ostr, test_unit const& tu, } void -junit_log_formatter::test_unit_aborted( std::ostream& os, test_unit const& tu ) +junit_log_formatter::test_unit_aborted( std::ostream& /*ostr*/, test_unit const& tu ) { assert( tu.p_id == list_path_to_root.back() ); //list_path_to_root.pop_back(); @@ -475,7 +543,7 @@ junit_log_formatter::test_unit_aborted( std::ostream& os, test_unit const& tu ) //____________________________________________________________________________// void -junit_log_formatter::test_unit_skipped( std::ostream& ostr, test_unit const& tu, const_string reason ) +junit_log_formatter::test_unit_skipped( std::ostream& /*ostr*/, test_unit const& tu, const_string reason ) { // if a test unit is skipped, then the start of this TU has not been called yet. // we cannot use get_current_log_entry here, but the TU id should appear in the map. @@ -487,7 +555,7 @@ junit_log_formatter::test_unit_skipped( std::ostream& ostr, test_unit const& tu, //____________________________________________________________________________// void -junit_log_formatter::log_exception_start( std::ostream& ostr, log_checkpoint_data const& checkpoint_data, execution_exception const& ex ) +junit_log_formatter::log_exception_start( std::ostream& /*ostr*/, log_checkpoint_data const& checkpoint_data, execution_exception const& ex ) { std::ostringstream o; execution_exception::location const& loc = ex.where(); @@ -555,7 +623,7 @@ junit_log_formatter::log_exception_start( std::ostream& ostr, log_checkpoint_dat //____________________________________________________________________________// void -junit_log_formatter::log_exception_finish( std::ostream& ostr ) +junit_log_formatter::log_exception_finish( std::ostream& /*ostr*/ ) { // sealing the last entry assert(!get_current_log_entry().assertion_entries.back().sealed); @@ -565,7 +633,7 @@ junit_log_formatter::log_exception_finish( std::ostream& ostr ) //____________________________________________________________________________// void -junit_log_formatter::log_entry_start( std::ostream& ostr, log_entry_data const& entry_data, log_entry_types let ) +junit_log_formatter::log_entry_start( std::ostream& /*ostr*/, log_entry_data const& entry_data, log_entry_types let ) { junit_impl::junit_log_helper& last_entry = get_current_log_entry(); last_entry.skipping = false; @@ -638,7 +706,7 @@ junit_log_formatter::log_entry_start( std::ostream& ostr, log_entry_data const& //____________________________________________________________________________// void -junit_log_formatter::log_entry_value( std::ostream& ostr, const_string value ) +junit_log_formatter::log_entry_value( std::ostream& /*ostr*/, const_string value ) { junit_impl::junit_log_helper& last_entry = get_current_log_entry(); if(last_entry.skipping) @@ -662,7 +730,7 @@ junit_log_formatter::log_entry_value( std::ostream& ostr, const_string value ) //____________________________________________________________________________// void -junit_log_formatter::log_entry_finish( std::ostream& ostr ) +junit_log_formatter::log_entry_finish( std::ostream& /*ostr*/ ) { junit_impl::junit_log_helper& last_entry = get_current_log_entry(); if(!last_entry.skipping) @@ -685,7 +753,7 @@ junit_log_formatter::log_entry_finish( std::ostream& ostr ) //____________________________________________________________________________// void -junit_log_formatter::entry_context_start( std::ostream& ostr, log_level ) +junit_log_formatter::entry_context_start( std::ostream& /*ostr*/, log_level ) { junit_impl::junit_log_helper& last_entry = get_current_log_entry(); if(last_entry.skipping) @@ -708,7 +776,7 @@ junit_log_formatter::entry_context_start( std::ostream& ostr, log_level ) //____________________________________________________________________________// void -junit_log_formatter::entry_context_finish( std::ostream& ostr ) +junit_log_formatter::entry_context_finish( std::ostream& /*ostr*/, log_level ) { // no op, may be removed junit_impl::junit_log_helper& last_entry = get_current_log_entry(); @@ -720,7 +788,7 @@ junit_log_formatter::entry_context_finish( std::ostream& ostr ) //____________________________________________________________________________// void -junit_log_formatter::log_entry_context( std::ostream& ostr, const_string context_descr ) +junit_log_formatter::log_entry_context( std::ostream& /*ostr*/, log_level , const_string context_descr ) { junit_impl::junit_log_helper& last_entry = get_current_log_entry(); if(last_entry.skipping) diff --git a/boost/test/impl/results_collector.ipp b/boost/test/impl/results_collector.ipp index daee8bc3bf..fd74bdb65c 100644 --- a/boost/test/impl/results_collector.ipp +++ b/boost/test/impl/results_collector.ipp @@ -59,6 +59,12 @@ test_results::passed() const !p_aborted; } +bool +test_results::aborted() const +{ + return p_aborted; +} + //____________________________________________________________________________// int diff --git a/boost/test/impl/test_framework_init_observer.ipp b/boost/test/impl/test_framework_init_observer.ipp new file mode 100644 index 0000000000..89f854aaed --- /dev/null +++ b/boost/test/impl/test_framework_init_observer.ipp @@ -0,0 +1,109 @@ +// (c) Copyright Raffi Enficiaud 2017. +// 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) + +// See http://www.boost.org/libs/test for the library home page. +// +//! @file +//! An observer for monitoring the success/failure of the other observers +// *************************************************************************** + +#ifndef BOOST_TEST_FRAMEWORK_INIT_OBSERVER_IPP_021105GER +#define BOOST_TEST_FRAMEWORK_INIT_OBSERVER_IPP_021105GER + +// Boost.Test +#include <boost/test/test_framework_init_observer.hpp> +#include <boost/test/framework.hpp> +#include <boost/test/detail/suppress_warnings.hpp> + +//____________________________________________________________________________// + +namespace boost { +namespace unit_test { + + +//____________________________________________________________________________// + +// ************************************************************************** // +// ************** framework_init_observer_t ************** // +// ************************************************************************** // + +namespace { + +struct test_init_observer_check { + bool has_failure; + + void clear() + { + has_failure = false; + } +}; + + +test_init_observer_check& s_tioc_impl() { static test_init_observer_check the_inst; return the_inst; } + +} // local namespace + +void +framework_init_observer_t::clear() +{ + if(!framework::test_in_progress()) + s_tioc_impl().clear(); +} + +//____________________________________________________________________________// + +void +framework_init_observer_t::test_start( counter_t ) +{ + clear(); +} + +//____________________________________________________________________________// + +void +framework_init_observer_t::assertion_result( unit_test::assertion_result ar ) +{ + test_init_observer_check& tr = s_tioc_impl(); + switch( ar ) { + case AR_TRIGGERED: break; + case AR_PASSED: break; + case AR_FAILED: tr.has_failure = true; break; + default: + break; + } +} + +//____________________________________________________________________________// + +void +framework_init_observer_t::exception_caught( execution_exception const& ) +{ + test_init_observer_check& tr = s_tioc_impl(); + tr.has_failure = true; +} + +void +framework_init_observer_t::test_aborted() +{ + s_tioc_impl().has_failure = true; +} + + +//____________________________________________________________________________// + +bool +framework_init_observer_t::has_failed() const +{ + return s_tioc_impl().has_failure; +} + +//____________________________________________________________________________// + +} // namespace unit_test +} // namespace boost + +#include <boost/test/detail/enable_warnings.hpp> + +#endif // BOOST_TEST_FRAMEWORK_INIT_OBSERVER_IPP_021105GER diff --git a/boost/test/impl/test_tools.ipp b/boost/test/impl/test_tools.ipp index 853b3913ee..7e01453313 100644 --- a/boost/test/impl/test_tools.ipp +++ b/boost/test/impl/test_tools.ipp @@ -121,7 +121,7 @@ print_log_value<wchar_t const*>::operator()( std::ostream& ostr, wchar_t const* #if !defined(BOOST_NO_CXX11_NULLPTR) void -print_log_value<std::nullptr_t>::operator()( std::ostream& ostr, std::nullptr_t p ) +print_log_value<std::nullptr_t>::operator()( std::ostream& ostr, std::nullptr_t ) { ostr << "nullptr"; } @@ -310,8 +310,19 @@ report_assertion( assertion_result const& ar, { using namespace unit_test; - BOOST_TEST_I_ASSRT( framework::current_test_case_id() != INV_TEST_UNIT_ID, - std::runtime_error( "Can't use testing tools outside of test case implementation." ) ); + if( !framework::test_in_progress() ) { + // in case no test is in progress, we do not throw anything: + // raising an exception here may result in raising an exception in a destructor of a global fixture + // which will abort the process + // We flag this as aborted instead + + //BOOST_TEST_I_ASSRT( framework::current_test_case_id() != INV_TEST_UNIT_ID, + // std::runtime_error( "Can't use testing tools outside of test case implementation." ) ); + + framework::test_aborted(); + return false; + } + if( !!ar ) tl = PASS; @@ -369,10 +380,9 @@ report_assertion( assertion_result const& ar, case REQUIRE: framework::assertion_result( AR_FAILED ); - - framework::test_unit_aborted( framework::current_test_case() ); - + framework::test_unit_aborted( framework::current_test_unit() ); BOOST_TEST_I_THROW( execution_aborted() ); + return false; } return true; @@ -493,7 +503,7 @@ struct output_test_stream::Impl char get_char() { - char res; + char res = 0; do { m_pattern.get( res ); } while( m_text_or_binary && res == '\r' && !m_pattern.fail() && !m_pattern.eof() ); @@ -619,6 +629,7 @@ output_test_stream::match_pattern( bool flush_stream ) int offset = 0; std::vector<char> last_elements; for ( std::string::size_type i = 0; static_cast<int>(i + offset) < static_cast<int>(stream_string_repr.length()); ++i ) { + char c = m_pimpl->get_char(); if( last_elements.size() <= n_chars_presuffix ) { @@ -698,7 +709,7 @@ output_test_stream::match_pattern( bool flush_stream ) if( last_elements_ordered[pattern_start_index + k] == sub_str_suffix[stream_start_index + k] ) nb_char_in_common ++; else - break; // we take fully macthing substring only + break; // we take fully matching substring only } if( nb_char_in_common > max_nb_char_in_common ) { @@ -709,20 +720,32 @@ output_test_stream::match_pattern( bool flush_stream ) } } - // indicates with more precision the location of the mismatchs in ascii arts ... + // indicates with more precision the location of the mismatchs in "ascii arts" ... result.message() << " ...\n... "; for( std::string::size_type j = 0; j < sub_str_prefix.size(); j++) { result.message() << ' '; } - for( std::size_t k = 0; k < (std::max)(best_pattern_start_index, best_stream_start_index); k++ ) { // 1 is for the current char c + result.message() << '~'; // places the first tilde at the current char that mismatches + + for( std::size_t k = 1; k < (std::max)(best_pattern_start_index, best_stream_start_index); k++ ) { // 1 is for the current char c std::string s1(pretty_print_log(std::string(1, last_elements_ordered[(std::min)(k, best_pattern_start_index)]))); std::string s2(pretty_print_log(std::string(1, sub_str_suffix[(std::min)(k, best_stream_start_index)]))); for( int h = (std::max)(s1.size(), s2.size()); h > 0; h--) - result.message() << "~"; + result.message() << "~"; + } + + if( m_pimpl->m_pattern.eof() ) { + result.message() << " (reference string shorter than current stream)"; } + result.message() << "\n"; + // no need to continue if the EOF is reached + if( m_pimpl->m_pattern.eof() ) { + break; + } + // first char is a replicat of c, so we do not copy it. for(std::string::size_type counter = 0; counter < last_elements_ordered.size() - 1 ; counter++) last_elements[ (i + 1 + counter) % last_elements.size() ] = last_elements_ordered[counter + 1]; diff --git a/boost/test/impl/test_tree.ipp b/boost/test/impl/test_tree.ipp index 08bdad3360..81995bb29f 100644 --- a/boost/test/impl/test_tree.ipp +++ b/boost/test/impl/test_tree.ipp @@ -448,9 +448,28 @@ auto_test_unit_registrar::auto_test_unit_registrar( int ) global_fixture::global_fixture() { + framework::register_global_fixture( *this ); +} + +global_fixture::~global_fixture() +{ + framework::deregister_global_fixture( *this ); +} + +// ************************************************************************** // +// ************** global_configuration ************** // +// ************************************************************************** // + +global_configuration::global_configuration() +{ framework::register_observer( *this ); } +global_configuration::~global_configuration() +{ + framework::deregister_observer( *this ); +} + //____________________________________________________________________________// } // namespace unit_test diff --git a/boost/test/impl/unit_test_log.ipp b/boost/test/impl/unit_test_log.ipp index c52260b94b..6ef7d930a2 100644 --- a/boost/test/impl/unit_test_log.ipp +++ b/boost/test/impl/unit_test_log.ipp @@ -171,6 +171,8 @@ unit_test_log_t::test_start( counter_t test_cases_amount ) if( runtime_config::get<bool>( runtime_config::btrt_build_info ) ) current_logger_data.m_log_formatter->log_build_info( current_logger_data.stream() ); + //current_logger_data.stream().flush(); + current_logger_data.m_entry_in_progress = false; } } @@ -472,14 +474,14 @@ unit_test_log_t::log_entry_context( log_level l ) { BOOST_TEST_FOREACH( unit_test_log_data_helper_impl&, current_logger_data, s_log_impl().m_log_formatter_data ) { if( current_logger_data.m_enabled ) { - current_logger_data.m_log_formatter->log_entry_context( current_logger_data.stream(), frame ); + current_logger_data.m_log_formatter->log_entry_context( current_logger_data.stream(), l, frame ); } } } BOOST_TEST_FOREACH( unit_test_log_data_helper_impl&, current_logger_data, s_log_impl().m_log_formatter_data ) { if( current_logger_data.m_enabled ) { - current_logger_data.m_log_formatter->entry_context_finish( current_logger_data.stream() ); + current_logger_data.m_log_formatter->entry_context_finish( current_logger_data.stream(), l ); } } } diff --git a/boost/test/impl/unit_test_monitor.ipp b/boost/test/impl/unit_test_monitor.ipp index fdd36f7c3a..cfb41a239c 100644 --- a/boost/test/impl/unit_test_monitor.ipp +++ b/boost/test/impl/unit_test_monitor.ipp @@ -47,7 +47,7 @@ unit_test_monitor_t::execute_and_translate( boost::function<void ()> const& func } BOOST_TEST_I_CATCH( execution_exception, ex ) { framework::exception_caught( ex ); - framework::test_unit_aborted( framework::current_test_case() ); + framework::test_unit_aborted( framework::current_test_unit() ); // translate execution_exception::error_code to error_level switch( ex.code() ) { diff --git a/boost/test/impl/xml_log_formatter.ipp b/boost/test/impl/xml_log_formatter.ipp index 81284020dd..ef44f1eade 100644 --- a/boost/test/impl/xml_log_formatter.ipp +++ b/boost/test/impl/xml_log_formatter.ipp @@ -199,7 +199,7 @@ xml_log_formatter::entry_context_start( std::ostream& ostr, log_level ) //____________________________________________________________________________// void -xml_log_formatter::entry_context_finish( std::ostream& ostr ) +xml_log_formatter::entry_context_finish( std::ostream& ostr, log_level ) { ostr << BOOST_TEST_L( "</Context>" ); } @@ -207,7 +207,7 @@ xml_log_formatter::entry_context_finish( std::ostream& ostr ) //____________________________________________________________________________// void -xml_log_formatter::log_entry_context( std::ostream& ostr, const_string context_descr ) +xml_log_formatter::log_entry_context( std::ostream& ostr, log_level, const_string context_descr ) { ostr << BOOST_TEST_L( "<Frame>" ) << utils::cdata() << context_descr << BOOST_TEST_L( "</Frame>" ); } diff --git a/boost/test/included/test_exec_monitor.hpp b/boost/test/included/test_exec_monitor.hpp index 34b6ef44dd..e75b4698f2 100644 --- a/boost/test/included/test_exec_monitor.hpp +++ b/boost/test/included/test_exec_monitor.hpp @@ -23,6 +23,7 @@ #include <boost/test/impl/progress_monitor.ipp> #include <boost/test/impl/results_collector.ipp> #include <boost/test/impl/results_reporter.ipp> +#include <boost/test/impl/test_framework_init_observer.ipp> #include <boost/test/impl/test_main.ipp> #include <boost/test/impl/test_tools.ipp> #include <boost/test/impl/test_tree.ipp> diff --git a/boost/test/included/unit_test.hpp b/boost/test/included/unit_test.hpp index 993d75e4c0..90882eb178 100644 --- a/boost/test/included/unit_test.hpp +++ b/boost/test/included/unit_test.hpp @@ -5,6 +5,7 @@ // See http://www.boost.org/libs/test for the library home page. // +// //!@file //!@brief Included (vs. linked) version of Unit Test Framework // *************************************************************************** @@ -24,6 +25,7 @@ #include <boost/test/impl/progress_monitor.ipp> #include <boost/test/impl/results_collector.ipp> #include <boost/test/impl/results_reporter.ipp> +#include <boost/test/impl/test_framework_init_observer.ipp> #include <boost/test/impl/test_tools.ipp> #include <boost/test/impl/test_tree.ipp> #include <boost/test/impl/unit_test_log.ipp> @@ -31,7 +33,6 @@ #include <boost/test/impl/unit_test_monitor.ipp> #include <boost/test/impl/unit_test_parameters.ipp> #include <boost/test/impl/xml_log_formatter.ipp> -#include <boost/test/impl/junit_log_formatter.ipp> #include <boost/test/impl/xml_report_formatter.ipp> #include <boost/test/unit_test.hpp> diff --git a/boost/test/output/compiler_log_formatter.hpp b/boost/test/output/compiler_log_formatter.hpp index cb6172aab6..50359334b1 100644 --- a/boost/test/output/compiler_log_formatter.hpp +++ b/boost/test/output/compiler_log_formatter.hpp @@ -51,8 +51,8 @@ public: void log_entry_finish( std::ostream& ); void entry_context_start( std::ostream&, log_level ); - void log_entry_context( std::ostream&, const_string ); - void entry_context_finish( std::ostream& ); + void log_entry_context( std::ostream&, log_level l, const_string ); + void entry_context_finish( std::ostream&, log_level l ); protected: virtual void print_prefix( std::ostream&, const_string file, std::size_t line ); diff --git a/boost/test/output/junit_log_formatter.hpp b/boost/test/output/junit_log_formatter.hpp index 325a1d8a17..713d3b016c 100644 --- a/boost/test/output/junit_log_formatter.hpp +++ b/boost/test/output/junit_log_formatter.hpp @@ -118,8 +118,8 @@ public: void log_entry_finish( std::ostream& ); void entry_context_start( std::ostream&, log_level ); - void log_entry_context( std::ostream&, const_string ); - void entry_context_finish( std::ostream& ); + void log_entry_context( std::ostream&, log_level, const_string ); + void entry_context_finish( std::ostream&, log_level ); //! Discards changes in the log level virtual void set_log_level(log_level ll) diff --git a/boost/test/output/xml_log_formatter.hpp b/boost/test/output/xml_log_formatter.hpp index 4d848a0425..1d8dec0f95 100644 --- a/boost/test/output/xml_log_formatter.hpp +++ b/boost/test/output/xml_log_formatter.hpp @@ -54,8 +54,8 @@ public: void log_entry_finish( std::ostream& ); void entry_context_start( std::ostream&, log_level ); - void log_entry_context( std::ostream&, const_string ); - void entry_context_finish( std::ostream& ); + void log_entry_context( std::ostream&, log_level, const_string ); + void entry_context_finish( std::ostream&, log_level ); private: // Data members diff --git a/boost/test/progress_monitor.hpp b/boost/test/progress_monitor.hpp index e480ac669d..2f661f5825 100644 --- a/boost/test/progress_monitor.hpp +++ b/boost/test/progress_monitor.hpp @@ -41,7 +41,7 @@ public: virtual void test_unit_finish( test_unit const&, unsigned long ); virtual void test_unit_skipped( test_unit const&, const_string ); - virtual int priority() { return 3; } + virtual int priority() { return 4; } /// @} /// @name Configuration diff --git a/boost/test/results_collector.hpp b/boost/test/results_collector.hpp index 7d2c2bee58..3acd7b87bc 100644 --- a/boost/test/results_collector.hpp +++ b/boost/test/results_collector.hpp @@ -79,6 +79,9 @@ public: /// Returns true if test unit passed bool passed() const; + /// Returns true if the test unit was aborted (hard failure) + bool aborted() const; + /// Produces result code for the test unit execution /// /// This methhod return one of the result codes defined in @c boost/cstdlib.hpp @@ -119,7 +122,7 @@ public: virtual void assertion_result( unit_test::assertion_result ); virtual void exception_caught( execution_exception const& ); - virtual int priority() { return 2; } + virtual int priority() { return 3; } /// Results access per test unit /// diff --git a/boost/test/test_framework_init_observer.hpp b/boost/test/test_framework_init_observer.hpp new file mode 100644 index 0000000000..cdf5ef5edd --- /dev/null +++ b/boost/test/test_framework_init_observer.hpp @@ -0,0 +1,63 @@ +// (c) Copyright Raffi Enficiaud 2017. +// 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) + +// See http://www.boost.org/libs/test for the library home page. +// +/// @file +/// @brief Defines an observer that monitors the init of the unit test framework +// *************************************************************************** + +#ifndef BOOST_TEST_FRAMEWORK_INIT_OBSERVER_HPP_071894GER +#define BOOST_TEST_FRAMEWORK_INIT_OBSERVER_HPP_071894GER + +// Boost.Test +#include <boost/test/tree/observer.hpp> + +#include <boost/test/detail/global_typedef.hpp> +#include <boost/test/detail/fwd_decl.hpp> + +#include <boost/test/utils/trivial_singleton.hpp> + +#include <boost/test/detail/suppress_warnings.hpp> + +//____________________________________________________________________________// + +namespace boost { +namespace unit_test { + +// ************************************************************************** // +/// @brief Monitors the init of the framework +/// +/// This class collects the state of the init/termination of the unit test framework. +/// +/// @see boost::unit_test::test_observer +class BOOST_TEST_DECL framework_init_observer_t : public test_observer, public singleton<framework_init_observer_t> { +public: + + virtual void test_start( counter_t ); + + virtual void assertion_result( unit_test::assertion_result ); + virtual void exception_caught( execution_exception const& ); + virtual void test_aborted(); + + virtual int priority() { return 0; } + + void clear(); + + /// Indicates if a failure has been recorded so far + bool has_failed( ) const; + +private: + BOOST_TEST_SINGLETON_CONS( framework_init_observer_t ) +}; + +BOOST_TEST_SINGLETON_INST( framework_init_observer ) + +} // namespace unit_test +} // namespace boost + +#include <boost/test/detail/enable_warnings.hpp> + +#endif // BOOST_TEST_FRAMEWORK_INIT_OBSERVER_HPP_071894GER diff --git a/boost/test/tools/collection_comparison_op.hpp b/boost/test/tools/collection_comparison_op.hpp index 396de502f8..864103fb4a 100644 --- a/boost/test/tools/collection_comparison_op.hpp +++ b/boost/test/tools/collection_comparison_op.hpp @@ -38,6 +38,15 @@ namespace assertion { template<typename T> struct specialized_compare : public mpl::false_ {}; +template <typename T> +struct is_c_array : public mpl::false_ {}; + +template<typename T, std::size_t N> +struct is_c_array<T [N]> : public mpl::true_ {}; + +template<typename T, std::size_t N> +struct is_c_array<T (&)[N]> : public mpl::true_ {}; + #define BOOST_TEST_SPECIALIZED_COLLECTION_COMPARE(Col) \ namespace boost { namespace test_tools { namespace assertion { \ template<> \ @@ -55,17 +64,21 @@ template <typename OP, bool can_be_equal, bool prefer_shorter, typename Lhs, typename Rhs> inline typename boost::enable_if_c< - unit_test::is_forward_iterable<Lhs>::value && unit_test::is_forward_iterable<Rhs>::value, + unit_test::is_forward_iterable<Lhs>::value && !unit_test::is_cstring<Lhs>::value + && unit_test::is_forward_iterable<Rhs>::value && !unit_test::is_cstring<Rhs>::value, assertion_result>::type lexicographic_compare( Lhs const& lhs, Rhs const& rhs ) { assertion_result ar( true ); - typename Lhs::const_iterator first1 = lhs.begin(); - typename Rhs::const_iterator first2 = rhs.begin(); - typename Lhs::const_iterator last1 = lhs.end(); - typename Rhs::const_iterator last2 = rhs.end(); - std::size_t pos = 0; + typedef unit_test::bt_iterator_traits<Lhs> t_Lhs_iterator; + typedef unit_test::bt_iterator_traits<Rhs> t_Rhs_iterator; + + typename t_Lhs_iterator::const_iterator first1 = t_Lhs_iterator::begin(lhs); + typename t_Rhs_iterator::const_iterator first2 = t_Rhs_iterator::begin(rhs); + typename t_Lhs_iterator::const_iterator last1 = t_Lhs_iterator::end(lhs); + typename t_Rhs_iterator::const_iterator last2 = t_Rhs_iterator::end(rhs); + std::size_t pos = 0; for( ; (first1 != last1) && (first2 != last2); ++first1, ++first2, ++pos ) { assertion_result const& element_ar = OP::eval(*first1, *first2); @@ -113,8 +126,7 @@ template <typename OP, bool can_be_equal, bool prefer_shorter, typename Lhs, typename Rhs> inline typename boost::enable_if_c< - (!unit_test::is_forward_iterable<Lhs>::value && unit_test::is_cstring<Lhs>::value) || - (!unit_test::is_forward_iterable<Rhs>::value && unit_test::is_cstring<Rhs>::value), + (unit_test::is_cstring<Lhs>::value || unit_test::is_cstring<Rhs>::value), assertion_result>::type lexicographic_compare( Lhs const& lhs, Rhs const& rhs ) { @@ -122,8 +134,8 @@ lexicographic_compare( Lhs const& lhs, Rhs const& rhs ) typedef typename unit_test::deduce_cstring<Rhs>::type rhs_char_type; return lexicographic_compare<OP, can_be_equal, prefer_shorter>( - boost::unit_test::basic_cstring<lhs_char_type>(lhs), - boost::unit_test::basic_cstring<rhs_char_type>(rhs)); + lhs_char_type(lhs), + rhs_char_type(rhs)); } //____________________________________________________________________________// @@ -135,23 +147,27 @@ lexicographic_compare( Lhs const& lhs, Rhs const& rhs ) template <typename OP, typename Lhs, typename Rhs> inline typename boost::enable_if_c< - unit_test::is_forward_iterable<Lhs>::value && unit_test::is_forward_iterable<Rhs>::value, + unit_test::is_forward_iterable<Lhs>::value && !unit_test::is_cstring<Lhs>::value + && unit_test::is_forward_iterable<Rhs>::value && !unit_test::is_cstring<Rhs>::value, assertion_result>::type element_compare( Lhs const& lhs, Rhs const& rhs ) { + typedef unit_test::bt_iterator_traits<Lhs> t_Lhs_iterator; + typedef unit_test::bt_iterator_traits<Rhs> t_Rhs_iterator; + assertion_result ar( true ); - if( lhs.size() != rhs.size() ) { + if( t_Lhs_iterator::size(lhs) != t_Rhs_iterator::size(rhs) ) { ar = false; - ar.message() << "\nCollections size mismatch: " << lhs.size() << " != " << rhs.size(); + ar.message() << "\nCollections size mismatch: " << t_Lhs_iterator::size(lhs) << " != " << t_Rhs_iterator::size(rhs); return ar; } - typename Lhs::const_iterator left = lhs.begin(); - typename Rhs::const_iterator right = rhs.begin(); - std::size_t pos = 0; + typename t_Lhs_iterator::const_iterator left = t_Lhs_iterator::begin(lhs); + typename t_Rhs_iterator::const_iterator right = t_Rhs_iterator::begin(rhs); + std::size_t pos = 0; - for( ; pos < lhs.size(); ++left, ++right, ++pos ) { + for( ; pos < t_Lhs_iterator::size(lhs); ++left, ++right, ++pos ) { assertion_result const element_ar = OP::eval( *left, *right ); if( element_ar ) continue; @@ -171,16 +187,15 @@ element_compare( Lhs const& lhs, Rhs const& rhs ) template <typename OP, typename Lhs, typename Rhs> inline typename boost::enable_if_c< - (!unit_test::is_forward_iterable<Lhs>::value && unit_test::is_cstring<Lhs>::value) || - (!unit_test::is_forward_iterable<Rhs>::value && unit_test::is_cstring<Rhs>::value), + (unit_test::is_cstring<Lhs>::value || unit_test::is_cstring<Rhs>::value), assertion_result>::type element_compare( Lhs const& lhs, Rhs const& rhs ) { typedef typename unit_test::deduce_cstring<Lhs>::type lhs_char_type; typedef typename unit_test::deduce_cstring<Rhs>::type rhs_char_type; - return element_compare<OP>(boost::unit_test::basic_cstring<lhs_char_type>(lhs), - boost::unit_test::basic_cstring<rhs_char_type>(rhs)); + return element_compare<OP>(lhs_char_type(lhs), + rhs_char_type(rhs)); } //____________________________________________________________________________// @@ -193,14 +208,17 @@ template <typename OP, typename Lhs, typename Rhs> inline assertion_result non_equality_compare( Lhs const& lhs, Rhs const& rhs ) { + typedef unit_test::bt_iterator_traits<Lhs> t_Lhs_iterator; + typedef unit_test::bt_iterator_traits<Rhs> t_Rhs_iterator; + assertion_result ar( true ); - if( lhs.size() != rhs.size() ) + if( t_Lhs_iterator::size(lhs) != t_Rhs_iterator::size(rhs) ) return ar; - typename Lhs::const_iterator left = lhs.begin(); - typename Rhs::const_iterator right = rhs.begin(); - typename Lhs::const_iterator end = lhs.end(); + typename t_Lhs_iterator::const_iterator left = t_Lhs_iterator::begin(lhs); + typename t_Rhs_iterator::const_iterator right = t_Rhs_iterator::begin(rhs); + typename t_Lhs_iterator::const_iterator end = t_Lhs_iterator::end(lhs); for( ; left != end; ++left, ++right ) { if( OP::eval( *left, *right ) ) @@ -367,22 +385,34 @@ compare_collections( Lhs const& lhs, Rhs const& rhs, boost::type<op::GE<L, R> >* #define DEFINE_COLLECTION_COMPARISON( oper, name, rev ) \ template<typename Lhs,typename Rhs> \ struct name<Lhs,Rhs,typename boost::enable_if_c< \ - unit_test::is_forward_iterable<Lhs>::value \ - && !unit_test::is_cstring<Lhs>::value \ - && unit_test::is_forward_iterable<Rhs>::value \ - && !unit_test::is_cstring<Rhs>::value>::type> { \ + unit_test::is_forward_iterable<Lhs>::value \ + && !unit_test::is_cstring_comparable<Lhs>::value \ + && unit_test::is_forward_iterable<Rhs>::value \ + && !unit_test::is_cstring_comparable<Rhs>::value>::type> { \ public: \ typedef assertion_result result_type; \ + typedef unit_test::bt_iterator_traits<Lhs> t_Lhs_iterator_helper; \ + typedef unit_test::bt_iterator_traits<Rhs> t_Rhs_iterator_helper; \ \ typedef name<Lhs, Rhs> OP; \ + \ typedef typename \ - mpl::if_c<is_same<typename decay<Lhs>::type, \ - typename decay<Rhs>::type>::value, \ - typename cctraits<OP>::is_specialized, \ - mpl::false_>::type is_specialized; \ + mpl::if_c< \ + mpl::or_< \ + typename is_c_array<Lhs>::type, \ + typename is_c_array<Rhs>::type \ + >::value, \ + mpl::true_, \ + typename \ + mpl::if_c<is_same<typename decay<Lhs>::type, \ + typename decay<Rhs>::type>::value, \ + typename cctraits<OP>::is_specialized, \ + mpl::false_>::type \ + >::type is_specialized; \ \ - typedef name<typename Lhs::value_type, \ - typename Rhs::value_type> elem_op; \ + typedef name<typename t_Lhs_iterator_helper::value_type, \ + typename t_Rhs_iterator_helper::value_type \ + > elem_op; \ \ static assertion_result \ eval( Lhs const& lhs, Rhs const& rhs) \ diff --git a/boost/test/tools/cstring_comparison_op.hpp b/boost/test/tools/cstring_comparison_op.hpp index 09cbf267e2..50f181d858 100644 --- a/boost/test/tools/cstring_comparison_op.hpp +++ b/boost/test/tools/cstring_comparison_op.hpp @@ -37,8 +37,8 @@ namespace op { #define DEFINE_CSTRING_COMPARISON( oper, name, rev ) \ template<typename Lhs,typename Rhs> \ struct name<Lhs,Rhs,typename boost::enable_if_c< \ - ( unit_test::is_cstring<Lhs>::value \ - && unit_test::is_cstring<Rhs>::value) \ + ( unit_test::is_cstring_comparable<Lhs>::value \ + && unit_test::is_cstring_comparable<Rhs>::value) \ >::type > \ { \ typedef typename unit_test::deduce_cstring<Lhs>::type lhs_char_type; \ @@ -46,13 +46,14 @@ struct name<Lhs,Rhs,typename boost::enable_if_c< \ public: \ typedef assertion_result result_type; \ \ - typedef name<lhs_char_type, rhs_char_type> elem_op; \ + typedef name< \ + typename lhs_char_type::value_type, \ + typename rhs_char_type::value_type> elem_op; \ \ static bool \ eval( Lhs const& lhs, Rhs const& rhs) \ { \ - return unit_test::basic_cstring<lhs_char_type>(lhs) oper \ - unit_test::basic_cstring<rhs_char_type>(rhs); \ + return lhs_char_type(lhs) oper rhs_char_type(rhs); \ } \ \ template<typename PrevExprType> \ diff --git a/boost/test/tools/fpc_op.hpp b/boost/test/tools/fpc_op.hpp index 18364a27b9..b879d218f2 100644 --- a/boost/test/tools/fpc_op.hpp +++ b/boost/test/tools/fpc_op.hpp @@ -38,22 +38,19 @@ namespace op { template<typename OP> struct fpctraits { - static const bool cmp_direct = true; -}; - -template <typename Lhs, typename Rhs> -struct fpctraits<op::NE<Lhs,Rhs> > { - static const bool cmp_direct = false; + // indicate if we should perform the operation with a "logical OR" + // with the "equality under tolerance". + static const bool equality_logical_disjunction = true; }; template <typename Lhs, typename Rhs> struct fpctraits<op::LT<Lhs,Rhs> > { - static const bool cmp_direct = false; + static const bool equality_logical_disjunction = false; }; template <typename Lhs, typename Rhs> struct fpctraits<op::GT<Lhs,Rhs> > { - static const bool cmp_direct = false; + static const bool equality_logical_disjunction = false; }; //____________________________________________________________________________// @@ -62,26 +59,24 @@ struct fpctraits<op::GT<Lhs,Rhs> > { // ************** set of overloads to select correct fpc algo ************** // // ************************************************************************** // // we really only care about EQ vs NE. All other comparisons use direct first -// and then need EQ. For example a < b (tolerance t) IFF a < b OR a == b (tolerance t) +// and then need EQ. For example a <= b (tolerance t) IFF a <= b OR a == b (tolerance t) template <typename FPT, typename Lhs, typename Rhs, typename OP> inline assertion_result -compare_fpv( Lhs const& lhs, Rhs const& rhs, OP* ) +compare_fpv( Lhs const& lhs, Rhs const& rhs, OP* cmp_operator) { - fpc::close_at_tolerance<FPT> P( fpc_tolerance<FPT>(), fpc::FPC_STRONG ); - - assertion_result ar( P( lhs, rhs ) ); - if( !ar ) - ar.message() << "Relative difference exceeds tolerance [" - << P.tested_rel_diff() << " > " << P.fraction_tolerance() << ']'; - return ar; + bool result = cmp_operator->eval_direct(lhs, rhs); + if(fpctraits<OP>::equality_logical_disjunction) { + return result || compare_fpv<FPT>(lhs, rhs, (op::EQ<Lhs, Rhs>*)0); + } + return result && compare_fpv<FPT>(lhs, rhs, (op::NE<Lhs, Rhs>*)0); } //____________________________________________________________________________// -template <typename FPT, typename OP> +template <typename FPT, typename Lhs, typename Rhs> inline assertion_result -compare_fpv_near_zero( FPT const& fpv, OP* ) +compare_fpv_near_zero( FPT const& fpv, op::EQ<Lhs,Rhs>* ) { fpc::small_with_tolerance<FPT> P( fpc_tolerance<FPT>() ); @@ -96,22 +91,6 @@ compare_fpv_near_zero( FPT const& fpv, OP* ) template <typename FPT, typename Lhs, typename Rhs> inline assertion_result -compare_fpv( Lhs const& lhs, Rhs const& rhs, op::NE<Lhs,Rhs>* ) -{ - fpc::close_at_tolerance<FPT> P( fpc_tolerance<FPT>(), fpc::FPC_WEAK ); - - assertion_result ar( !P( lhs, rhs ) ); - if( !ar ) - ar.message() << "Relative difference is within tolerance [" - << P.tested_rel_diff() << " < " << fpc_tolerance<FPT>() << ']'; - - return ar; -} - -//____________________________________________________________________________// - -template <typename FPT, typename Lhs, typename Rhs> -inline assertion_result compare_fpv_near_zero( FPT const& fpv, op::NE<Lhs,Rhs>* ) { fpc::small_with_tolerance<FPT> P( fpc_tolerance<FPT>() ); @@ -126,35 +105,49 @@ compare_fpv_near_zero( FPT const& fpv, op::NE<Lhs,Rhs>* ) template <typename FPT, typename Lhs, typename Rhs> inline assertion_result -compare_fpv( Lhs const& lhs, Rhs const& rhs, op::LT<Lhs,Rhs>* ) +compare_fpv( Lhs const& lhs, Rhs const& rhs, op::EQ<Lhs,Rhs>* ) { - return lhs >= rhs ? assertion_result( false ) : compare_fpv<FPT>( lhs, rhs, (op::NE<Lhs,Rhs>*)0 ); -} - -template <typename FPT, typename Lhs, typename Rhs> -inline assertion_result -compare_fpv_near_zero( FPT const& fpv, op::LT<Lhs,Rhs>* ) -{ - return fpv >= 0 ? assertion_result( false ) : compare_fpv_near_zero( fpv, (op::NE<Lhs,Rhs>*)0 ); + if( lhs == 0 ) { + return compare_fpv_near_zero( rhs, (op::EQ<Lhs,Rhs>*)0 ); + } + else if( rhs == 0) { + return compare_fpv_near_zero( lhs, (op::EQ<Lhs,Rhs>*)0 ); + } + else { + fpc::close_at_tolerance<FPT> P( fpc_tolerance<FPT>(), fpc::FPC_STRONG ); + + assertion_result ar( P( lhs, rhs ) ); + if( !ar ) + ar.message() << "Relative difference exceeds tolerance [" + << P.tested_rel_diff() << " > " << P.fraction_tolerance() << ']'; + return ar; + } } //____________________________________________________________________________// template <typename FPT, typename Lhs, typename Rhs> inline assertion_result -compare_fpv( Lhs const& lhs, Rhs const& rhs, op::GT<Lhs,Rhs>* ) -{ - return lhs <= rhs ? assertion_result( false ) : compare_fpv<FPT>( lhs, rhs, (op::NE<Lhs,Rhs>*)0 ); -} - -template <typename FPT, typename Lhs, typename Rhs> -inline assertion_result -compare_fpv_near_zero( FPT const& fpv, op::GT<Lhs,Rhs>* ) +compare_fpv( Lhs const& lhs, Rhs const& rhs, op::NE<Lhs,Rhs>* ) { - return fpv <= 0 ? assertion_result( false ) : compare_fpv_near_zero( fpv, (op::NE<Lhs,Rhs>*)0 ); + if( lhs == 0 ) { + return compare_fpv_near_zero( rhs, (op::NE<Lhs,Rhs>*)0 ); + } + else if( rhs == 0 ) { + return compare_fpv_near_zero( lhs, (op::NE<Lhs,Rhs>*)0 ); + } + else { + fpc::close_at_tolerance<FPT> P( fpc_tolerance<FPT>(), fpc::FPC_WEAK ); + + assertion_result ar( !P( lhs, rhs ) ); + if( !ar ) + ar.message() << "Relative difference is within tolerance [" + << P.tested_rel_diff() << " < " << fpc_tolerance<FPT>() << ']'; + + return ar; + } } - //____________________________________________________________________________// #define DEFINE_FPV_COMPARISON( oper, name, rev ) \ @@ -177,22 +170,9 @@ public: \ static assertion_result \ eval( Lhs const& lhs, Rhs const& rhs ) \ { \ - if( lhs == 0 ) \ - { \ - return compare_fpv_near_zero( rhs, (OP*)0 ); \ - } \ - \ - if( rhs == 0 ) \ - { \ - return compare_fpv_near_zero( lhs, (OP*)0 ); \ - } \ - \ - bool direct_res = eval_direct( lhs, rhs ); \ - \ - if( (direct_res && fpctraits<OP>::cmp_direct) || \ - fpc_tolerance<FPT>() == FPT(0) ) \ + if( fpc_tolerance<FPT>() == FPT(0) ) \ { \ - return direct_res; \ + return eval_direct( lhs, rhs ); \ } \ \ return compare_fpv<FPT>( lhs, rhs, (OP*)0 ); \ diff --git a/boost/test/tree/fixture.hpp b/boost/test/tree/fixture.hpp index 7bca5a8de3..8e07b2aa1d 100644 --- a/boost/test/tree/fixture.hpp +++ b/boost/test/tree/fixture.hpp @@ -5,11 +5,8 @@ // See http://www.boost.org/libs/test for the library home page. // -// File : $RCSfile$ -// -// Version : $Revision: 74640 $ -// -// Description : defines fixture interface and object makers +/// @file +/// Defines fixture interface and object makers // *************************************************************************** #ifndef BOOST_TEST_TREE_FIXTURE_HPP_100311GER @@ -22,6 +19,7 @@ #include <boost/shared_ptr.hpp> #include <boost/scoped_ptr.hpp> #include <boost/function/function0.hpp> +#include <boost/utility/declval.hpp> #include <boost/test/detail/suppress_warnings.hpp> @@ -46,6 +44,83 @@ public: typedef shared_ptr<test_unit_fixture> test_unit_fixture_ptr; // ************************************************************************** // +// ************** fixture helper functions ************** // +// ************************************************************************** // + +namespace impl_fixture { + +#if defined(BOOST_NO_CXX11_DECLTYPE) || defined(BOOST_NO_CXX11_TRAILING_RESULT_TYPES) + + template<typename U, void (U::*)()> struct fixture_detect {}; + + template<typename T> + struct has_setup { + private: + template<typename U> static char Test(fixture_detect<U, &U::setup>*); + template<typename U> static int Test(...); + public: + static const bool value = sizeof(Test<T>(0)) == sizeof(char); + }; + + template<typename T> + struct has_teardown { + private: + template<typename U> static char Test(fixture_detect<U, &U::teardown>*); + template<typename U> static int Test(...); + public: + static const bool value = sizeof(Test<T>(0)) == sizeof(char); + }; + +#else + + template<typename U> struct fixture_detect { typedef char type; }; + template<typename T> + struct has_setup { + private: + template<typename U> static auto Test(U*) -> typename fixture_detect<decltype(boost::declval<U>().setup())>::type; + template<typename U> static int Test(...); + public: + static const bool value = sizeof(Test<T>(0)) == sizeof(char); + }; + + template<typename T> + struct has_teardown { + private: + template<typename U> static auto Test(U*) -> typename fixture_detect<decltype(boost::declval<U>().teardown())>::type; + template<typename U> static int Test(...); + public: + static const bool value = sizeof(Test<T>(0)) == sizeof(char); + }; + +#endif + + template <bool has_setup = false> + struct call_setup { template <class U> void operator()(U& ) { } }; + + template <> + struct call_setup<true> { template <class U> void operator()(U& u) { u.setup(); } }; + + template <bool has_teardown = false> + struct call_teardown { template <class U> void operator()(U& ) { } }; + + template <> + struct call_teardown<true> { template <class U> void operator()(U& u) { u.teardown(); } }; +} + +//! Calls the fixture "setup" if detected by the compiler, otherwise does nothing. +template <class U> +void setup_conditional(U& u) { + return impl_fixture::call_setup<impl_fixture::has_setup<U>::value>()(u); +} + +//! Calls the fixture "teardown" if detected by the compiler, otherwise does nothing. +template <class U> +void teardown_conditional(U& u) { + return impl_fixture::call_teardown<impl_fixture::has_teardown<U>::value>()(u); +} + + +// ************************************************************************** // // ************** class_based_fixture ************** // // ************************************************************************** // @@ -57,8 +132,8 @@ public: private: // Fixture interface - virtual void setup() { m_inst.reset( new F( m_arg ) ); } - virtual void teardown() { m_inst.reset(); } + virtual void setup() { m_inst.reset( new F( m_arg ) ); setup_conditional(*m_inst); } + virtual void teardown() { teardown_conditional(*m_inst); m_inst.reset(); } // Data members scoped_ptr<F> m_inst; @@ -75,8 +150,8 @@ public: private: // Fixture interface - virtual void setup() { m_inst.reset( new F ); } - virtual void teardown() { m_inst.reset(); } + virtual void setup() { m_inst.reset( new F ); setup_conditional(*m_inst); } + virtual void teardown() { teardown_conditional(*m_inst); m_inst.reset(); } // Data members scoped_ptr<F> m_inst; diff --git a/boost/test/tree/global_fixture.hpp b/boost/test/tree/global_fixture.hpp index 2114595929..7c96d34e89 100644 --- a/boost/test/tree/global_fixture.hpp +++ b/boost/test/tree/global_fixture.hpp @@ -17,6 +17,7 @@ #include <boost/test/detail/global_typedef.hpp> #include <boost/test/tree/observer.hpp> +#include <boost/test/tree/fixture.hpp> #include <boost/test/detail/suppress_warnings.hpp> @@ -27,13 +28,36 @@ namespace boost { namespace unit_test { // ************************************************************************** // +// ************** global_configuration ************** // +// ************************************************************************** // + +class BOOST_TEST_DECL global_configuration : public test_observer { + +public: + // Constructor + global_configuration(); + + // Dtor + virtual ~global_configuration(); + + // Happens after the framework global observer init has been done + virtual int priority() { return 1; } +}; + + + +// ************************************************************************** // // ************** global_fixture ************** // // ************************************************************************** // -class BOOST_TEST_DECL global_fixture : public test_observer { +class BOOST_TEST_DECL global_fixture : public test_unit_fixture { + public: // Constructor global_fixture(); + + // Dtor + virtual ~global_fixture(); }; //____________________________________________________________________________// @@ -41,14 +65,48 @@ public: namespace ut_detail { template<typename F> -struct global_fixture_impl : public global_fixture { +struct global_configuration_impl : public global_configuration { // Constructor - global_fixture_impl() : m_fixture( 0 ) {} + global_configuration_impl() : m_configuration_observer( 0 ) { + } // test observer interface - virtual void test_start( counter_t ) { m_fixture = new F; } - virtual void test_finish() { delete m_fixture; m_fixture = 0; } - virtual void test_aborted() { delete m_fixture; m_fixture = 0; } + virtual void test_start( counter_t ) { + m_configuration_observer = new F; + } + + // test observer interface + virtual void test_finish() { + if(m_configuration_observer) { + delete m_configuration_observer; + m_configuration_observer = 0; + } + } +private: + // Data members + F* m_configuration_observer; +}; + +template<typename F> +struct global_fixture_impl : public global_fixture { + // Constructor + global_fixture_impl() : m_fixture( 0 ) { + } + + // test fixture interface + virtual void setup() { + m_fixture = new F; + setup_conditional(*m_fixture); + } + + // test fixture interface + virtual void teardown() { + if(m_fixture) { + teardown_conditional(*m_fixture); + } + delete m_fixture; + m_fixture = 0; + } private: // Data members diff --git a/boost/test/tree/observer.hpp b/boost/test/tree/observer.hpp index 4db930fb07..bd6fc9bff5 100644 --- a/boost/test/tree/observer.hpp +++ b/boost/test/tree/observer.hpp @@ -34,7 +34,7 @@ namespace unit_test { /// Boost.Test framework on the current execution state. /// /// Several observers can be running at the same time, and it is not unusual to -/// have interactions among them. The test_observer#priority member function allows the specification +/// have interactions among them. The @ref test_observer::priority member function allows the specification /// of a particular order among them (lowest priority executed first, except specified otherwise). /// class BOOST_TEST_DECL test_observer { @@ -44,10 +44,8 @@ public: //! //! @param[in] number_of_test_cases indicates the number of test cases. Only active //! test cases are taken into account. - //! virtual void test_start( counter_t /* number_of_test_cases */ ) {} - //! Called after the framework ends executing the test cases //! //! @note The call is made with a reversed priority order. @@ -98,6 +96,8 @@ public: //! additional data about the exception. virtual void exception_caught( execution_exception const& ) {} + //! The priority indicates the order at which this observer is initialized + //! and tore down in the UTF framework. The order is lowest to highest priority. virtual int priority() { return 0; } protected: diff --git a/boost/test/unit_test_log.hpp b/boost/test/unit_test_log.hpp index ba998b0ca4..4e6a97b3c2 100644 --- a/boost/test/unit_test_log.hpp +++ b/boost/test/unit_test_log.hpp @@ -123,7 +123,7 @@ public: virtual void exception_caught( execution_exception const& ex ); - virtual int priority() { return 1; } + virtual int priority() { return 2; } // log configuration methods //! Sets the stream for all loggers diff --git a/boost/test/unit_test_log_formatter.hpp b/boost/test/unit_test_log_formatter.hpp index 77fec40aed..79b74e0849 100644 --- a/boost/test/unit_test_log_formatter.hpp +++ b/boost/test/unit_test_log_formatter.hpp @@ -248,7 +248,7 @@ public: // @name Log entry context report /// Invoked by Unit Test Framework to start log entry context report - + // /// Unit Test Framework logs for failed assertions and uncaught exceptions context if one was defined by a test module. /// Context consists of multiple "scopes" identified by description messages assigned by the test module using /// BOOST_TEST_INFO/BOOST_TEST_CONTEXT statements. @@ -258,18 +258,20 @@ public: virtual void entry_context_start( std::ostream& os, log_level l ) = 0; /// Invoked by Unit Test Framework to report log entry context "scope" description - + // /// Each "scope" description is reported by separate call to log_entry_context. /// @param[in] os output stream to write a messages into + /// @param[in] l entry log_level, to be used to fine tune the message /// @param[in] value context "scope" description /// @see log_entry_start, entry_context_finish - virtual void log_entry_context( std::ostream& os, const_string value ) = 0; + virtual void log_entry_context( std::ostream& os, log_level l, const_string value ) = 0; /// Invoked by Unit Test Framework to finish log entry context report - + /// /// @param[in] os output stream to write a messages into + /// @param[in] l entry log_level, to be used to fine tune the message /// @see log_entry_start, entry_context_context - virtual void entry_context_finish( std::ostream& os ) = 0; + virtual void entry_context_finish( std::ostream& os, log_level l ) = 0; // @} // @name Log level management diff --git a/boost/test/unit_test_suite.hpp b/boost/test/unit_test_suite.hpp index b434fa9f97..13ff804b44 100644 --- a/boost/test/unit_test_suite.hpp +++ b/boost/test/unit_test_suite.hpp @@ -143,11 +143,15 @@ struct test_name : public F { void test_method(); }; \ \ static void BOOST_AUTO_TC_INVOKER( test_name )() \ { \ - BOOST_TEST_CHECKPOINT('"' << #test_name << "\" fixture entry."); \ + BOOST_TEST_CHECKPOINT('"' << #test_name << "\" fixture ctor"); \ test_name t; \ - BOOST_TEST_CHECKPOINT('"' << #test_name << "\" entry."); \ + BOOST_TEST_CHECKPOINT('"' << #test_name << "\" fixture setup"); \ + boost::unit_test::setup_conditional(t); \ + BOOST_TEST_CHECKPOINT('"' << #test_name << "\" test entry"); \ t.test_method(); \ - BOOST_TEST_CHECKPOINT('"' << #test_name << "\" exit."); \ + BOOST_TEST_CHECKPOINT('"' << #test_name << "\" fixture teardown"); \ + boost::unit_test::teardown_conditional(t); \ + BOOST_TEST_CHECKPOINT('"' << #test_name << "\" fixture dtor"); \ } \ \ struct BOOST_AUTO_TC_UNIQUE_ID( test_name ) {}; \ @@ -230,10 +234,11 @@ struct BOOST_AUTO_TC_INVOKER( test_name ) { \ static void run( boost::type<TestType>* = 0 ) \ { \ BOOST_TEST_CHECKPOINT('"' << #test_name <<"\" fixture entry."); \ - test_name<TestType> t; \ + test_name<TestType> t; boost::unit_test::setup_conditional(t); \ BOOST_TEST_CHECKPOINT('"' << #test_name << "\" entry."); \ t.test_method(); \ BOOST_TEST_CHECKPOINT('"' << #test_name << "\" exit."); \ + boost::unit_test::teardown_conditional(t); \ } \ }; \ \ @@ -290,6 +295,22 @@ void BOOST_JOIN( name, _impl )( boost::type<type_name>* ) \ // ************************************************************************** // #define BOOST_GLOBAL_FIXTURE( F ) \ +static boost::unit_test::ut_detail::global_configuration_impl<F> BOOST_JOIN( gf_, F ) \ +/**/ + +// ************************************************************************** // +// ************** BOOST_TEST_GLOBAL_CONFIGURATION ************** // +// ************************************************************************** // + +#define BOOST_TEST_GLOBAL_CONFIGURATION( F ) \ +static boost::unit_test::ut_detail::global_configuration_impl<F> BOOST_JOIN( gf_, F ) \ +/**/ + +// ************************************************************************** // +// ************** BOOST_TEST_GLOBAL_FIXTURE ************** // +// ************************************************************************** // + +#define BOOST_TEST_GLOBAL_FIXTURE( F ) \ static boost::unit_test::ut_detail::global_fixture_impl<F> BOOST_JOIN( gf_, F ) \ /**/ diff --git a/boost/test/utils/algorithm.hpp b/boost/test/utils/algorithm.hpp index a5491816eb..7f16816c3a 100644 --- a/boost/test/utils/algorithm.hpp +++ b/boost/test/utils/algorithm.hpp @@ -15,10 +15,16 @@ // STL #include <utility> #include <algorithm> // std::find -#include <functional> // std::bind1st +#include <functional> // std::bind1st or std::bind #include <boost/test/detail/suppress_warnings.hpp> +#ifdef BOOST_NO_CXX98_BINDERS +#define BOOST_TEST_BIND1ST(F,A) std::bind( (F), (A), std::placeholders::_1 ) +#else +#define BOOST_TEST_BIND1ST(F,A) std::bind1st( (F), (A) ) +#endif + //____________________________________________________________________________// namespace boost { @@ -109,7 +115,7 @@ find_first_not_of( ForwardIterator1 first1, ForwardIterator1 last1, Predicate pred ) { while( first1 != last1 ) { - if( std::find_if( first2, last2, std::bind1st( pred, *first1 ) ) == last2 ) + if( std::find_if( first2, last2, BOOST_TEST_BIND1ST( pred, *first1 ) ) == last2 ) break; ++first1; } @@ -159,9 +165,9 @@ find_last_of( BidirectionalIterator1 first1, BidirectionalIterator1 last1, return last1; BidirectionalIterator1 it1 = last1; - while( --it1 != first1 && std::find_if( first2, last2, std::bind1st( pred, *it1 ) ) == last2 ) {} + while( --it1 != first1 && std::find_if( first2, last2, BOOST_TEST_BIND1ST( pred, *it1 ) ) == last2 ) {} - return it1 == first1 && std::find_if( first2, last2, std::bind1st( pred, *it1 ) ) == last2 ? last1 : it1; + return it1 == first1 && std::find_if( first2, last2, BOOST_TEST_BIND1ST( pred, *it1 ) ) == last2 ? last1 : it1; } //____________________________________________________________________________// @@ -206,9 +212,9 @@ find_last_not_of( BidirectionalIterator1 first1, BidirectionalIterator1 last1, return last1; BidirectionalIterator1 it1 = last1; - while( --it1 != first1 && std::find_if( first2, last2, std::bind1st( pred, *it1 ) ) != last2 ) {} + while( --it1 != first1 && std::find_if( first2, last2, BOOST_TEST_BIND1ST( pred, *it1 ) ) != last2 ) {} - return it1 == first1 && std::find_if( first2, last2, std::bind1st( pred, *it1 ) ) == last2 ? last1 : it1; + return it1 == first1 && std::find_if( first2, last2, BOOST_TEST_BIND1ST( pred, *it1 ) ) == last2 ? last1 : it1; } //____________________________________________________________________________// diff --git a/boost/test/utils/basic_cstring/basic_cstring.hpp b/boost/test/utils/basic_cstring/basic_cstring.hpp index d6259990e0..fdd87d5211 100644 --- a/boost/test/utils/basic_cstring/basic_cstring.hpp +++ b/boost/test/utils/basic_cstring/basic_cstring.hpp @@ -44,7 +44,7 @@ class basic_cstring { public: // Subtypes typedef ut_detail::bcs_char_traits<CharT> traits_type; - typedef typename ut_detail::bcs_char_traits<CharT>::std_string std_string; + typedef typename traits_type::std_string std_string; typedef CharT value_type; typedef typename remove_cv<value_type>::type value_ret_type; @@ -72,6 +72,7 @@ public: // Constructors; default copy constructor is generated by compiler basic_cstring(); + basic_cstring( basic_cstring const & ); basic_cstring( std_string const& s ); basic_cstring( pointer s ); template<typename LenType> @@ -188,6 +189,16 @@ basic_cstring<CharT>::basic_cstring() template<typename CharT> inline +basic_cstring<CharT>::basic_cstring(basic_cstring const & s) +: m_begin( s.m_begin ) +, m_end( s.m_end ) +{ +} + +//____________________________________________________________________________// + +template<typename CharT> +inline basic_cstring<CharT>::basic_cstring( std_string const& s ) : m_begin( s.c_str() ) , m_end( m_begin + s.size() ) diff --git a/boost/test/utils/basic_cstring/compare.hpp b/boost/test/utils/basic_cstring/compare.hpp index b416b1f2b9..2a256fc6be 100644 --- a/boost/test/utils/basic_cstring/compare.hpp +++ b/boost/test/utils/basic_cstring/compare.hpp @@ -76,9 +76,13 @@ case_ins_eq( basic_cstring<CharT> x, basic_cstring<CharT> y ) // ************************************************************************** // template<class CharT> -class case_ins_less : public std::binary_function<basic_cstring<CharT>,basic_cstring<CharT>,bool> +class case_ins_less { public: + typedef bool result_type; + typedef basic_cstring<CharT> first_argument_type; + typedef basic_cstring<CharT> second_argument_type; + bool operator()( basic_cstring<CharT> x, basic_cstring<CharT> y ) const { return x.size() != y.size() diff --git a/boost/test/utils/is_cstring.hpp b/boost/test/utils/is_cstring.hpp index 914c7cf673..12326b0418 100644 --- a/boost/test/utils/is_cstring.hpp +++ b/boost/test/utils/is_cstring.hpp @@ -23,6 +23,7 @@ #include <boost/type_traits/remove_const.hpp> #include <boost/type_traits/add_const.hpp> +#include <boost/test/utils/basic_cstring/basic_cstring_fwd.hpp> #include <string> //____________________________________________________________________________// @@ -51,19 +52,36 @@ struct is_cstring_impl<char*> : public mpl::true_ {}; template<> struct is_cstring_impl<wchar_t*> : public mpl::true_ {}; +template <typename T, bool is_cstring = is_cstring_impl<typename boost::decay<T>::type>::value > +struct deduce_cstring_impl; + +template <typename T, bool is_cstring > +struct deduce_cstring_impl<T&, is_cstring> : public deduce_cstring_impl<T, is_cstring>{}; + +template <typename T, bool is_cstring > +struct deduce_cstring_impl<T const, is_cstring> : public deduce_cstring_impl<T, is_cstring>{}; + template <typename T> -struct deduce_cstring_impl { +struct deduce_cstring_impl<T, true> { typedef typename boost::add_const< typename boost::remove_pointer< typename boost::decay<T>::type >::type - >::type type; + >::type U; + typedef boost::unit_test::basic_cstring<U> type; +}; + +template <typename T> +struct deduce_cstring_impl< T, false > { + typedef typename + boost::remove_const< + typename boost::remove_reference<T>::type + >::type type; }; template <typename T> -struct deduce_cstring_impl< std::basic_string<T, std::char_traits<T> > > { - // const is required here - typedef typename boost::add_const<T>::type type; +struct deduce_cstring_impl< std::basic_string<T, std::char_traits<T> >, false > { + typedef boost::unit_test::basic_cstring<typename boost::add_const<T>::type> type; }; } // namespace ut_detail @@ -71,8 +89,17 @@ struct deduce_cstring_impl< std::basic_string<T, std::char_traits<T> > > { template<typename T> struct is_cstring : public ut_detail::is_cstring_impl<typename decay<T>::type> {}; +template<typename T, bool is_cstring = is_cstring<typename boost::decay<T>::type>::value > +struct is_cstring_comparable: public mpl::false_ {}; + +template<typename T> +struct is_cstring_comparable< T, true > : public mpl::true_ {}; + +template<typename T> +struct is_cstring_comparable< std::basic_string<T, std::char_traits<T> >, false > : public mpl::true_ {}; + template<typename T> -struct is_cstring< std::basic_string<T, std::char_traits<T> > > : public mpl::true_ {}; +struct is_cstring_comparable< boost::unit_test::basic_cstring<T>, false > : public mpl::true_ {}; template <class T> struct deduce_cstring { @@ -80,7 +107,7 @@ struct deduce_cstring { boost::remove_const< typename boost::remove_reference<T>::type >::type U; - typedef typename ut_detail::deduce_cstring_impl<U>::type type; + typedef typename ut_detail::deduce_cstring_impl<typename boost::decay<U>::type>::type type; }; } // namespace unit_test diff --git a/boost/test/utils/is_forward_iterable.hpp b/boost/test/utils/is_forward_iterable.hpp index b218e96cba..e8f5d39467 100644 --- a/boost/test/utils/is_forward_iterable.hpp +++ b/boost/test/utils/is_forward_iterable.hpp @@ -36,6 +36,7 @@ // Boost #include <boost/utility/declval.hpp> +#include <boost/range.hpp> #include <boost/type_traits/is_same.hpp> #include <boost/type_traits/remove_reference.hpp> #include <boost/type_traits/remove_cv.hpp> @@ -51,6 +52,9 @@ namespace boost { namespace unit_test { +template<typename T> +struct is_forward_iterable; + // ************************************************************************** // // ************** is_forward_iterable ************** // // ************************************************************************** // @@ -65,6 +69,9 @@ struct is_forward_iterable<T const> : public is_forward_iterable<T> {}; template<typename T> struct is_forward_iterable<T&> : public is_forward_iterable<T> {}; +template<typename T, std::size_t N> +struct is_forward_iterable< T [N] > : public mpl::true_ {}; + template<typename T, typename A> struct is_forward_iterable< std::vector<T, A> > : public mpl::true_ {}; @@ -86,6 +93,7 @@ struct is_forward_iterable< std::string > : public mpl::true_ {}; namespace ut_detail { +// SFINAE helper template<typename T> struct is_present : public mpl::true_ {}; @@ -110,10 +118,12 @@ template <class T> struct has_member_begin { private: struct nil_t {}; - template<typename U> static auto test( U* ) -> decltype(boost::declval<U>().begin()); + template<typename U> static auto test( U* ) -> decltype(std::begin(boost::declval<U&>())); // does not work with boost::begin template<typename> static nil_t test( ... ); public: static bool const value = !std::is_same< decltype(test<T>( nullptr )), nil_t>::value; + + }; //____________________________________________________________________________// @@ -122,7 +132,7 @@ template <class T> struct has_member_end { private: struct nil_t {}; - template<typename U> static auto test( U* ) -> decltype(boost::declval<U>().end()); + template<typename U> static auto test( U* ) -> decltype(std::end(boost::declval<U&>())); // does not work with boost::end template<typename> static nil_t test( ... ); public: static bool const value = !std::is_same< decltype(test<T>( nullptr )), nil_t>::value; @@ -134,24 +144,36 @@ template <class T, class enabled = void> struct is_forward_iterable_impl : std::false_type { }; -//____________________________________________________________________________// - template <class T> struct is_forward_iterable_impl< T, typename std::enable_if< - is_present<typename T::const_iterator>::value && - is_present<typename T::value_type>::value && - has_member_size<T>::value && - has_member_begin<T>::value && - has_member_end<T>::value && - !is_cstring<T>::value + has_member_begin<T>::value && + has_member_end<T>::value >::type > : std::true_type {}; //____________________________________________________________________________// +template <class T, class enabled = void> +struct is_container_forward_iterable_impl : std::false_type { +}; + +template <class T> +struct is_container_forward_iterable_impl< + T, + typename std::enable_if< + is_present<typename T::const_iterator>::value && + is_present<typename T::value_type>::value && + has_member_size<T>::value && + is_forward_iterable_impl<T>::value + >::type +> : is_forward_iterable_impl<T> +{}; + +//____________________________________________________________________________// + } // namespace ut_detail /*! Indicates that a specific type implements the forward iterable concept. */ @@ -163,8 +185,54 @@ struct is_forward_iterable { enum { value = is_fwd_it_t::value }; }; +/*! Indicates that a specific type implements the forward iterable concept. */ +template<typename T> +struct is_container_forward_iterable { + typedef typename std::remove_reference<T>::type T_ref; + typedef ut_detail::is_container_forward_iterable_impl<T_ref> is_fwd_it_t; + typedef mpl::bool_<is_fwd_it_t::value> type; + enum { value = is_fwd_it_t::value }; +}; + #endif /* defined(BOOST_TEST_FWD_ITERABLE_CXX03) */ +template <typename T, bool is_forward_iterable = is_forward_iterable<T>::value > +struct bt_iterator_traits; + +template <typename T> +struct bt_iterator_traits< T, true >{ + BOOST_STATIC_ASSERT((is_forward_iterable<T>::value)); //, "only for forward iterable types"); + typedef typename T::const_iterator const_iterator; + typedef typename T::value_type value_type; + + static const_iterator begin(T const& container) { + return container.begin(); + } + static const_iterator end(T const& container) { + return container.end(); + } + static std::size_t size(T const& container) { + return container.size(); + } +}; + +template <typename T, std::size_t N> +struct bt_iterator_traits< T [N], true > { + typedef typename boost::add_const<T>::type T_const; + typedef typename boost::add_pointer<T_const>::type const_iterator; + typedef T value_type; + + static const_iterator begin(T_const (&array)[N]) { + return &array[0]; + } + static const_iterator end(T_const (&array)[N]) { + return &array[N]; + } + static std::size_t size(T_const (&)[N]) { + return N; + } +}; + } // namespace unit_test } // namespace boost |