diff options
author | DongHun Kwak <dh0128.kwak@samsung.com> | 2017-09-13 11:24:46 +0900 |
---|---|---|
committer | DongHun Kwak <dh0128.kwak@samsung.com> | 2017-09-13 11:25:39 +0900 |
commit | 4fadd968fa12130524c8380f33fcfe25d4de79e5 (patch) | |
tree | fd26a490cd15388d42fc6652b3c5c13012e7f93e /boost/test/impl | |
parent | b5c87084afaef42b2d058f68091be31988a6a874 (diff) | |
download | boost-4fadd968fa12130524c8380f33fcfe25d4de79e5.tar.gz boost-4fadd968fa12130524c8380f33fcfe25d4de79e5.tar.bz2 boost-4fadd968fa12130524c8380f33fcfe25d4de79e5.zip |
Imported Upstream version 1.65.0upstream/1.65.0
Change-Id: Icf8400b375482cb11bcf77440a6934ba360d6ba4
Signed-off-by: DongHun Kwak <dh0128.kwak@samsung.com>
Diffstat (limited to 'boost/test/impl')
-rw-r--r-- | boost/test/impl/compiler_log_formatter.ipp | 16 | ||||
-rw-r--r-- | boost/test/impl/execution_monitor.ipp | 6 | ||||
-rw-r--r-- | boost/test/impl/framework.ipp | 210 | ||||
-rw-r--r-- | boost/test/impl/junit_log_formatter.ipp | 274 | ||||
-rw-r--r-- | boost/test/impl/results_collector.ipp | 6 | ||||
-rw-r--r-- | boost/test/impl/test_framework_init_observer.ipp | 109 | ||||
-rw-r--r-- | boost/test/impl/test_tools.ipp | 45 | ||||
-rw-r--r-- | boost/test/impl/test_tree.ipp | 19 | ||||
-rw-r--r-- | boost/test/impl/unit_test_log.ipp | 6 | ||||
-rw-r--r-- | boost/test/impl/unit_test_monitor.ipp | 2 | ||||
-rw-r--r-- | boost/test/impl/xml_log_formatter.ipp | 4 |
11 files changed, 550 insertions, 147 deletions
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>" ); } |