diff options
Diffstat (limited to 'boost/test/impl')
23 files changed, 3091 insertions, 2434 deletions
diff --git a/boost/test/impl/compiler_log_formatter.ipp b/boost/test/impl/compiler_log_formatter.ipp index 8fc08ccf44..c1ed944ab1 100644 --- a/boost/test/impl/compiler_log_formatter.ipp +++ b/boost/test/impl/compiler_log_formatter.ipp @@ -1,6 +1,6 @@ -// (C) Copyright Gennadiy Rozental 2005-2008. +// (C) Copyright Gennadiy Rozental 2005-2014. // Distributed under the Boost Software License, Version 1.0. -// (See accompanying file LICENSE_1_0.txt or copy at +// (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. @@ -16,11 +16,14 @@ #define BOOST_TEST_COMPILER_LOG_FORMATTER_IPP_020105GER // Boost.Test -#include <boost/test/output/compiler_log_formatter.hpp> -#include <boost/test/unit_test_suite_impl.hpp> #include <boost/test/framework.hpp> +#include <boost/test/execution_monitor.hpp> +#include <boost/test/tree/test_unit.hpp> #include <boost/test/utils/basic_cstring/io.hpp> #include <boost/test/utils/lazy_ostream.hpp> +#include <boost/test/utils/setcolor.hpp> +#include <boost/test/output/compiler_log_formatter.hpp> +#include <boost/test/unit_test_parameters.hpp> // Boost #include <boost/version.hpp> @@ -33,9 +36,7 @@ //____________________________________________________________________________// namespace boost { - namespace unit_test { - namespace output { // ************************************************************************** // @@ -44,12 +45,10 @@ namespace output { namespace { -const_string +std::string test_phase_identifier() { - return framework::is_initialized() - ? const_string( framework::current_test_case().p_name.get() ) - : BOOST_TEST_L( "Test setup" ); + return framework::test_in_progress() ? framework::current_test_case().full_name() : std::string( "Test setup" ); } } // local namespace @@ -90,6 +89,10 @@ compiler_log_formatter::log_build_info( std::ostream& output ) void compiler_log_formatter::test_unit_start( std::ostream& output, test_unit const& tu ) { + BOOST_TEST_SCOPE_SETCOLOR( output, term_attr::BRIGHT, term_color::BLUE ); + + print_prefix( output, tu.p_file_name, tu.p_line_num ); + output << "Entering test " << tu.p_type_name << " \"" << tu.p_name << "\"" << std::endl; } @@ -98,6 +101,10 @@ compiler_log_formatter::test_unit_start( std::ostream& output, test_unit const& void compiler_log_formatter::test_unit_finish( std::ostream& output, test_unit const& tu, unsigned long elapsed ) { + BOOST_TEST_SCOPE_SETCOLOR( output, term_attr::BRIGHT, term_color::BLUE ); + + print_prefix( output, tu.p_file_name, tu.p_line_num ); + output << "Leaving test " << tu.p_type_name << " \"" << tu.p_name << "\""; if( elapsed > 0 ) { @@ -105,7 +112,7 @@ compiler_log_formatter::test_unit_finish( std::ostream& output, test_unit const& if( elapsed % 1000 == 0 ) output << elapsed/1000 << "ms"; else - output << elapsed << "mks"; + output << elapsed << "us"; } output << std::endl; @@ -114,31 +121,48 @@ compiler_log_formatter::test_unit_finish( std::ostream& output, test_unit const& //____________________________________________________________________________// void -compiler_log_formatter::test_unit_skipped( std::ostream& output, test_unit const& tu ) +compiler_log_formatter::test_unit_skipped( std::ostream& output, test_unit const& tu, const_string reason ) { - output << "Test " << tu.p_type_name << " \"" << tu.p_name << "\"" << "is skipped" << std::endl; + BOOST_TEST_SCOPE_SETCOLOR( output, term_attr::BRIGHT, term_color::YELLOW ); + + print_prefix( output, tu.p_file_name, tu.p_line_num ); + + output << "Test " << tu.p_type_name << " \"" << tu.full_name() << "\"" << " is skipped because " << reason << std::endl; } - + //____________________________________________________________________________// void -compiler_log_formatter::log_exception( std::ostream& output, log_checkpoint_data const& checkpoint_data, execution_exception const& ex ) +compiler_log_formatter::log_exception_start( std::ostream& output, log_checkpoint_data const& checkpoint_data, execution_exception const& ex ) { execution_exception::location const& loc = ex.where(); + print_prefix( output, loc.m_file_name, loc.m_line_num ); - output << "fatal error in \"" << (loc.m_function.is_empty() ? test_phase_identifier() : loc.m_function ) << "\": "; + { + BOOST_TEST_SCOPE_SETCOLOR( output, term_attr::BLINK, term_color::RED ); - output << ex.what(); + output << "fatal error: in \"" << (loc.m_function.is_empty() ? test_phase_identifier() : loc.m_function ) << "\": " + << ex.what(); + } if( !checkpoint_data.m_file_name.is_empty() ) { output << '\n'; print_prefix( output, checkpoint_data.m_file_name, checkpoint_data.m_line_num ); + + BOOST_TEST_SCOPE_SETCOLOR( output, term_attr::BRIGHT, term_color::CYAN ); + output << "last checkpoint"; if( !checkpoint_data.m_message.empty() ) output << ": " << checkpoint_data.m_message; } - +} + +//____________________________________________________________________________// + +void +compiler_log_formatter::log_exception_finish( std::ostream& output ) +{ output << std::endl; } @@ -150,21 +174,31 @@ compiler_log_formatter::log_entry_start( std::ostream& output, log_entry_data co switch( let ) { case BOOST_UTL_ET_INFO: print_prefix( output, entry_data.m_file_name, entry_data.m_line_num ); + if( runtime_config::color_output() ) + output << setcolor( term_attr::BRIGHT, term_color::GREEN ); output << "info: "; break; case BOOST_UTL_ET_MESSAGE: + if( runtime_config::color_output() ) + output << setcolor( term_attr::BRIGHT, term_color::CYAN ); break; case BOOST_UTL_ET_WARNING: print_prefix( output, entry_data.m_file_name, entry_data.m_line_num ); - output << "warning in \"" << test_phase_identifier() << "\": "; + if( runtime_config::color_output() ) + output << setcolor( term_attr::BRIGHT, term_color::YELLOW ); + output << "warning: in \"" << test_phase_identifier() << "\": "; break; case BOOST_UTL_ET_ERROR: print_prefix( output, entry_data.m_file_name, entry_data.m_line_num ); - output << "error in \"" << test_phase_identifier() << "\": "; + if( runtime_config::color_output() ) + output << setcolor( term_attr::BRIGHT, term_color::RED ); + output << "error: in \"" << test_phase_identifier() << "\": "; break; case BOOST_UTL_ET_FATAL_ERROR: print_prefix( output, entry_data.m_file_name, entry_data.m_line_num ); - output << "fatal error in \"" << test_phase_identifier() << "\": "; + if( runtime_config::color_output() ) + output << setcolor( term_attr::BLINK, term_color::RED ); + output << "fatal error: in \"" << test_phase_identifier() << "\": "; break; } } @@ -190,33 +224,60 @@ compiler_log_formatter::log_entry_value( std::ostream& output, lazy_ostream cons void compiler_log_formatter::log_entry_finish( std::ostream& output ) { + if( runtime_config::color_output() ) + output << setcolor(); + output << std::endl; } + //____________________________________________________________________________// void -compiler_log_formatter::print_prefix( std::ostream& output, const_string file, std::size_t line ) +compiler_log_formatter::print_prefix( std::ostream& output, const_string file_name, std::size_t line_num ) { + if( !file_name.empty() ) + { #ifdef __APPLE_CC__ - // Xcode-compatible logging format, idea by Richard Dingwall at - // <http://richarddingwall.name/2008/06/01/using-the-boost-unit-test-framework-with-xcode-3/>. - output << file << ':' << line << ": "; + // Xcode-compatible logging format, idea by Richard Dingwall at + // <http://richarddingwall.name/2008/06/01/using-the-boost-unit-test-framework-with-xcode-3/>. + output << file_name << ':' << line_num << ": "; #else - output << file << '(' << line << "): "; + output << file_name << '(' << line_num << "): "; #endif + } } //____________________________________________________________________________// -} // namespace output +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:"; +} -} // namespace unit_test +//____________________________________________________________________________// -} // namespace boost +void +compiler_log_formatter::entry_context_finish( std::ostream& output ) +{ + output.flush(); +} //____________________________________________________________________________// +void +compiler_log_formatter::log_entry_context( std::ostream& output, const_string context_descr ) +{ + output << "\n " << context_descr; +} + +//____________________________________________________________________________// + +} // namespace output +} // namespace unit_test +} // namespace boost + #include <boost/test/detail/enable_warnings.hpp> #endif // BOOST_TEST_COMPILER_LOG_FORMATTER_IPP_020105GER diff --git a/boost/test/impl/cpp_main.ipp b/boost/test/impl/cpp_main.ipp index 23d19e2f31..5cab0f4274 100644 --- a/boost/test/impl/cpp_main.ipp +++ b/boost/test/impl/cpp_main.ipp @@ -1,7 +1,7 @@ -// (C) Copyright Gennadiy Rozental 2001-2008. +// (C) Copyright Gennadiy Rozental 2001-2014. // (C) Copyright Beman Dawes 1995-2001. // Distributed under the Boost Software License, Version 1.0. -// (See accompanying file LICENSE_1_0.txt or copy at +// (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. @@ -41,18 +41,18 @@ namespace std { using ::getenv; using ::strerror; } namespace { struct cpp_main_caller { - cpp_main_caller( int (*cpp_main_func)( int argc, char* argv[] ), int argc, char** argv ) + cpp_main_caller( int (*cpp_main_func)( int argc, char* argv[] ), int argc, char** argv ) : m_cpp_main_func( cpp_main_func ) , m_argc( argc ) , m_argv( argv ) {} - - int operator()() { return (*m_cpp_main_func)( m_argc, m_argv ); } - + + int operator()() { return (*m_cpp_main_func)( m_argc, m_argv ); } + private: - // Data members - int (*m_cpp_main_func)( int argc, char* argv[] ); - int m_argc; - char** m_argv; + // Data members + int (*m_cpp_main_func)( int argc, char* argv[] ); + int m_argc; + char** m_argv; }; } // local namespace @@ -68,15 +68,14 @@ prg_exec_monitor_main( int (*cpp_main)( int argc, char* argv[] ), int argc, char { int result = 0; - try { + BOOST_TEST_IMPL_TRY { boost::unit_test::const_string p( std::getenv( "BOOST_TEST_CATCH_SYSTEM_ERRORS" ) ); ::boost::execution_monitor ex_mon; ex_mon.p_catch_system_errors.value = p != "no"; - - result = ex_mon.execute( - ::boost::unit_test::callback0<int>( cpp_main_caller( cpp_main, argc, argv ) ) ); - + + result = ex_mon.execute( cpp_main_caller( cpp_main, argc, argv ) ); + if( result == 0 ) result = ::boost::exit_success; else if( result != ::boost::exit_success ) { @@ -84,13 +83,13 @@ prg_exec_monitor_main( int (*cpp_main)( int argc, char* argv[] ), int argc, char result = ::boost::exit_failure; } } - catch( ::boost::execution_exception const& exex ) { + BOOST_TEST_IMPL_CATCH( ::boost::execution_exception, exex ) { std::cout << "\n**** exception(" << exex.code() << "): " << exex.what() << std::endl; result = ::boost::exit_exception_failure; } - catch( ::boost::system_error const& ex ) { + BOOST_TEST_IMPL_CATCH( ::boost::system_error, ex ) { std::cout << "\n**** failed to initialize execution monitor." - << "\n**** expression at fault: " << ex.p_failed_exp + << "\n**** expression at fault: " << ex.p_failed_exp << "\n**** error(" << ex.p_errno << "): " << std::strerror( ex.p_errno ) << std::endl; result = ::boost::exit_exception_failure; } @@ -104,8 +103,8 @@ prg_exec_monitor_main( int (*cpp_main)( int argc, char* argv[] ), int argc, char // line argument modifications; for use in production programs // that's a no-no in some organizations. ::boost::unit_test::const_string p( std::getenv( "BOOST_PRG_MON_CONFIRM" ) ); - if( p != "no" ) { - std::cerr << std::flush << "no errors detected" << std::endl; + if( p != "no" ) { + std::cerr << std::flush << "no errors detected" << std::endl; } } @@ -132,8 +131,6 @@ main( int argc, char* argv[] ) #endif // !BOOST_TEST_DYN_LINK && !BOOST_TEST_NO_MAIN -//____________________________________________________________________________// - #include <boost/test/detail/enable_warnings.hpp> #endif // BOOST_TEST_CPP_MAIN_IPP_012205GER diff --git a/boost/test/impl/debug.ipp b/boost/test/impl/debug.ipp index 78c3aa8e38..90e9d7ff2f 100644 --- a/boost/test/impl/debug.ipp +++ b/boost/test/impl/debug.ipp @@ -1,4 +1,4 @@ -// (C) Copyright Gennadiy Rozental 2006-2008. +// (C) Copyright Gennadiy Rozental 2006-2014. // Use, modification, and distribution are subject to the // Boost Software License, Version 1.0. (See accompanying file // http://www.boost.org/LICENSE_1_0.txt) @@ -40,10 +40,6 @@ # endif -# if BOOST_WORKAROUND( BOOST_MSVC, <1300) -# define snprintf _snprintf -# endif - # ifdef BOOST_NO_STDC_NAMESPACE namespace std { using ::memset; using ::sprintf; } # endif @@ -113,7 +109,6 @@ namespace std { using ::memset; using ::sprintf; } //____________________________________________________________________________// namespace boost { - namespace debug { using unit_test::const_string; @@ -210,10 +205,11 @@ private: #if defined(BOOST_SUN_BASED_DEBUG) struct psinfo m_psi; + char m_binary_path_buff[500+1]; // !! ?? #elif defined(BOOST_LINUX_BASED_DEBUG) char m_stat_line[BOOST_TEST_STAT_LINE_MAX+1]; -#endif char m_binary_path_buff[500+1]; // !! ?? +#endif }; //____________________________________________________________________________// @@ -239,12 +235,12 @@ process_info::process_info( int pid ) m_binary_name.assign( m_psi.pr_fname ); //-------------------------- // - + ::snprintf( fname_buff, sizeof(fname_buff), "/proc/%d/as", pid ); fd_holder as_fd( ::open( fname_buff, O_RDONLY ) ); uintptr_t binary_name_pos; - + // !! ?? could we avoid reading whole m_binary_path_buff? if( as_fd == -1 || ::lseek( as_fd, m_psi.pr_argv, SEEK_SET ) == -1 || @@ -252,9 +248,9 @@ process_info::process_info( int pid ) ::lseek( as_fd, binary_name_pos, SEEK_SET ) == -1 || ::read ( as_fd, m_binary_path_buff, sizeof(m_binary_path_buff) ) == -1 ) return; - + m_binary_path.assign( m_binary_path_buff ); - + #elif defined(BOOST_LINUX_BASED_DEBUG) char fname_buff[30]; @@ -377,8 +373,10 @@ safe_execlp( char const* file, ... ) va_start( args, file ); while( !!(arg = va_arg( args, char const* )) ) { printf( "!! %s\n", arg ); - if( !(*argv_it++ = copy_arg( work_buff, arg )) ) + if( !(*argv_it++ = copy_arg( work_buff, arg )) ) { + va_end( args ); return false; + } } va_end( args ); @@ -440,7 +438,7 @@ prepare_gdb_cmnd_file( dbg_startup_info const& dsi ) WRITE_CSTR( "\ncont" ); if( dsi.break_or_continue ) WRITE_CSTR( "\nup 4" ); - + WRITE_CSTR( "\necho \\n" ); // !! ?? WRITE_CSTR( "\nlist -" ); WRITE_CSTR( "\nlist" ); @@ -513,9 +511,9 @@ prepare_dbx_cmd_line( dbg_startup_info const& dsi, bool list_source = true ) { static char cmd_line_buff[500]; // !! ?? - ::snprintf( cmd_line_buff, sizeof(cmd_line_buff), "unlink %s;cont;%s%s", - dsi.init_done_lock.begin(), - dsi.break_or_continue ? "up 2;": "", + ::snprintf( cmd_line_buff, sizeof(cmd_line_buff), "unlink %s;cont;%s%s", + dsi.init_done_lock.begin(), + dsi.break_or_continue ? "up 2;": "", list_source ? "echo \" \";list -w3;" : "" ); return cmd_line_buff; @@ -543,8 +541,8 @@ start_dbx_in_xterm( dbg_startup_info const& dsi ) char pid_buff[16]; // !! ?? ::snprintf( pid_buff, sizeof(pid_buff), "%ld", dsi.pid ); - - safe_execlp( "xterm", "-T", title, "-display", dsi.display.begin(), + + safe_execlp( "xterm", "-T", title, "-display", dsi.display.begin(), "-bg", "black", "-fg", "white", "-geometry", "88x30+10+10", "-fn", "9x15", "-e", "dbx", "-q", "-c", prepare_dbx_cmd_line( dsi ), dsi.binary_path.begin(), pid_buff, 0 ); } @@ -580,7 +578,7 @@ start_dbx_in_ddd( dbg_startup_info const& dsi ) char pid_buff[16]; // !! ?? ::snprintf( pid_buff, sizeof(pid_buff), "%ld", dsi.pid ); - + safe_execlp( "ddd", "-display", dsi.display.begin(), "--dbx", "-q", "-c", prepare_dbx_cmd_line( dsi, false ), dsi.binary_path.begin(), pid_buff, 0 ); } @@ -597,7 +595,7 @@ static struct info_t { // Public properties unit_test::readwrite_property<std::string> p_dbg; - + // Data members std::map<std::string,dbg_starter> m_dbg_starter_reg; } s_info; @@ -609,7 +607,7 @@ info_t::info_t() p_dbg.value = ::getenv( "DISPLAY" ) ? std::string( BOOST_STRINGIZE( BOOST_TEST_GUI_DBG ) ) : std::string( BOOST_STRINGIZE( BOOST_TEST_CNL_DBG ) ); - + m_dbg_starter_reg[std::string("gdb")] = &start_gdb_in_console; m_dbg_starter_reg[std::string("gdb-emacs")] = &start_gdb_in_emacs; m_dbg_starter_reg[std::string("gdb-xterm")] = &start_gdb_in_xterm; @@ -679,8 +677,7 @@ debugger_break() #if defined(BOOST_WIN32_BASED_DEBUG) // *********************** WIN32 -#if BOOST_WORKAROUND(BOOST_MSVC, >= 1300) || \ - BOOST_WORKAROUND(__GNUC__, >= 3) && !defined(__MINGW32__) || \ +#if defined(__GNUC__) && !defined(__MINGW32__) || \ defined(__INTEL_COMPILER) # define BOOST_DEBUG_BREAK __debugbreak #else @@ -734,7 +731,7 @@ set_debugger( unit_test::const_string dbg_id, dbg_starter s ) assign_op( s_info.p_dbg.value, dbg_id, 0 ); if( !!s ) - s_info.m_dbg_starter_reg[s_info.p_dbg] = s; + s_info.m_dbg_starter_reg[s_info.p_dbg.get()] = s; return old; } @@ -864,7 +861,7 @@ attach_debugger( bool break_or_continue ) if( init_done_lock_fd == -1 ) return false; - + pid_t child_pid = fork(); if( child_pid == -1 ) @@ -872,7 +869,7 @@ attach_debugger( bool break_or_continue ) if( child_pid != 0 ) { // parent process - here we will start the debugger dbg_startup_info dsi; - + process_info pi( child_pid ); if( pi.binary_path().is_empty() ) ::exit( -1 ); @@ -882,7 +879,7 @@ attach_debugger( bool break_or_continue ) dsi.binary_path = pi.binary_path(); dsi.display = ::getenv( "DISPLAY" ); dsi.init_done_lock = init_done_lock_fn; - + dbg_starter starter = s_info.m_dbg_starter_reg[s_info.p_dbg]; if( !!starter ) starter( dsi ); @@ -922,7 +919,7 @@ attach_debugger( bool break_or_continue ) // ************************************************************************** // void -detect_memory_leaks( bool on_off ) +detect_memory_leaks( bool on_off, unit_test::const_string report_file ) { unit_test::ut_detail::ignore_unused_variable_warning( on_off ); @@ -934,10 +931,19 @@ detect_memory_leaks( bool on_off ) else { flags |= _CRTDBG_LEAK_CHECK_DF; _CrtSetReportMode(_CRT_WARN, _CRTDBG_MODE_FILE); - _CrtSetReportFile(_CRT_WARN, _CRTDBG_FILE_STDOUT); + + if( report_file.is_empty() ) + _CrtSetReportFile(_CRT_WARN, _CRTDBG_FILE_STDERR); + else { + HANDLE hreport_f = ::CreateFileA( report_file.begin(), + GENERIC_WRITE, FILE_SHARE_WRITE, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL); + _CrtSetReportFile(_CRT_WARN, hreport_f ); + } } _CrtSetDbgFlag ( flags ); +#else + unit_test::ut_detail::ignore_unused_variable_warning( report_file ); #endif // BOOST_MS_CRT_BASED_DEBUG } @@ -954,16 +960,17 @@ break_memory_alloc( long mem_alloc_order_num ) unit_test::ut_detail::ignore_unused_variable_warning( mem_alloc_order_num ); #ifdef BOOST_MS_CRT_BASED_DEBUG - _CrtSetBreakAlloc( mem_alloc_order_num ); + // only set the value if one was supplied (do not use default used by UTF just as a indicator to enable leak detection) + if( mem_alloc_order_num > 1 ) + _CrtSetBreakAlloc( mem_alloc_order_num ); #endif // BOOST_MS_CRT_BASED_DEBUG } -} // namespace debug +//____________________________________________________________________________// +} // namespace debug } // namespace boost -//____________________________________________________________________________// - #include <boost/test/detail/enable_warnings.hpp> #endif // BOOST_TEST_DEBUG_API_IPP_112006GER diff --git a/boost/test/impl/decorator.ipp b/boost/test/impl/decorator.ipp new file mode 100644 index 0000000000..bf17907881 --- /dev/null +++ b/boost/test/impl/decorator.ipp @@ -0,0 +1,202 @@ +// (C) Copyright Gennadiy Rozental 2011-2014. +// 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 : $RCSfile$ +// +// Version : $Revision$ +// +// Description : unit test decorators implementation +// *************************************************************************** + +#ifndef BOOST_TEST_TREE_DECORATOR_IPP_091911GER +#define BOOST_TEST_TREE_DECORATOR_IPP_091911GER + +// Boost.Test +#include <boost/test/tree/decorator.hpp> +#include <boost/test/tree/test_unit.hpp> + +#include <boost/test/framework.hpp> +#if BOOST_TEST_SUPPORT_TOKEN_ITERATOR +#include <boost/test/utils/iterator/token_iterator.hpp> +#endif + +#include <boost/test/detail/throw_exception.hpp> + +#include <boost/test/detail/suppress_warnings.hpp> + +//____________________________________________________________________________// + +namespace boost { +namespace unit_test { +namespace decorator { + +// ************************************************************************** // +// ************** decorator::collector ************** // +// ************************************************************************** // + +collector& +collector::operator*( base const& d ) +{ + m_tu_decorators.push_back( d.clone() ); + + return *this; +} + +//____________________________________________________________________________// + +void +collector::store_in( test_unit& tu ) +{ + tu.p_decorators.value.insert( tu.p_decorators.value.end(), m_tu_decorators.begin(), m_tu_decorators.end() ); +} + +//____________________________________________________________________________// + +void +collector::reset() +{ + m_tu_decorators.clear(); +} + +//____________________________________________________________________________// + +// ************************************************************************** // +// ************** decorator::base ************** // +// ************************************************************************** // + +collector& +base::operator*() const +{ + return collector::instance() * *this; +} + +// ************************************************************************** // +// ************** decorator::label ************** // +// ************************************************************************** // + +void +label::apply( test_unit& tu ) +{ + tu.add_label( m_label ); +} + +//____________________________________________________________________________// + +// ************************************************************************** // +// ************** decorator::expected_failures ************** // +// ************************************************************************** // + +void +expected_failures::apply( test_unit& tu ) +{ + tu.increase_exp_fail( m_exp_fail ); +} + +//____________________________________________________________________________// + +// ************************************************************************** // +// ************** decorator::timeout ************** // +// ************************************************************************** // + +void +timeout::apply( test_unit& tu ) +{ + tu.p_timeout.value = m_timeout; +} + +//____________________________________________________________________________// + +// ************************************************************************** // +// ************** decorator::description ************** // +// ************************************************************************** // + +void +description::apply( test_unit& tu ) +{ + tu.p_description.value += m_description; +} + +//____________________________________________________________________________// + +// ************************************************************************** // +// ************** decorator::depends_on ************** // +// ************************************************************************** // + +void +depends_on::apply( test_unit& tu ) +{ +#if !BOOST_TEST_SUPPORT_TOKEN_ITERATOR + BOOST_TEST_SETUP_ASSERT( false, "depends_on decorator is not supported on this platform" ); +#else + string_token_iterator tit( m_dependency, (dropped_delimeters = "/", kept_delimeters = dt_none) ); + + test_unit* dep = &framework::master_test_suite(); + while( tit != string_token_iterator() ) { + BOOST_TEST_SETUP_ASSERT( dep->p_type == TUT_SUITE, std::string( "incorrect dependency specification " ) + m_dependency ); + + test_unit_id next_id = static_cast<test_suite*>(dep)->get( *tit ); + + BOOST_TEST_SETUP_ASSERT( next_id != INV_TEST_UNIT_ID, + std::string( "incorrect dependency specification " ) + m_dependency ); + + dep = &framework::get( next_id, TUT_ANY ); + ++tit; + } + + tu.depends_on( dep ); +#endif +} + +//____________________________________________________________________________// + +// ************************************************************************** // +// ************** decorator::enable_if/enabled/disabled ************** // +// ************************************************************************** // + +void +enable_if_impl::apply_impl( test_unit& tu, bool condition ) +{ + BOOST_TEST_SETUP_ASSERT(tu.p_default_status == test_unit::RS_INHERIT, + "Can't apply multiple enabled/disabled decorators " + "to the same test unit " + tu.full_name()); + + tu.p_default_status.value = condition ? test_unit::RS_ENABLED : test_unit::RS_DISABLED; +} + +//____________________________________________________________________________// + +// ************************************************************************** // +// ************** decorator::fixture ************** // +// ************************************************************************** // + +void +fixture_t::apply( test_unit& tu ) +{ + tu.p_fixtures.value.push_back( m_impl ); +} + +//____________________________________________________________________________// + +// ************************************************************************** // +// ************** decorator::depends_on ************** // +// ************************************************************************** // + +void +precondition::apply( test_unit& tu ) +{ + tu.add_precondition( m_precondition ); +} + +//____________________________________________________________________________// + +} // namespace decorator +} // namespace unit_test +} // namespace boost + +#include <boost/test/detail/enable_warnings.hpp> + +#endif // BOOST_TEST_TREE_DECORATOR_IPP_091911GER diff --git a/boost/test/impl/exception_safety.ipp b/boost/test/impl/exception_safety.ipp deleted file mode 100644 index 7f0afcb457..0000000000 --- a/boost/test/impl/exception_safety.ipp +++ /dev/null @@ -1,537 +0,0 @@ -// (C) Copyright Gennadiy Rozental 2005-2008. -// Use, modification, and distribution are subject to the -// Boost Software License, Version 1.0. (See accompanying file -// http://www.boost.org/LICENSE_1_0.txt) - -// See http://www.boost.org/libs/test for the library home page. -// -// File : $RCSfile$ -// -// Version : $Revision$ -// -// Description : Facilities to perform exception safety tests -// *************************************************************************** - -#ifndef BOOST_TEST_EXECUTION_SAFETY_IPP_112005GER -#define BOOST_TEST_EXECUTION_SAFETY_IPP_112005GER - -// Boost.Test -#include <boost/test/detail/config.hpp> - -#if BOOST_TEST_SUPPORT_INTERACTION_TESTING - -#include <boost/test/detail/global_typedef.hpp> -#include <boost/test/detail/unit_test_parameters.hpp> - -#include <boost/test/utils/callback.hpp> -#include <boost/test/utils/wrap_stringstream.hpp> -#include <boost/test/utils/iterator/token_iterator.hpp> - -#include <boost/test/interaction_based.hpp> -#include <boost/test/test_tools.hpp> -#include <boost/test/unit_test_log.hpp> -#include <boost/test/framework.hpp> -#include <boost/test/test_observer.hpp> -#include <boost/test/debug.hpp> - -#include <boost/test/detail/suppress_warnings.hpp> - -// Boost -#include <boost/lexical_cast.hpp> - -// STL -#include <vector> -#include <cstdlib> -#include <map> -#include <iomanip> -#include <cctype> -#include <boost/limits.hpp> - -//____________________________________________________________________________// - -namespace boost { - -using namespace ::boost::unit_test; - -namespace itest { - -// ************************************************************************** // -// ************** execution_path_point ************** // -// ************************************************************************** // - -enum exec_path_point_type { EPP_SCOPE, EPP_EXCEPT, EPP_DECISION, EPP_ALLOC }; - -struct execution_path_point { - execution_path_point( exec_path_point_type t, const_string file, std::size_t line_num ) - : m_type( t ) - , m_file_name( file ) - , m_line_num( line_num ) - {} - - exec_path_point_type m_type; - const_string m_file_name; - std::size_t m_line_num; - - // Execution path point specific - struct decision_data { - bool value; - unsigned forced_exception_point; - }; - struct scope_data { - unsigned size; - char const* name; - }; - struct except_data { - char const* description; - }; - struct alloc_data { - void* ptr; - std::size_t size; - }; - - union { - struct decision_data m_decision; - struct scope_data m_scope; - struct except_data m_except; - struct alloc_data m_alloc; - }; -}; - -// ************************************************************************** // -// ************** exception safety test implementation ************** // -// ************************************************************************** // - -struct exception_safety_tester : itest::manager, test_observer { - // helpers types - struct unique_exception {}; - - // Constructor - explicit exception_safety_tester( const_string test_name ); - ~exception_safety_tester(); - - // check last run and prepare for next - bool next_execution_path(); - - // memory tracking - - // manager interface implementation - virtual void exception_point( const_string file, std::size_t line_num, const_string description ); - virtual bool decision_point( const_string file, std::size_t line_num ); - virtual unsigned enter_scope( const_string file, std::size_t line_num, const_string scope_name ); - virtual void leave_scope( unsigned enter_scope_point ); - virtual void allocated( const_string file, std::size_t line_num, void* p, std::size_t s ); - virtual void freed( void* p ); - - // test observer interface - virtual void assertion_result( bool passed ); - virtual int priority() { return (std::numeric_limits<int>::max)(); } // we want this observer to run the last - -private: - void failure_point(); - void report_error(); - - typedef std::vector<execution_path_point> exec_path; - typedef std::map<void*,unsigned> registry; - - // Data members - bool m_internal_activity; - - unsigned m_exception_point_counter; - unsigned m_forced_exception_point; - - unsigned m_exec_path_point; - exec_path m_execution_path; - - unsigned m_exec_path_counter; - unsigned m_break_exec_path; - - bool m_invairant_failed; - registry m_memory_in_use; -}; - -//____________________________________________________________________________// - -struct activity_guard { - bool& m_v; - - activity_guard( bool& v ) : m_v( v ) { m_v = true; } - ~activity_guard() { m_v = false; } -}; - -//____________________________________________________________________________// - -exception_safety_tester::exception_safety_tester( const_string test_name ) -: m_internal_activity( true ) -, m_exception_point_counter( 0 ) -, m_forced_exception_point( 1 ) -, m_exec_path_point( 0 ) -, m_exec_path_counter( 1 ) -, m_break_exec_path( static_cast<unsigned>(-1) ) -, m_invairant_failed( false ) -{ - framework::register_observer( *this ); - - if( !runtime_config::break_exec_path().is_empty() ) { - using namespace unit_test; - - string_token_iterator tit( runtime_config::break_exec_path(), - (dropped_delimeters = ":",kept_delimeters = " ") ); - - const_string test_to_break = *tit; - - if( test_to_break == test_name ) { - ++tit; - - m_break_exec_path = lexical_cast<unsigned>( *tit ); - } - } - - m_internal_activity = false; -} - -//____________________________________________________________________________// - -exception_safety_tester::~exception_safety_tester() -{ - m_internal_activity = true; - - framework::deregister_observer( *this ); -} - -//____________________________________________________________________________// - -bool -exception_safety_tester::next_execution_path() -{ - activity_guard ag( m_internal_activity ); - - // check memory usage - if( m_execution_path.size() > 0 ) { - bool errors_detected = m_invairant_failed || (m_memory_in_use.size() != 0); - framework::assertion_result( !errors_detected ); - - if( errors_detected ) - report_error(); - - m_memory_in_use.clear(); - } - - m_exec_path_point = 0; - m_exception_point_counter = 0; - m_invairant_failed = false; - ++m_exec_path_counter; - - while( m_execution_path.size() > 0 ) { - switch( m_execution_path.back().m_type ) { - case EPP_SCOPE: - case EPP_ALLOC: - m_execution_path.pop_back(); - break; - - case EPP_DECISION: - if( !m_execution_path.back().m_decision.value ) { - m_execution_path.pop_back(); - break; - } - - m_execution_path.back().m_decision.value = false; - m_forced_exception_point = m_execution_path.back().m_decision.forced_exception_point; - return true; - - case EPP_EXCEPT: - m_execution_path.pop_back(); - ++m_forced_exception_point; - return true; - } - } - - BOOST_TEST_MESSAGE( "Total tested " << --m_exec_path_counter << " execution path" ); - - return false; -} - -//____________________________________________________________________________// - -void -exception_safety_tester::exception_point( const_string file, std::size_t line_num, const_string description ) -{ - activity_guard ag( m_internal_activity ); - - if( ++m_exception_point_counter == m_forced_exception_point ) { - m_execution_path.push_back( - execution_path_point( EPP_EXCEPT, file, line_num ) ); - - m_execution_path.back().m_except.description = description.begin(); - - ++m_exec_path_point; - - failure_point(); - } -} - -//____________________________________________________________________________// - -bool -exception_safety_tester::decision_point( const_string file, std::size_t line_num ) -{ - activity_guard ag( m_internal_activity ); - - if( m_exec_path_point < m_execution_path.size() ) { - BOOST_REQUIRE_MESSAGE( m_execution_path[m_exec_path_point].m_type == EPP_DECISION && - m_execution_path[m_exec_path_point].m_file_name == file && - m_execution_path[m_exec_path_point].m_line_num == line_num, - "Function under test exibit non-deterministic behavior" ); - } - else { - m_execution_path.push_back( - execution_path_point( EPP_DECISION, file, line_num ) ); - - m_execution_path.back().m_decision.value = true; - m_execution_path.back().m_decision.forced_exception_point = m_forced_exception_point; - } - - return m_execution_path[m_exec_path_point++].m_decision.value; -} - -//____________________________________________________________________________// - -unsigned -exception_safety_tester::enter_scope( const_string file, std::size_t line_num, const_string scope_name ) -{ - activity_guard ag( m_internal_activity ); - - if( m_exec_path_point < m_execution_path.size() ) { - BOOST_REQUIRE_MESSAGE( m_execution_path[m_exec_path_point].m_type == EPP_SCOPE && - m_execution_path[m_exec_path_point].m_file_name == file && - m_execution_path[m_exec_path_point].m_line_num == line_num, - "Function under test exibit non-deterministic behavior" ); - } - else { - m_execution_path.push_back( - execution_path_point( EPP_SCOPE, file, line_num ) ); - } - - m_execution_path[m_exec_path_point].m_scope.size = 0; - m_execution_path[m_exec_path_point].m_scope.name = scope_name.begin(); - - return m_exec_path_point++; -} - -//____________________________________________________________________________// - -void -exception_safety_tester::leave_scope( unsigned enter_scope_point ) -{ - activity_guard ag( m_internal_activity ); - - BOOST_REQUIRE_MESSAGE( m_execution_path[enter_scope_point].m_type == EPP_SCOPE, - "Function under test exibit non-deterministic behavior" ); - - m_execution_path[enter_scope_point].m_scope.size = m_exec_path_point - enter_scope_point; -} - -//____________________________________________________________________________// - -void -exception_safety_tester::allocated( const_string file, std::size_t line_num, void* p, std::size_t s ) -{ - if( m_internal_activity ) - return; - - activity_guard ag( m_internal_activity ); - - if( m_exec_path_point < m_execution_path.size() ) - BOOST_REQUIRE_MESSAGE( m_execution_path[m_exec_path_point].m_type == EPP_ALLOC, - "Function under test exibit non-deterministic behavior" ); - else - m_execution_path.push_back( - execution_path_point( EPP_ALLOC, file, line_num ) ); - - m_execution_path[m_exec_path_point].m_alloc.ptr = p; - m_execution_path[m_exec_path_point].m_alloc.size = s; - - m_memory_in_use.insert( std::make_pair( p, m_exec_path_point++ ) ); -} - -//____________________________________________________________________________// - -void -exception_safety_tester::freed( void* p ) -{ - if( m_internal_activity ) - return; - - activity_guard ag( m_internal_activity ); - - registry::iterator it = m_memory_in_use.find( p ); - if( it != m_memory_in_use.end() ) { - m_execution_path[it->second].m_alloc.ptr = 0; - m_memory_in_use.erase( it ); - } -} - -//____________________________________________________________________________// - -void -exception_safety_tester::assertion_result( bool passed ) -{ - if( !m_internal_activity && !passed ) { - m_invairant_failed = true; - - failure_point(); - } -} - -//____________________________________________________________________________// - -void -exception_safety_tester::failure_point() -{ - if( m_exec_path_counter == m_break_exec_path ) - debug::debugger_break(); - - throw unique_exception(); -} - -//____________________________________________________________________________// - -namespace { - -inline void -format_location( wrap_stringstream& formatter, execution_path_point const& /*p*/, unsigned indent ) -{ - if( indent ) - formatter << std::left << std::setw( indent ) << ""; - -// !! ?? optional if( p.m_file_name ) -// formatter << p.m_file_name << '(' << p.m_line_num << "): "; -} - -//____________________________________________________________________________// - -template<typename ExecPathIt> -inline void -format_execution_path( wrap_stringstream& formatter, ExecPathIt it, ExecPathIt end, unsigned indent = 0 ) -{ - while( it != end ) { - switch( it->m_type ) { - case EPP_SCOPE: - format_location( formatter, *it, indent ); - formatter << "> \"" << it->m_scope.name << "\"\n"; - format_execution_path( formatter, it+1, it + it->m_scope.size, indent + 2 ); - format_location( formatter, *it, indent ); - formatter << "< \"" << it->m_scope.name << "\"\n"; - it += it->m_scope.size; - break; - - case EPP_DECISION: - format_location( formatter, *it, indent ); - formatter << "Decision made as " << std::boolalpha << it->m_decision.value << '\n'; - ++it; - break; - - case EPP_EXCEPT: - format_location( formatter, *it, indent ); - formatter << "Forced failure"; - if( it->m_except.description ) - formatter << ": " << it->m_except.description; - formatter << "\n"; - ++it; - break; - - case EPP_ALLOC: - if( it->m_alloc.ptr ) { - format_location( formatter, *it, indent ); - formatter << "Allocated memory block 0x" << std::uppercase << it->m_alloc.ptr - << ", " << it->m_alloc.size << " bytes long: <"; - - unsigned i; - for( i = 0; i < std::min<std::size_t>( it->m_alloc.size, 8 ); i++ ) { - unsigned char c = static_cast<unsigned char*>(it->m_alloc.ptr)[i]; - if( (std::isprint)( c ) ) - formatter << c; - else - formatter << '.'; - } - - formatter << "> "; - - for( i = 0; i < std::min<std::size_t>( it->m_alloc.size, 8 ); i++ ) { - unsigned c = static_cast<unsigned char*>(it->m_alloc.ptr)[i]; - formatter << std::hex << std::uppercase << c << ' '; - } - - formatter << "\n"; - } - ++it; - break; - } - } -} - -//____________________________________________________________________________// - -} // local namespace - -void -exception_safety_tester::report_error() -{ - activity_guard ag( m_internal_activity ); - - unit_test_log << unit_test::log::begin( m_execution_path.back().m_file_name, - m_execution_path.back().m_line_num ) - << log_all_errors; - - wrap_stringstream formatter; - - if( m_invairant_failed ) - formatter << "Failed invariant"; - - if( m_memory_in_use.size() != 0 ) { - if( m_invairant_failed ) - formatter << " and "; - - formatter << static_cast<unsigned int>(m_memory_in_use.size()) << " memory leak"; - if( m_memory_in_use.size() > 1 ) - formatter << 's'; - } - formatter << " detected in the execution path " << m_exec_path_counter << ":\n"; - - format_execution_path( formatter, m_execution_path.begin(), m_execution_path.end() ); - - unit_test_log << const_string( formatter.str() ) << unit_test::log::end(); -} - -//____________________________________________________________________________// - -// ************************************************************************** // -// ************** exception safety test ************** // -// ************************************************************************** // - -void BOOST_TEST_DECL -exception_safety( callback0<> const& F, const_string test_name ) -{ - exception_safety_tester est( test_name ); - - do { - try { - F(); - } - catch( exception_safety_tester::unique_exception const& ) {} - - } while( est.next_execution_path() ); -} - -//____________________________________________________________________________// - -} // namespace itest - -} // namespace boost - -//____________________________________________________________________________// - -#include <boost/test/detail/enable_warnings.hpp> - -#endif // non-ancient compiler - -#endif // BOOST_TEST_EXECUTION_SAFETY_IPP_112005GER diff --git a/boost/test/impl/execution_monitor.ipp b/boost/test/impl/execution_monitor.ipp index 07484b19d9..9929f74b53 100644 --- a/boost/test/impl/execution_monitor.ipp +++ b/boost/test/impl/execution_monitor.ipp @@ -1,4 +1,4 @@ -// (C) Copyright Gennadiy Rozental 2001-2008. +// (C) Copyright Gennadiy Rozental 2001-2014. // (C) Copyright Beman Dawes and Ullrich Koethe 1995-2001. // Use, modification, and distribution are subject to the // Boost Software License, Version 1.0. (See accompanying file @@ -27,14 +27,18 @@ // Boost.Test #include <boost/test/detail/config.hpp> #include <boost/test/detail/workaround.hpp> +#include <boost/test/detail/throw_exception.hpp> #include <boost/test/execution_monitor.hpp> #include <boost/test/debug.hpp> // Boost #include <boost/cstdlib.hpp> // for exit codes #include <boost/config.hpp> // for workarounds +#include <boost/core/ignore_unused.hpp> // for ignore_unused +#ifndef BOOST_NO_EXCEPTION #include <boost/exception/get_error_info.hpp> // for get_error_info #include <boost/exception/current_exception_cast.hpp> // for current_exception_cast +#endif // STL #include <string> // for std::string @@ -48,6 +52,8 @@ #include <cstdio> // for vsnprintf #include <cstdarg> // for varargs +#include <iostream> // for varargs + #ifdef BOOST_NO_STDC_NAMESPACE namespace std { using ::strerror; using ::strlen; using ::strncat; } #endif @@ -59,17 +65,12 @@ namespace std { using ::strerror; using ::strlen; using ::strncat; } using std::va_list; #endif -// to use vsnprintf -#if defined(__QNXNTO__) -# include <stdio.h> +// to use vsnprintf +#if defined(__QNXNTO__) +# include <stdio.h> #endif -#if defined(_WIN32) && !defined(BOOST_DISABLE_WIN32) && \ - (!defined(__COMO__) && !defined(__MWERKS__) && !defined(__GNUC__) || \ - BOOST_WORKAROUND(__MWERKS__, >= 0x3000)) - -# define BOOST_SEH_BASED_SIGNAL_HANDLING - +#ifdef BOOST_SEH_BASED_SIGNAL_HANDLING # include <windows.h> # if defined(__MWERKS__) || (defined(_MSC_VER) && !defined(UNDER_CE)) @@ -84,37 +85,12 @@ using std::va_list; typedef unsigned uintptr_t; # endif -# if BOOST_WORKAROUND(_MSC_VER, < 1300 ) || defined(UNDER_CE) -typedef void* uintptr_t; +# if defined(UNDER_CE) && BOOST_WORKAROUND(_MSC_VER, < 1500 ) + typedef void* uintptr_t; +# elif defined(UNDER_CE) +# include <crtdefs.h> # endif -// for the FP control routines -#include <float.h> - -#ifndef EM_INVALID -#define EM_INVALID _EM_INVALID -#endif - -#ifndef EM_DENORMAL -#define EM_DENORMAL _EM_DENORMAL -#endif - -#ifndef EM_ZERODIVIDE -#define EM_ZERODIVIDE _EM_ZERODIVIDE -#endif - -#ifndef EM_OVERFLOW -#define EM_OVERFLOW _EM_OVERFLOW -#endif - -#ifndef EM_UNDERFLOW -#define EM_UNDERFLOW _EM_UNDERFLOW -#endif - -#ifndef MCW_EM -#define MCW_EM _MCW_EM -#endif - # if !defined(NDEBUG) && defined(_MSC_VER) && !defined(UNDER_CE) # include <crtdbg.h> # define BOOST_TEST_CRT_HOOK_TYPE _CRT_REPORT_HOOK @@ -128,7 +104,8 @@ typedef void* uintptr_t; # define BOOST_TEST_CRT_SET_HOOK(H) (void*)(H) # endif -# if !BOOST_WORKAROUND(_MSC_VER, >= 1400 ) || defined(UNDER_CE) +# if (!BOOST_WORKAROUND(_MSC_VER, >= 1400 ) && \ + !defined(BOOST_COMO)) || defined(UNDER_CE) typedef void* _invalid_parameter_handler; @@ -154,7 +131,9 @@ namespace { void _set_se_translator( void* ) {} } # include <signal.h> # include <setjmp.h> -# if defined(__FreeBSD__) +# if defined(__FreeBSD__) + +# include <osreldate.h> # ifndef SIGPOLL # define SIGPOLL SIGIO @@ -168,13 +147,17 @@ namespace { void _set_se_translator( void* ) {} } # define ILL_COPROC ILL_FPOP_FAULT # define BOOST_TEST_LIMITED_SIGNAL_DETAILS -# define BOOST_TEST_IGNORE_SIGCHLD -# endif -# endif +# endif +# endif + +# if defined(__ANDROID__) +# include <android/api-level.h> +# endif -# if !defined(__CYGWIN__) && !defined(__QNXNTO__) -# define BOOST_TEST_USE_ALT_STACK +# if !defined(__CYGWIN__) && !defined(__QNXNTO__) && !defined(__bgq__) && \ + (!defined(__ANDROID__) || __ANDROID_API__ >= 8) +# define BOOST_TEST_USE_ALT_STACK # endif # if defined(SIGPOLL) && !defined(__CYGWIN__) && \ @@ -188,6 +171,7 @@ namespace { void _set_se_translator( void* ) {} } # define BOOST_TEST_ALT_STACK_SIZE SIGSTKSZ # endif + #else # define BOOST_NO_SIGNAL_HANDLING @@ -198,6 +182,10 @@ namespace { void _set_se_translator( void* ) {} } #include <errno.h> #endif +#if defined(__GNUC__) && !defined(BOOST_NO_TYPEID) +# include <cxxabi.h> +#endif + #include <boost/test/detail/suppress_warnings.hpp> //____________________________________________________________________________// @@ -205,6 +193,14 @@ namespace { void _set_se_translator( void* ) {} } namespace boost { // ************************************************************************** // +// ************** throw_exception ************** // +// ************************************************************************** // + +#ifdef BOOST_NO_EXCEPTION +void throw_exception( std::exception const & e ) { abort(); } +#endif + +// ************************************************************************** // // ************** report_error ************** // // ************************************************************************** // @@ -220,6 +216,8 @@ namespace detail { # define BOOST_TEST_VSNPRINTF( a1, a2, a3, a4 ) vsnprintf( (a1), (a2), (a3), (a4) ) #endif +#ifndef BOOST_NO_EXCEPTION + template <typename ErrorInfo> typename ErrorInfo::value_type extract( boost::exception const* ex ) @@ -237,39 +235,41 @@ extract( boost::exception const* ex ) static void report_error( execution_exception::error_code ec, boost::exception const* be, char const* format, va_list* args ) { - static const int REPORT_ERROR_BUFFER_SIZE = 512; + static const int REPORT_ERROR_BUFFER_SIZE = 4096; static char buf[REPORT_ERROR_BUFFER_SIZE]; - BOOST_TEST_VSNPRINTF( buf, sizeof(buf)-1, format, *args ); + BOOST_TEST_VSNPRINTF( buf, sizeof(buf)-1, format, *args ); buf[sizeof(buf)-1] = 0; va_end( *args ); - throw execution_exception( ec, buf, execution_exception::location( extract<throw_file>( be ), - extract<throw_line>( be ), + throw execution_exception( ec, buf, execution_exception::location( extract<throw_file>( be ), + (size_t)extract<throw_line>( be ), extract<throw_function>( be ) ) ); } //____________________________________________________________________________// static void -report_error( execution_exception::error_code ec, char const* format, ... ) +report_error( execution_exception::error_code ec, boost::exception const* be, char const* format, ... ) { va_list args; va_start( args, format ); - report_error( ec, 0, format, &args ); + report_error( ec, be, format, &args ); } +#endif + //____________________________________________________________________________// static void -report_error( execution_exception::error_code ec, boost::exception const* be, char const* format, ... ) +report_error( execution_exception::error_code ec, char const* format, ... ) { va_list args; va_start( args, format ); - report_error( ec, be, format, &args ); + report_error( ec, 0, format, &args ); } //____________________________________________________________________________// @@ -283,6 +283,47 @@ do_invoke( Tr const& tr, Functor const& F ) //____________________________________________________________________________// +struct fpe_except_guard { + explicit fpe_except_guard( unsigned detect_fpe ) + : m_detect_fpe( detect_fpe ) + { + // prepare fp exceptions control + m_previosly_enabled = fpe::disable( fpe::BOOST_FPE_ALL ); + if( m_previosly_enabled != fpe::BOOST_FPE_INV && detect_fpe != fpe::BOOST_FPE_OFF ) + fpe::enable( detect_fpe ); + } + ~fpe_except_guard() + { + if( m_detect_fpe != fpe::BOOST_FPE_OFF ) + fpe::disable( m_detect_fpe ); + if( m_previosly_enabled != fpe::BOOST_FPE_INV ) + fpe::enable( m_previosly_enabled ); + } + + unsigned m_detect_fpe; + unsigned m_previosly_enabled; +}; + +#ifndef BOOST_NO_TYPEID + +// ************************************************************************** // +// ************** typeid_name ************** // +// ************************************************************************** // + +template<typename T> +char const* +typeid_name( T const& t ) +{ +#ifdef __GNUC__ + int status; + + return abi::__cxa_demangle( typeid(t).name(), 0, 0, &status ); +#else + return typeid(t).name(); +#endif +} +#endif + } // namespace detail #if defined(BOOST_SIGACTION_BASED_SIGNAL_HANDLING) @@ -398,10 +439,10 @@ system_signal_exception::report() const "signal: co-processor error; address of failing instruction: 0x%08lx", m_sig_info->si_addr ); break; - default: - report_error( execution_exception::system_fatal_error, - "signal: SIGILL, si_code: %d (illegal instruction; address of failing instruction: 0x%08lx)", - m_sig_info->si_addr, m_sig_info->si_code ); + default: + report_error( execution_exception::system_fatal_error, + "signal: SIGILL, si_code: %d (illegal instruction; address of failing instruction: 0x%08lx)", + m_sig_info->si_addr, m_sig_info->si_code ); break; } break; @@ -505,48 +546,6 @@ system_signal_exception::report() const } break; - case SIGCHLD: - switch( m_sig_info->si_code ) { -#ifndef BOOST_TEST_LIMITED_SIGNAL_DETAILS - case CLD_EXITED: - report_error( execution_exception::system_error, - "child has exited; pid: %d; uid: %d; exit value: %d", - (int)m_sig_info->si_pid, (int)m_sig_info->si_uid, (int)m_sig_info->si_status ); - break; - case CLD_KILLED: - report_error( execution_exception::system_error, - "child was killed; pid: %d; uid: %d; exit value: %d", - (int)m_sig_info->si_pid, (int)m_sig_info->si_uid, (int)m_sig_info->si_status ); - break; - case CLD_DUMPED: - report_error( execution_exception::system_error, - "child terminated abnormally; pid: %d; uid: %d; exit value: %d", - (int)m_sig_info->si_pid, (int)m_sig_info->si_uid, (int)m_sig_info->si_status ); - break; - case CLD_TRAPPED: - report_error( execution_exception::system_error, - "traced child has trapped; pid: %d; uid: %d; exit value: %d", - (int)m_sig_info->si_pid, (int)m_sig_info->si_uid, (int)m_sig_info->si_status ); - break; - case CLD_STOPPED: - report_error( execution_exception::system_error, - "child has stopped; pid: %d; uid: %d; exit value: %d", - (int)m_sig_info->si_pid, (int)m_sig_info->si_uid, (int)m_sig_info->si_status ); - break; - case CLD_CONTINUED: - report_error( execution_exception::system_error, - "stopped child had continued; pid: %d; uid: %d; exit value: %d", - (int)m_sig_info->si_pid, (int)m_sig_info->si_uid, (int)m_sig_info->si_status ); - break; -#endif - default: - report_error( execution_exception::system_error, - "signal: SIGCHLD, si_code: %d (child process has terminated; pid: %d; uid: %d; exit value: %d)", - (int)m_sig_info->si_pid, (int)m_sig_info->si_uid, (int)m_sig_info->si_status, m_sig_info->si_code ); - break; - } - break; - #if defined(BOOST_TEST_CATCH_SIGPOLL) case SIGPOLL: @@ -585,11 +584,11 @@ system_signal_exception::report() const break; #endif #endif - default: - report_error( execution_exception::system_error, - "signal: SIGPOLL, si_code: %d (asynchronous I/O event occured; band event %d)", - (int)m_sig_info->si_band, m_sig_info->si_code ); - break; + default: + report_error( execution_exception::system_error, + "signal: SIGPOLL, si_code: %d (asynchronous I/O event occurred; band event %d)", + (int)m_sig_info->si_band, m_sig_info->si_code ); + break; } break; @@ -606,7 +605,8 @@ system_signal_exception::report() const break; default: - report_error( execution_exception::system_error, "unrecognized signal" ); + report_error( execution_exception::system_error, + "unrecognized signal %d", m_sig_info->si_signo ); } } @@ -618,8 +618,8 @@ system_signal_exception::report() const // Forward declaration extern "C" { -static void execution_monitor_jumping_signal_handler( int sig, siginfo_t* info, void* context ); -static void execution_monitor_attaching_signal_handler( int sig, siginfo_t* info, void* context ); +static void boost_execution_monitor_jumping_signal_handler( int sig, siginfo_t* info, void* context ); +static void boost_execution_monitor_attaching_signal_handler( int sig, siginfo_t* info, void* context ); } class signal_action { @@ -663,8 +663,8 @@ signal_action::signal_action( int sig, bool install, bool attach_dbg, char* alt_ } m_new_action.sa_flags |= SA_SIGINFO; - m_new_action.sa_sigaction = attach_dbg ? &execution_monitor_attaching_signal_handler - : &execution_monitor_jumping_signal_handler; + m_new_action.sa_sigaction = attach_dbg ? &boost_execution_monitor_attaching_signal_handler + : &boost_execution_monitor_jumping_signal_handler; BOOST_TEST_SYS_ASSERT( sigemptyset( &m_new_action.sa_mask ) != -1 ); #ifdef BOOST_TEST_USE_ALT_STACK @@ -692,7 +692,7 @@ signal_action::~signal_action() class signal_handler { public: // Constructor - explicit signal_handler( bool catch_system_errors, int timeout, bool attach_dbg, char* alt_stack ); + explicit signal_handler( bool catch_system_errors, bool detect_fpe, unsigned timeout, bool attach_dbg, char* alt_stack ); // Destructor ~signal_handler(); @@ -715,8 +715,9 @@ public: private: // Data members signal_handler* m_prev_handler; - int m_timeout; + unsigned m_timeout; + // Note: We intentionality do not catch SIGCHLD. Users have to deal with it themselves signal_action m_ILL_action; signal_action m_FPE_action; signal_action m_SEGV_action; @@ -738,16 +739,13 @@ signal_handler* signal_handler::s_active_handler = signal_handler_ptr(); //____________________________________________________________________________// -signal_handler::signal_handler( bool catch_system_errors, int timeout, bool attach_dbg, char* alt_stack ) +signal_handler::signal_handler( bool catch_system_errors, bool detect_fpe, unsigned timeout, bool attach_dbg, char* alt_stack ) : m_prev_handler( s_active_handler ) , m_timeout( timeout ) , m_ILL_action ( SIGILL , catch_system_errors, attach_dbg, alt_stack ) -, m_FPE_action ( SIGFPE , catch_system_errors, attach_dbg, alt_stack ) +, m_FPE_action ( SIGFPE , detect_fpe , attach_dbg, alt_stack ) , m_SEGV_action( SIGSEGV, catch_system_errors, attach_dbg, alt_stack ) , m_BUS_action ( SIGBUS , catch_system_errors, attach_dbg, alt_stack ) -#ifndef BOOST_TEST_IGNORE_SIGCHLD -, m_CHLD_action( SIGCHLD, catch_system_errors, attach_dbg, alt_stack ) -#endif #ifdef BOOST_TEST_CATCH_SIGPOLL , m_POLL_action( SIGPOLL, catch_system_errors, attach_dbg, alt_stack ) #endif @@ -799,7 +797,12 @@ signal_handler::~signal_handler() sigstk.ss_size = MINSIGSTKSZ; sigstk.ss_flags = SS_DISABLE; - BOOST_TEST_SYS_ASSERT( ::sigaltstack( &sigstk, 0 ) != -1 ); + if( ::sigaltstack( &sigstk, 0 ) == -1 ) { + int error_n = errno; + std::cerr << "******** errors disabling the alternate stack:" << std::endl + << "\t#error:" << error_n << std::endl + << "\t" << std::strerror( error_n ) << std::endl; + } #endif s_active_handler = m_prev_handler; @@ -813,26 +816,8 @@ signal_handler::~signal_handler() extern "C" { -static bool ignore_sigchild( siginfo_t* info ) -{ - return info->si_signo == SIGCHLD -#ifndef BOOST_TEST_LIMITED_SIGNAL_DETAILS - && info->si_code == CLD_EXITED -#endif -#ifdef BOOST_TEST_IGNORE_NON_ZERO_CHILD_CODE - ; -#else - && (int)info->si_status == 0; -#endif -} - -//____________________________________________________________________________// - -static void execution_monitor_jumping_signal_handler( int sig, siginfo_t* info, void* context ) +static void boost_execution_monitor_jumping_signal_handler( int sig, siginfo_t* info, void* context ) { - if( ignore_sigchild( info ) ) - return; - signal_handler::sys_sig()( info, context ); siglongjmp( signal_handler::jump_buffer(), sig ); @@ -840,13 +825,10 @@ static void execution_monitor_jumping_signal_handler( int sig, siginfo_t* info, //____________________________________________________________________________// -static void execution_monitor_attaching_signal_handler( int sig, siginfo_t* info, void* context ) +static void boost_execution_monitor_attaching_signal_handler( int sig, siginfo_t* info, void* context ) { - if( ignore_sigchild( info ) ) - return; - if( !debug::attach_debugger( false ) ) - execution_monitor_jumping_signal_handler( sig, info, context ); + boost_execution_monitor_jumping_signal_handler( sig, info, context ); // debugger attached; it will handle the signal BOOST_TEST_SYS_ASSERT( ::signal( sig, SIG_DFL ) != SIG_ERR ); @@ -863,7 +845,7 @@ static void execution_monitor_attaching_signal_handler( int sig, siginfo_t* info // ************************************************************************** // int -execution_monitor::catch_signals( unit_test::callback0<int> const& F ) +execution_monitor::catch_signals( boost::function<int ()> const& F ) { using namespace detail; @@ -878,13 +860,16 @@ execution_monitor::catch_signals( unit_test::callback0<int> const& F ) p_use_alt_stack.value = false; #endif - signal_handler local_signal_handler( p_catch_system_errors, p_timeout, p_auto_start_dbg, + signal_handler local_signal_handler( p_catch_system_errors, + p_catch_system_errors || (p_detect_fp_exceptions != fpe::BOOST_FPE_OFF), + p_timeout, + p_auto_start_dbg, !p_use_alt_stack ? 0 : m_alt_stack.get() ); if( !sigsetjmp( signal_handler::jump_buffer(), 1 ) ) return detail::do_invoke( m_custom_translators , F ); else - throw local_signal_handler.sys_sig(); + return BOOST_TEST_IMPL_THROW( local_signal_handler.sys_sig() ); } //____________________________________________________________________________// @@ -916,37 +901,64 @@ public: {} void report() const; - int operator()( unsigned int id, _EXCEPTION_POINTERS* exps ); + int operator()( unsigned id, _EXCEPTION_POINTERS* exps ); private: // Data members execution_monitor* m_em; - unsigned int m_se_id; + unsigned m_se_id; void* m_fault_address; bool m_dir; }; +//____________________________________________________________________________// + +#if BOOST_WORKAROUND( BOOST_MSVC, <= 1310) static void -seh_catch_preventer( unsigned int /* id */, _EXCEPTION_POINTERS* /* exps */ ) +seh_catch_preventer( unsigned /* id */, _EXCEPTION_POINTERS* /* exps */ ) { throw; } +#endif //____________________________________________________________________________// int -system_signal_exception::operator()( unsigned int id, _EXCEPTION_POINTERS* exps ) +system_signal_exception::operator()( unsigned id, _EXCEPTION_POINTERS* exps ) { - const unsigned int MSFT_CPP_EXCEPT = 0xE06d7363; // EMSC + const unsigned MSFT_CPP_EXCEPT = 0xE06d7363; // EMSC - if( !m_em->p_catch_system_errors || (id == MSFT_CPP_EXCEPT) ) + // C++ exception - allow to go through + if( id == MSFT_CPP_EXCEPT ) return EXCEPTION_CONTINUE_SEARCH; + // FPE detection is enabled, while system exception detection is not - check if this is actually FPE + if( !m_em->p_catch_system_errors ) { + if( !m_em->p_detect_fp_exceptions ) + return EXCEPTION_CONTINUE_SEARCH; + + switch( id ) { + case EXCEPTION_FLT_DIVIDE_BY_ZERO: + case EXCEPTION_FLT_STACK_CHECK: + case EXCEPTION_FLT_DENORMAL_OPERAND: + case EXCEPTION_FLT_INEXACT_RESULT: + case EXCEPTION_FLT_OVERFLOW: + case EXCEPTION_FLT_UNDERFLOW: + case EXCEPTION_FLT_INVALID_OPERATION: + case STATUS_FLOAT_MULTIPLE_FAULTS: + case STATUS_FLOAT_MULTIPLE_TRAPS: + break; + default: + return EXCEPTION_CONTINUE_SEARCH; + } + } + if( !!m_em->p_auto_start_dbg && debug::attach_debugger( false ) ) { m_em->p_catch_system_errors.value = false; +#if BOOST_WORKAROUND( BOOST_MSVC, <= 1310) _set_se_translator( &seh_catch_preventer ); - +#endif return EXCEPTION_CONTINUE_EXECUTION; } @@ -1031,12 +1043,10 @@ system_signal_exception::report() const "operand of floating point operation is denormal" ); break; -# if 0 // !! ?? case EXCEPTION_FLT_INEXACT_RESULT: detail::report_error( execution_exception::system_error, "result of a floating-point operation cannot be represented exactly" ); break; -#endif case EXCEPTION_FLT_OVERFLOW: detail::report_error( execution_exception::system_error, @@ -1052,6 +1062,14 @@ system_signal_exception::report() const detail::report_error( execution_exception::system_error, "floating point error" ); break; + case STATUS_FLOAT_MULTIPLE_FAULTS: + detail::report_error( execution_exception::system_error, "multiple floating point errors" ); + break; + + case STATUS_FLOAT_MULTIPLE_TRAPS: + detail::report_error( execution_exception::system_error, "multiple floating point errors" ); + break; + case EXCEPTION_BREAKPOINT: detail::report_error( execution_exception::system_error, "breakpoint encountered" ); break; @@ -1071,59 +1089,28 @@ system_signal_exception::report() const int BOOST_TEST_CALL_DECL assert_reporting_function( int reportType, char* userMessage, int* ) { - switch( reportType ) { - case BOOST_TEST_CRT_ASSERT: - detail::report_error( execution_exception::user_error, userMessage ); + // write this way instead of switch to avoid unreachable statements + if( reportType == BOOST_TEST_CRT_ASSERT || reportType == BOOST_TEST_CRT_ERROR ) + detail::report_error( reportType == BOOST_TEST_CRT_ASSERT ? execution_exception::user_error : execution_exception::system_error, userMessage ); - return 1; // return value and retVal are not important since we never reach this line - case BOOST_TEST_CRT_ERROR: - detail::report_error( execution_exception::system_error, userMessage ); - - return 1; // return value and retVal are not important since we never reach this line - default: - return 0; // use usual reporting method - } + return 0; } // assert_reporting_function //____________________________________________________________________________// void BOOST_TEST_CALL_DECL -invalid_param_handler( wchar_t const* /* expr */, - wchar_t const* /* func */, - wchar_t const* /* file */, - unsigned int /* line */, +invalid_param_handler( wchar_t const* /* expr */, + wchar_t const* /* func */, + wchar_t const* /* file */, + unsigned /* line */, uintptr_t /* reserved */) { - detail::report_error( execution_exception::user_error, + detail::report_error( execution_exception::user_error, "Invalid parameter detected by C runtime library" ); } //____________________________________________________________________________// -void BOOST_TEST_CALL_DECL -switch_fp_exceptions( bool on_off ) -{ - if( !on_off ) - _clearfp(); - - int cw = ::_controlfp( 0, 0 ); - - int exceptions_mask = EM_INVALID|EM_DENORMAL|EM_ZERODIVIDE|EM_OVERFLOW|EM_UNDERFLOW; - - if( on_off ) - cw &= ~exceptions_mask; // Set the exception masks on, turn exceptions off - else - cw |= exceptions_mask; // Set the exception masks off, turn exceptions on - - if( on_off ) - _clearfp(); - - // Set the control word - ::_controlfp( cw, MCW_EM ); -} - -//____________________________________________________________________________// - } // namespace detail // ************************************************************************** // @@ -1131,25 +1118,24 @@ switch_fp_exceptions( bool on_off ) // ************************************************************************** // int -execution_monitor::catch_signals( unit_test::callback0<int> const& F ) +execution_monitor::catch_signals( boost::function<int ()> const& F ) { _invalid_parameter_handler old_iph = _invalid_parameter_handler(); BOOST_TEST_CRT_HOOK_TYPE old_crt_hook = 0; - if( !p_catch_system_errors ) - _set_se_translator( &detail::seh_catch_preventer ); - else { - if( !!p_detect_fp_exceptions ) - detail::switch_fp_exceptions( true ); - - old_crt_hook = BOOST_TEST_CRT_SET_HOOK( &detail::assert_reporting_function ); + if( p_catch_system_errors ) { + old_crt_hook = BOOST_TEST_CRT_SET_HOOK( &detail::assert_reporting_function ); - old_iph = _set_invalid_parameter_handler( - reinterpret_cast<_invalid_parameter_handler>( &detail::invalid_param_handler ) ); + old_iph = _set_invalid_parameter_handler( + reinterpret_cast<_invalid_parameter_handler>( &detail::invalid_param_handler ) ); + } else if( !p_detect_fp_exceptions ) { +#if BOOST_WORKAROUND( BOOST_MSVC, <= 1310) + _set_se_translator( &detail::seh_catch_preventer ); +#endif } detail::system_signal_exception SSE( this ); - + int ret_val = 0; __try { @@ -1161,10 +1147,7 @@ execution_monitor::catch_signals( unit_test::callback0<int> const& F ) } } __finally { - if( !!p_catch_system_errors ) { - if( !!p_detect_fp_exceptions ) - detail::switch_fp_exceptions( false ); - + if( p_catch_system_errors ) { BOOST_TEST_CRT_SET_HOOK( old_crt_hook ); _set_invalid_parameter_handler( old_iph ); @@ -1188,7 +1171,7 @@ public: } // namespace detail int -execution_monitor::catch_signals( unit_test::callback0<int> const& F ) +execution_monitor::catch_signals( boost::function<int ()> const& F ) { return detail::do_invoke( m_custom_translators , F ); } @@ -1198,19 +1181,34 @@ execution_monitor::catch_signals( unit_test::callback0<int> const& F ) #endif // choose signal handler // ************************************************************************** // -// ************** execution_monitor::execute ************** // +// ************** execution_monitor ************** // // ************************************************************************** // +execution_monitor::execution_monitor() +: p_catch_system_errors( true ) +, p_auto_start_dbg( false ) +, p_timeout( 0 ) +, p_use_alt_stack( true ) +, p_detect_fp_exceptions( fpe::BOOST_FPE_OFF ) +{} + +//____________________________________________________________________________// + int -execution_monitor::execute( unit_test::callback0<int> const& F ) +execution_monitor::execute( boost::function<int ()> const& F ) { if( debug::under_debugger() ) p_catch_system_errors.value = false; - try { + BOOST_TEST_IMPL_TRY { + detail::fpe_except_guard G( p_detect_fp_exceptions ); + unit_test::ut_detail::ignore_unused_variable_warning( G ); + return catch_signals( F ); } +#ifndef BOOST_NO_EXCEPTION + // Catch-clause reference arguments are a bit different from function // arguments (ISO 15.3 paragraphs 18 & 19). Apparently const isn't // required. Programmers ask for const anyhow, so we supply it. That's @@ -1220,89 +1218,61 @@ execution_monitor::execute( unit_test::callback0<int> const& F ) { detail::report_error( execution_exception::cpp_exception_error, "C string: %s", ex ); } catch( std::string const& ex ) - { detail::report_error( execution_exception::cpp_exception_error, + { detail::report_error( execution_exception::cpp_exception_error, "std::string: %s", ex.c_str() ); } // std:: exceptions +#ifdef BOOST_NO_TYPEID +#define CATCH_AND_REPORT_STD_EXCEPTION( ex_name ) \ + catch( ex_name const& ex ) \ + { detail::report_error( execution_exception::cpp_exception_error, \ + current_exception_cast<boost::exception const>(), \ + #ex_name ": %s", ex.what() ); } \ +/**/ +#else +#define CATCH_AND_REPORT_STD_EXCEPTION( ex_name ) \ + catch( ex_name const& ex ) \ + { detail::report_error( execution_exception::cpp_exception_error, \ + current_exception_cast<boost::exception const>(), \ + "%s: %s", detail::typeid_name(ex), ex.what() ); } \ +/**/ +#endif - catch( std::bad_alloc const& ex ) - { detail::report_error( execution_exception::cpp_exception_error, - current_exception_cast<boost::exception const>(), - "std::bad_alloc: %s", ex.what() ); } + CATCH_AND_REPORT_STD_EXCEPTION( std::bad_alloc ) #if BOOST_WORKAROUND(__BORLANDC__, <= 0x0551) - catch( std::bad_cast const& ex ) - { detail::report_error( execution_exception::cpp_exception_error, - current_exception_cast<boost::exception const>(), - "std::bad_cast" ); } - catch( std::bad_typeid const& ex ) - { detail::report_error( execution_exception::cpp_exception_error, - current_exception_cast<boost::exception const>(), - "std::bad_typeid" ); } + CATCH_AND_REPORT_STD_EXCEPTION( std::bad_cast ) + CATCH_AND_REPORT_STD_EXCEPTION( std::bad_typeid ) #else - catch( std::bad_cast const& ex ) - { detail::report_error( execution_exception::cpp_exception_error, - current_exception_cast<boost::exception const>(), - "std::bad_cast: %s", ex.what() ); } - catch( std::bad_typeid const& ex ) - { detail::report_error( execution_exception::cpp_exception_error, - current_exception_cast<boost::exception const>(), - "std::bad_typeid: %s", ex.what() ); } + CATCH_AND_REPORT_STD_EXCEPTION( std::bad_cast ) + CATCH_AND_REPORT_STD_EXCEPTION( std::bad_typeid ) #endif - catch( std::bad_exception const& ex ) - { detail::report_error( execution_exception::cpp_exception_error, - current_exception_cast<boost::exception const>(), - "std::bad_exception: %s", ex.what() ); } - catch( std::domain_error const& ex ) - { detail::report_error( execution_exception::cpp_exception_error, - current_exception_cast<boost::exception const>(), - "std::domain_error: %s", ex.what() ); } - catch( std::invalid_argument const& ex ) - { detail::report_error( execution_exception::cpp_exception_error, - current_exception_cast<boost::exception const>(), - "std::invalid_argument: %s", ex.what() ); } - catch( std::length_error const& ex ) - { detail::report_error( execution_exception::cpp_exception_error, - current_exception_cast<boost::exception const>(), - "std::length_error: %s", ex.what() ); } - catch( std::out_of_range const& ex ) - { detail::report_error( execution_exception::cpp_exception_error, - current_exception_cast<boost::exception const>(), - "std::out_of_range: %s", ex.what() ); } - catch( std::range_error const& ex ) - { detail::report_error( execution_exception::cpp_exception_error, - current_exception_cast<boost::exception const>(), - "std::range_error: %s", ex.what() ); } - catch( std::overflow_error const& ex ) - { detail::report_error( execution_exception::cpp_exception_error, - current_exception_cast<boost::exception const>(), - "std::overflow_error: %s", ex.what() ); } - catch( std::underflow_error const& ex ) - { detail::report_error( execution_exception::cpp_exception_error, - current_exception_cast<boost::exception const>(), - "std::underflow_error: %s", ex.what() ); } - catch( std::logic_error const& ex ) - { detail::report_error( execution_exception::cpp_exception_error, - current_exception_cast<boost::exception const>(), - "std::logic_error: %s", ex.what() ); } - catch( std::runtime_error const& ex ) - { detail::report_error( execution_exception::cpp_exception_error, - current_exception_cast<boost::exception const>(), - "std::runtime_error: %s", ex.what() ); } - catch( std::exception const& ex ) - { detail::report_error( execution_exception::cpp_exception_error, - current_exception_cast<boost::exception const>(), - "std::exception: %s", ex.what() ); } + CATCH_AND_REPORT_STD_EXCEPTION( std::bad_exception ) + CATCH_AND_REPORT_STD_EXCEPTION( std::domain_error ) + CATCH_AND_REPORT_STD_EXCEPTION( std::invalid_argument ) + CATCH_AND_REPORT_STD_EXCEPTION( std::length_error ) + CATCH_AND_REPORT_STD_EXCEPTION( std::out_of_range ) + CATCH_AND_REPORT_STD_EXCEPTION( std::range_error ) + CATCH_AND_REPORT_STD_EXCEPTION( std::overflow_error ) + CATCH_AND_REPORT_STD_EXCEPTION( std::underflow_error ) + CATCH_AND_REPORT_STD_EXCEPTION( std::logic_error ) + CATCH_AND_REPORT_STD_EXCEPTION( std::runtime_error ) + CATCH_AND_REPORT_STD_EXCEPTION( std::exception ) +#undef CATCH_AND_REPORT_STD_EXCEPTION catch( boost::exception const& ex ) - { detail::report_error( execution_exception::cpp_exception_error, - &ex, - "unknown boost::exception" ); } + { detail::report_error( execution_exception::cpp_exception_error, + &ex, +#ifdef BOOST_NO_TYPEID + "unknown boost::exception" ); } +#else + typeid(ex).name() ); } +#endif // system errors catch( system_error const& ex ) - { detail::report_error( execution_exception::cpp_exception_error, + { detail::report_error( execution_exception::cpp_exception_error, "system_error produced by: %s: %s", ex.p_failed_exp.get(), std::strerror( ex.p_errno ) ); } catch( detail::system_signal_exception const& ex ) { ex.report(); } @@ -1319,11 +1289,30 @@ execution_monitor::execute( unit_test::callback0<int> const& F ) catch( ... ) { detail::report_error( execution_exception::cpp_exception_error, "unknown type" ); } +#endif // !BOOST_NO_EXCEPTION + return 0; // never reached; supplied to quiet compiler warnings } // execute //____________________________________________________________________________// +namespace detail { + +struct forward { + explicit forward( boost::function<void ()> const& F ) : m_F( F ) {} + + int operator()() { m_F(); return 0; } + + boost::function<void ()> const& m_F; +}; + +} // namespace detail +void +execution_monitor::vexecute( boost::function<void ()> const& F ) +{ + execute( detail::forward( F ) ); +} + // ************************************************************************** // // ************** system_error ************** // // ************************************************************************** // @@ -1359,6 +1348,88 @@ execution_exception::location::location( char const* file_name, size_t line_num, //____________________________________________________________________________// +// ************************************************************************** // +// **************Floating point exception management interface ************** // +// ************************************************************************** // + +namespace fpe { + +unsigned +enable( unsigned mask ) +{ + boost::ignore_unused(mask); + +#if defined(UNDER_CE) + /* Not Implemented in Windows CE */ + return 0; +#elif defined(BOOST_SEH_BASED_SIGNAL_HANDLING) + _clearfp(); + +#if BOOST_WORKAROUND( BOOST_MSVC, <= 1310) + unsigned old_cw = ::_controlfp( 0, 0 ); + ::_controlfp( old_cw & ~mask, BOOST_FPE_ALL ); +#else + unsigned old_cw; + if( ::_controlfp_s( &old_cw, 0, 0 ) != 0 ) + return BOOST_FPE_INV; + + // Set the control word + if( ::_controlfp_s( 0, old_cw & ~mask, BOOST_FPE_ALL ) != 0 ) + return BOOST_FPE_INV; +#endif + + return ~old_cw & BOOST_FPE_ALL; +#elif defined(__GLIBC__) && defined(__USE_GNU) && !defined(BOOST_CLANG) && !defined(BOOST_NO_FENV_H) + ::feclearexcept(BOOST_FPE_ALL); + int res = ::feenableexcept( mask ); + return res == -1 ? (unsigned)BOOST_FPE_INV : (unsigned)res; +#else + /* Not Implemented */ + return 0; +#endif +} + +//____________________________________________________________________________// + +unsigned +disable( unsigned mask ) +{ + boost::ignore_unused(mask); + +#if defined(UNDER_CE) + /* Not Implemented in Windows CE */ + return 0; +#elif defined(BOOST_SEH_BASED_SIGNAL_HANDLING) + _clearfp(); + +#if BOOST_WORKAROUND( BOOST_MSVC, <= 1310) + unsigned old_cw = ::_controlfp( 0, 0 ); + ::_controlfp( old_cw | mask, BOOST_FPE_ALL ); +#else + unsigned old_cw; + if( ::_controlfp_s( &old_cw, 0, 0 ) != 0 ) + return BOOST_FPE_INV; + + // Set the control word + if( ::_controlfp_s( 0, old_cw | mask, BOOST_FPE_ALL ) != 0 ) + return BOOST_FPE_INV; +#endif + + return ~old_cw & BOOST_FPE_ALL; +#elif defined(__GLIBC__) && defined(__USE_GNU) && !defined(BOOST_CLANG) && !defined(BOOST_NO_FENV_H) + ::feclearexcept(BOOST_FPE_ALL); + int res = ::fedisableexcept( mask ); + return res == -1 ? (unsigned)BOOST_FPE_INV : (unsigned)res; +#else + /* Not Implemented */ + return BOOST_FPE_INV; +#endif +} + +//____________________________________________________________________________// + +} // namespace fpe + } // namespace boost #include <boost/test/detail/enable_warnings.hpp> diff --git a/boost/test/impl/framework.ipp b/boost/test/impl/framework.ipp index a1e98b3771..a69d95cd2d 100644 --- a/boost/test/impl/framework.ipp +++ b/boost/test/impl/framework.ipp @@ -1,4 +1,4 @@ -// (C) Copyright Gennadiy Rozental 2005-2008. +// (C) Copyright Gennadiy Rozental 2005-2014. // 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) @@ -19,24 +19,36 @@ #include <boost/test/framework.hpp> #include <boost/test/execution_monitor.hpp> #include <boost/test/debug.hpp> -#include <boost/test/unit_test_suite_impl.hpp> +#include <boost/test/unit_test_parameters.hpp> + #include <boost/test/unit_test_log.hpp> #include <boost/test/unit_test_monitor.hpp> -#include <boost/test/test_observer.hpp> #include <boost/test/results_collector.hpp> #include <boost/test/progress_monitor.hpp> #include <boost/test/results_reporter.hpp> -#include <boost/test/test_tools.hpp> -#include <boost/test/detail/unit_test_parameters.hpp> -#include <boost/test/detail/global_typedef.hpp> +#include <boost/test/tree/observer.hpp> +#include <boost/test/tree/test_unit.hpp> +#include <boost/test/tree/visitor.hpp> +#include <boost/test/tree/traverse.hpp> +#include <boost/test/tree/test_case_counter.hpp> + +#if BOOST_TEST_SUPPORT_TOKEN_ITERATOR +#include <boost/test/utils/iterator/token_iterator.hpp> +#endif #include <boost/test/utils/foreach.hpp> +#include <boost/test/utils/basic_cstring/io.hpp> + +#include <boost/test/detail/global_typedef.hpp> +#include <boost/test/detail/throw_exception.hpp> // Boost #include <boost/timer.hpp> +#include <boost/bind.hpp> // STL +#include <limits> #include <map> #include <set> #include <cstdlib> @@ -51,148 +63,672 @@ namespace std { using ::time; using ::srand; } //____________________________________________________________________________// namespace boost { - namespace unit_test { +namespace framework { +namespace impl { // ************************************************************************** // -// ************** test_start calls wrapper ************** // +// ************** order detection helpers ************** // // ************************************************************************** // -namespace ut_detail { +struct order_info { + order_info() : depth(-1) {} -struct test_start_caller { - test_start_caller( test_observer* to, counter_t tc_amount ) - : m_to( to ) - , m_tc_amount( tc_amount ) - {} + int depth; + std::vector<test_unit_id> dependant_siblings; +}; - int operator()() - { - m_to->test_start( m_tc_amount ); +typedef std::set<test_unit_id> tu_id_set; +typedef std::map<test_unit_id,order_info> order_info_per_tu; // !! ?? unordered map + +//____________________________________________________________________________// + +static test_unit_id +get_tu_parent( test_unit_id tu_id ) +{ + return framework::get( tu_id, TUT_ANY ).p_parent_id; +} + +//____________________________________________________________________________// + +static int +tu_depth( test_unit_id tu_id, test_unit_id master_tu_id, order_info_per_tu& tuoi ) +{ + if( tu_id == master_tu_id ) return 0; + + order_info& info = tuoi[tu_id]; + + if( info.depth == -1 ) + info.depth = tu_depth( get_tu_parent( tu_id ), master_tu_id, tuoi ) + 1; + + return info.depth; +} + +//____________________________________________________________________________// + +static void +collect_dependant_siblings( test_unit_id from, test_unit_id to, test_unit_id master_tu_id, order_info_per_tu& tuoi ) +{ + int from_depth = tu_depth( from, master_tu_id, tuoi ); + int to_depth = tu_depth( to, master_tu_id, tuoi ); + + while(from_depth > to_depth) { + from = get_tu_parent( from ); + --from_depth; + } + + while(from_depth < to_depth) { + to = get_tu_parent( to ); + --to_depth; + } + + while(true) { + test_unit_id from_parent = get_tu_parent( from ); + test_unit_id to_parent = get_tu_parent( to ); + if( from_parent == to_parent ) + break; + from = from_parent; + to = to_parent; + } + + tuoi[from].dependant_siblings.push_back( to ); +} + +//____________________________________________________________________________// + +static counter_t +assign_sibling_rank( test_unit_id tu_id, order_info_per_tu& tuoi ) +{ + test_unit& tu = framework::get( tu_id, TUT_ANY ); + + BOOST_TEST_SETUP_ASSERT( tu.p_sibling_rank != (std::numeric_limits<counter_t>::max)(), + "Cyclic dependency detected involving test unit \"" + tu.full_name() + "\"" ); + + if( tu.p_sibling_rank != 0 ) + return tu.p_sibling_rank; + + order_info const& info = tuoi[tu_id]; + + // indicate in progress + tu.p_sibling_rank.value = (std::numeric_limits<counter_t>::max)(); + + counter_t new_rank = 1; + BOOST_TEST_FOREACH( test_unit_id, sibling_id, info.dependant_siblings ) + new_rank = (std::max)(new_rank, assign_sibling_rank( sibling_id, tuoi ) + 1); + + return tu.p_sibling_rank.value = new_rank; +} + +//____________________________________________________________________________// + +// ************************************************************************** // +// ************** test_init call wrapper ************** // +// ************************************************************************** // + +static void +invoke_init_func( init_unit_test_func init_func ) +{ +#ifdef BOOST_TEST_ALTERNATIVE_INIT_API + if( !(*init_func)() ) + BOOST_TEST_IMPL_THROW( std::runtime_error( "test module initialization failed" ) ); +#else + test_suite* manual_test_units = (*init_func)( framework::master_test_suite().argc, framework::master_test_suite().argv ); + + if( manual_test_units ) + framework::master_test_suite().add( manual_test_units ); +#endif +} + +// ************************************************************************** // +// ************** name_filter ************** // +// ************************************************************************** // + +class name_filter : public test_tree_visitor { + struct component { + component( const_string name ) // has to be implicit + { + if( name == "*" ) + m_kind = SFK_ALL; + else if( first_char( name ) == '*' && last_char( name ) == '*' ) { + m_kind = SFK_SUBSTR; + m_name = name.substr( 1, name.size()-1 ); + } + else if( first_char( name ) == '*' ) { + m_kind = SFK_TRAILING; + m_name = name.substr( 1 ); + } + else if( last_char( name ) == '*' ) { + m_kind = SFK_LEADING; + m_name = name.substr( 0, name.size()-1 ); + } + else { + m_kind = SFK_MATCH; + m_name = name; + } + } + + bool pass( test_unit const& tu ) const + { + const_string name( tu.p_name ); + + switch( m_kind ) { + default: + case SFK_ALL: + return true; + case SFK_LEADING: + return name.substr( 0, m_name.size() ) == m_name; + case SFK_TRAILING: + return name.size() >= m_name.size() && name.substr( name.size() - m_name.size() ) == m_name; + case SFK_SUBSTR: + return name.find( m_name ) != const_string::npos; + case SFK_MATCH: + return m_name == tu.p_name.get(); + } + } + enum kind { SFK_ALL, SFK_LEADING, SFK_TRAILING, SFK_SUBSTR, SFK_MATCH }; + + kind m_kind; + const_string m_name; + }; + +public: + // Constructor + name_filter( test_unit_id_list& targ_list, const_string filter_expr ) : m_targ_list( targ_list ), m_depth( 0 ) + { +#ifdef BOOST_TEST_SUPPORT_TOKEN_ITERATOR + string_token_iterator tit( filter_expr, (dropped_delimeters = "/", kept_delimeters = dt_none) ); + + while( tit != string_token_iterator() ) { + m_components.push_back( std::vector<component>( string_token_iterator( *tit, (dropped_delimeters = ",", kept_delimeters = dt_none) ), + string_token_iterator() ) ); + + ++tit; + } +#endif } private: + bool filter_unit( test_unit const& tu ) + { + // skip master test suite + if( m_depth == 0 ) + return true; + + // corresponding name filters are at level m_depth-1 + std::vector<component> const& filters = m_components[m_depth-1]; + + // look for match + return std::find_if( filters.begin(), filters.end(), bind( &component::pass, _1, boost::ref(tu) ) ) != filters.end(); + } + + // test_tree_visitor interface + virtual void visit( test_case const& tc ) + { + // make sure we only accept test cases if we match last component of the filter + if( m_depth == m_components.size() && filter_unit( tc ) ) + m_targ_list.push_back( tc.p_id ); // found a test case + } + virtual bool test_suite_start( test_suite const& ts ) + { + if( !filter_unit( ts ) ) + return false; + + if( m_depth < m_components.size() ) { + ++m_depth; + return true; + } + + m_targ_list.push_back( ts.p_id ); // found a test suite + + return false; + } + virtual void test_suite_finish( test_suite const& /*ts*/ ) + { + --m_depth; + } + // Data members - test_observer* m_to; - counter_t m_tc_amount; + typedef std::vector<std::vector<component> > components_per_level; + + components_per_level m_components; + test_unit_id_list& m_targ_list; + unsigned m_depth; }; -//____________________________________________________________________________// +// ************************************************************************** // +// ************** label_filter ************** // +// ************************************************************************** // -struct test_init_caller { - explicit test_init_caller( init_unit_test_func init_func ) - : m_init_func( init_func ) +class label_filter : public test_tree_visitor { +public: + label_filter( test_unit_id_list& targ_list, const_string label ) + : m_targ_list( targ_list ) + , m_label( label ) {} - int operator()() + +private: + // test_tree_visitor interface + virtual bool visit( test_unit const& tu ) { -#ifdef BOOST_TEST_ALTERNATIVE_INIT_API - if( !(*m_init_func)() ) - throw std::runtime_error( "test module initialization failed" ); -#else - test_suite* manual_test_units = (*m_init_func)( framework::master_test_suite().argc, framework::master_test_suite().argv ); + if( tu.has_label( m_label ) ) { + // found a test unit; add it to list of tu to enable with children and stop recursion in case of suites + m_targ_list.push_back( tu.p_id ); + return false; + } - if( manual_test_units ) - framework::master_test_suite().add( manual_test_units ); -#endif - return 0; + return true; + } + + // Data members + test_unit_id_list& m_targ_list; + const_string m_label; +}; + +// ************************************************************************** // +// ************** set_run_status ************** // +// ************************************************************************** // + +class set_run_status : public test_tree_visitor { +public: + explicit set_run_status( test_unit::run_status rs, test_unit_id_list* dep_collector = 0 ) + : m_new_status( rs ) + , m_dep_collector( dep_collector ) + {} + +private: + // test_tree_visitor interface + virtual bool visit( test_unit const& tu ) + { + const_cast<test_unit&>(tu).p_run_status.value = m_new_status == test_unit::RS_INVALID ? tu.p_default_status : m_new_status; + + if( m_dep_collector ) { + BOOST_TEST_FOREACH( test_unit_id, dep_id, tu.p_dependencies.get() ) { + test_unit const& dep = framework::get( dep_id, TUT_ANY ); + + if( dep.p_run_status == tu.p_run_status ) + continue; + + BOOST_TEST_MESSAGE( "Including test " << dep.p_type_name << ' ' << dep.full_name() << + " as a dependency of test " << tu.p_type_name << ' ' << tu.full_name() ); + + m_dep_collector->push_back( dep_id ); + } + } + return true; } // Data members - init_unit_test_func m_init_func; + test_unit::run_status m_new_status; + test_unit_id_list* m_dep_collector; }; +// ************************************************************************** // +// ************** parse_filters ************** // +// ************************************************************************** // + +static void +add_filtered_test_units( test_unit_id master_tu_id, const_string filter, test_unit_id_list& targ ) +{ + // Choose between two kinds of filters + if( filter[0] == '@' ) { + filter.trim_left( 1 ); + label_filter lf( targ, filter ); + traverse_test_tree( master_tu_id, lf, true ); + } + else { + name_filter nf( targ, filter ); + traverse_test_tree( master_tu_id, nf, true ); + } } +//____________________________________________________________________________// + +static bool +parse_filters( test_unit_id master_tu_id, test_unit_id_list& tu_to_enable, test_unit_id_list& tu_to_disable ) +{ + // 10. collect tu to enable and disable based on filters + bool had_selector_filter = false; + + BOOST_TEST_FOREACH( const_string, filter, runtime_config::test_to_run() ) { + BOOST_TEST_SETUP_ASSERT( !filter.is_empty(), "Invalid filter specification" ); + + enum { SELECTOR, ENABLER, DISABLER } filter_type = SELECTOR; + + // 11. Deduce filter type + if( filter[0] == '!' || filter[0] == '+' ) { + filter_type = filter[0] == '+' ? ENABLER : DISABLER; + filter.trim_left( 1 ); + BOOST_TEST_SETUP_ASSERT( !filter.is_empty(), "Invalid filter specification" ); + } + + had_selector_filter |= filter_type == SELECTOR; + + // 12. Add test units to corresponding list + switch( filter_type ) { + case SELECTOR: + case ENABLER: add_filtered_test_units( master_tu_id, filter, tu_to_enable ); break; + case DISABLER: add_filtered_test_units( master_tu_id, filter, tu_to_disable ); break; + } + } + + return had_selector_filter; +} + +//____________________________________________________________________________// + +} // namespace impl + // ************************************************************************** // -// ************** framework ************** // +// ************** framework::state ************** // // ************************************************************************** // -class framework_impl : public test_tree_visitor { +unsigned const TIMEOUT_EXCEEDED = static_cast<unsigned>( -1 ); + +class state { public: - framework_impl() - : m_master_test_suite( 0 ) - , m_curr_test_case( INV_TEST_UNIT_ID ) + state() + : m_curr_test_case( INV_TEST_UNIT_ID ) , m_next_test_case_id( MIN_TEST_CASE_ID ) , m_next_test_suite_id( MIN_TEST_SUITE_ID ) - , m_is_initialized( false ) , m_test_in_progress( false ) - {} + , m_context_idx( 0 ) + { + } - ~framework_impl() { clear(); } + ~state() { clear(); } void clear() { while( !m_test_units.empty() ) { test_unit_store::value_type const& tu = *m_test_units.begin(); - test_unit* tu_ptr = tu.second; + test_unit const* tu_ptr = tu.second; // the delete will erase this element from map - if( ut_detail::test_id_2_unit_type( tu.second->p_id ) == tut_suite ) - delete (test_suite const*)tu_ptr; + if( ut_detail::test_id_2_unit_type( tu.second->p_id ) == TUT_SUITE ) + delete static_cast<test_suite const*>(tu_ptr); else - delete (test_case const*)tu_ptr; + delete static_cast<test_case const*>(tu_ptr); } } void set_tu_id( test_unit& tu, test_unit_id id ) { tu.p_id.value = id; } - // test_tree_visitor interface implementation - void visit( test_case const& tc ) + ////////////////////////////////////////////////////////////////// + + // Validates the dependency graph and deduces the sibling dependency rank for each child + void deduce_siblings_order( test_unit_id tu_id, test_unit_id master_tu_id, impl::order_info_per_tu& tuoi ) { - if( !tc.check_dependencies() ) { - BOOST_TEST_FOREACH( test_observer*, to, m_observers ) - to->test_unit_skipped( tc ); + test_unit& tu = framework::get( tu_id, TUT_ANY ); + + // collect all sibling dependancy from tu own list + BOOST_TEST_FOREACH( test_unit_id, dep_id, tu.p_dependencies.get() ) + collect_dependant_siblings( tu_id, dep_id, master_tu_id, tuoi ); + if( tu.p_type != TUT_SUITE ) return; + + test_suite& ts = static_cast<test_suite&>(tu); + + // recursive call to children first + BOOST_TEST_FOREACH( test_unit_id, chld_id, ts.m_children ) + deduce_siblings_order( chld_id, master_tu_id, tuoi ); + + BOOST_TEST_FOREACH( test_unit_id, chld_id, ts.m_children ) { + counter_t rank = assign_sibling_rank( chld_id, tuoi ); + ts.m_ranked_children.insert( std::make_pair( rank, chld_id ) ); } + } - BOOST_TEST_FOREACH( test_observer*, to, m_observers ) - to->test_unit_start( tc ); + ////////////////////////////////////////////////////////////////// - boost::timer tc_timer; - test_unit_id bkup = m_curr_test_case; - m_curr_test_case = tc.p_id; - unit_test_monitor_t::error_level run_result = unit_test_monitor.execute_and_translate( tc ); + // Finalize default run status: + // 1) inherit run status from parent where applicable + // 2) if any of test units in test suite enabled enable it as well + bool finalize_default_run_status( test_unit_id tu_id, test_unit::run_status parent_status ) + { + test_unit& tu = framework::get( tu_id, TUT_ANY ); - unsigned long elapsed = static_cast<unsigned long>( tc_timer.elapsed() * 1e6 ); + if( tu.p_default_status == test_suite::RS_INHERIT ) + tu.p_default_status.value = parent_status; - if( unit_test_monitor.is_critical_error( run_result ) ) { - BOOST_TEST_FOREACH( test_observer*, to, m_observers ) - to->test_aborted(); + // go through list of children + if( tu.p_type == TUT_SUITE ) { + bool has_enabled_child = false; + BOOST_TEST_FOREACH( test_unit_id, chld_id, static_cast<test_suite const&>(tu).m_children ) + has_enabled_child |= finalize_default_run_status( chld_id, tu.p_default_status ); + + tu.p_default_status.value = has_enabled_child ? test_suite::RS_ENABLED : test_suite::RS_DISABLED; } - BOOST_TEST_FOREACH( test_observer*, to, m_observers ) - to->test_unit_finish( tc, elapsed ); + return tu.p_default_status == test_suite::RS_ENABLED; + } - m_curr_test_case = bkup; + ////////////////////////////////////////////////////////////////// + + bool finalize_run_status( test_unit_id tu_id ) + { + test_unit& tu = framework::get( tu_id, TUT_ANY ); + + // go through list of children + if( tu.p_type == TUT_SUITE ) { + bool has_enabled_child = false; + BOOST_TEST_FOREACH( test_unit_id, chld_id, static_cast<test_suite const&>(tu).m_children) + has_enabled_child |= finalize_run_status( chld_id ); + + tu.p_run_status.value = has_enabled_child ? test_suite::RS_ENABLED : test_suite::RS_DISABLED; + } - if( unit_test_monitor.is_critical_error( run_result ) ) - throw test_being_aborted(); + return tu.is_enabled(); } - bool test_suite_start( test_suite const& ts ) + ////////////////////////////////////////////////////////////////// + + void deduce_run_status( test_unit_id master_tu_id ) { - if( !ts.check_dependencies() ) { - BOOST_TEST_FOREACH( test_observer*, to, m_observers ) - to->test_unit_skipped( ts ); + using namespace framework::impl; + test_unit_id_list tu_to_enable; + test_unit_id_list tu_to_disable; - return false; + // 10. If there are any filters supplied, figure out lists of test units to enable/disable + bool had_selector_filter = !runtime_config::test_to_run().empty() && + parse_filters( master_tu_id, tu_to_enable, tu_to_disable ); + + // 20. Set the stage: either use default run status or disable all test units + set_run_status setter( had_selector_filter ? test_unit::RS_DISABLED : test_unit::RS_INVALID ); + traverse_test_tree( master_tu_id, setter, true ); + + // 30. Apply all selectors and enablers. + while( !tu_to_enable.empty() ) { + test_unit& tu = framework::get( tu_to_enable.back(), TUT_ANY ); + + tu_to_enable.pop_back(); + + // 35. Ignore test units which already enabled + if( tu.is_enabled() ) + continue; + + // set new status and add all dependencies into tu_to_enable + set_run_status setter( test_unit::RS_ENABLED, &tu_to_enable ); + traverse_test_tree( tu.p_id, setter, true ); } - BOOST_TEST_FOREACH( test_observer*, to, m_observers ) - to->test_unit_start( ts ); + // 40. Apply all disablers + while( !tu_to_disable.empty() ) { + test_unit const& tu = framework::get( tu_to_disable.back(), TUT_ANY ); - return true; + tu_to_disable.pop_back(); + + // 35. Ignore test units which already disabled + if( !tu.is_enabled() ) + continue; + + set_run_status setter( test_unit::RS_DISABLED ); + traverse_test_tree( tu.p_id, setter, true ); + } + + // 50. Make sure parents of enabled test units are also enabled + finalize_run_status( master_tu_id ); } - void test_suite_finish( test_suite const& ts ) + ////////////////////////////////////////////////////////////////// + + typedef unit_test_monitor_t::error_level execution_result; + + // Executed the test tree with the root at specified test unit + execution_result execute_test_tree( test_unit_id tu_id, unsigned timeout = 0 ) { + test_unit const& tu = framework::get( tu_id, TUT_ANY ); + + execution_result result = unit_test_monitor_t::test_ok; + + if( !tu.is_enabled() ) + return result; + + // 10. Check preconditions, including zero time left for execution and + // successful execution of all dependencies + if( timeout == TIMEOUT_EXCEEDED ) { + // notify all observers about skipped test unit + BOOST_TEST_FOREACH( test_observer*, to, m_observers ) + to->test_unit_skipped( tu, "timeout for the test unit is exceeded" ); + + return unit_test_monitor_t::os_timeout; + } + else if( timeout == 0 || timeout > tu.p_timeout ) // deduce timeout for this test unit + timeout = tu.p_timeout; + + test_tools::assertion_result const precondition_res = tu.check_preconditions(); + if( !precondition_res ) { + // notify all observers about skipped test unit + BOOST_TEST_FOREACH( test_observer*, to, m_observers ) + to->test_unit_skipped( tu, precondition_res.message() ); + + return unit_test_monitor_t::precondition_failure; + } + + // 20. Notify all observers about the start of the test unit BOOST_TEST_FOREACH( test_observer*, to, m_observers ) - to->test_unit_finish( ts, 0 ); + to->test_unit_start( tu ); + + // 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() ) { + result = unit_test_monitor.execute_and_translate( boost::bind( &test_unit_fixture::setup, F ) ); + if( result != unit_test_monitor_t::test_ok ) + break; + } + + // This is the time we are going to spend executing the test unit + unsigned long elapsed = 0; + + if( result == unit_test_monitor_t::test_ok ) { + // 40. We are going to time the execution + boost::timer tu_timer; + + if( tu.p_type == TUT_SUITE ) { + test_suite const& ts = static_cast<test_suite const&>( tu ); + + if( runtime_config::random_seed() == 0 ) { + typedef std::pair<counter_t,test_unit_id> value_type; + + BOOST_TEST_FOREACH( value_type, chld, ts.m_ranked_children ) { + unsigned chld_timeout = child_timeout( timeout, tu_timer.elapsed() ); + + result = (std::min)( result, execute_test_tree( chld.second, chld_timeout ) ); + + if( unit_test_monitor.is_critical_error( result ) ) + break; + } + } + else { + // Go through ranges of chldren with the same dependency rank and shuffle them + // independently. Execute each subtree in this order + test_unit_id_list children_with_the_same_rank; + + typedef test_suite::children_per_rank::const_iterator it_type; + it_type it = ts.m_ranked_children.begin(); + while( it != ts.m_ranked_children.end() ) { + children_with_the_same_rank.clear(); + + std::pair<it_type,it_type> range = ts.m_ranked_children.equal_range( it->first ); + it = range.first; + while( it != range.second ) { + children_with_the_same_rank.push_back( it->second ); + it++; + } + + std::random_shuffle( children_with_the_same_rank.begin(), children_with_the_same_rank.end() ); + + BOOST_TEST_FOREACH( test_unit_id, chld, children_with_the_same_rank ) { + unsigned chld_timeout = child_timeout( timeout, tu_timer.elapsed() ); + + result = (std::min)( result, execute_test_tree( chld, chld_timeout ) ); + + if( unit_test_monitor.is_critical_error( result ) ) + break; + } + } + } + + elapsed = static_cast<unsigned long>( tu_timer.elapsed() * 1e6 ); + } + else { // TUT_CASE + test_case const& tc = static_cast<test_case const&>( tu ); + + // setup contexts + m_context_idx = 0; + + // setup current test case + test_unit_id bkup = m_curr_test_case; + m_curr_test_case = tc.p_id; + + // execute the test case body + result = unit_test_monitor.execute_and_translate( tc.p_test_func, timeout ); + elapsed = static_cast<unsigned long>( tu_timer.elapsed() * 1e6 ); + + // cleanup leftover context + m_context.clear(); + + // restore state and abort if necessary + m_curr_test_case = bkup; + } + } + + // if run error is critical skip teardown, who knows what the state of the program at this point + 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() ) { + 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 ) ) + break; + } + } + + // notify all observers about abortion + if( unit_test_monitor.is_critical_error( result ) ) { + BOOST_TEST_FOREACH( test_observer*, to, m_observers ) + to->test_aborted(); + } + + // notify all observers about completion + BOOST_TEST_REVERSE_FOREACH( test_observer*, to, m_observers ) + to->test_unit_finish( tu, elapsed ); + + return result; } ////////////////////////////////////////////////////////////////// + + unsigned child_timeout( unsigned tu_timeout, double elapsed ) + { + if( tu_timeout == 0U ) + return 0U; + + unsigned elpsed_sec = static_cast<unsigned>(elapsed); // rounding to number of whole seconds + + return tu_timeout > elpsed_sec ? tu_timeout - elpsed_sec : TIMEOUT_EXCEEDED; + } + struct priority_order { bool operator()( test_observer* lhs, test_observer* rhs ) const { @@ -200,226 +736,467 @@ public: } }; + // Data members typedef std::map<test_unit_id,test_unit*> test_unit_store; typedef std::set<test_observer*,priority_order> observer_store; + struct context_frame { + context_frame( std::string const& d, int id, bool sticky ) + : descr( d ) + , frame_id( id ) + , is_sticky( sticky ) + {} + + std::string descr; + int frame_id; + bool is_sticky; + }; + typedef std::vector<context_frame> context_data; 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_store m_test_units; test_unit_id m_next_test_case_id; test_unit_id m_next_test_suite_id; - bool m_is_initialized; bool m_test_in_progress; observer_store m_observers; + context_data m_context; + int m_context_idx; + + boost::execution_monitor m_aux_em; }; //____________________________________________________________________________// +namespace impl { namespace { #if defined(__CYGWIN__) -framework_impl& s_frk_impl() { static framework_impl* the_inst = 0; if(!the_inst) the_inst = new framework_impl; return *the_inst; } +framework::state& s_frk_state() { static framework::state* the_inst = 0; if(!the_inst) the_inst = new framework::state; return *the_inst; } #else -framework_impl& s_frk_impl() { static framework_impl the_inst; return the_inst; } +framework::state& s_frk_state() { static framework::state the_inst; return the_inst; } #endif } // local namespace +void +setup_for_execution( test_unit const& tu ) +{ + s_frk_state().deduce_run_status( tu.p_id ); +} + //____________________________________________________________________________// -namespace framework { +} // namespace impl + +//____________________________________________________________________________// + +// ************************************************************************** // +// ************** framework::init ************** // +// ************************************************************************** // void init( init_unit_test_func init_func, int argc, char* argv[] ) { + // 10. Set up runtime parameters runtime_config::init( argc, argv ); - // set the log level and format + // 20. Set the desired log level and format unit_test_log.set_threshold_level( runtime_config::log_level() ); unit_test_log.set_format( runtime_config::log_format() ); - // set the report level and format + // 30. Set the desired report level and format results_reporter::set_level( runtime_config::report_level() ); results_reporter::set_format( runtime_config::report_format() ); + // 40. Register default test observers register_observer( results_collector ); register_observer( unit_test_log ); if( runtime_config::show_progress() ) register_observer( progress_monitor ); + // 50. Set up memory leak detection if( runtime_config::detect_memory_leaks() > 0 ) { - debug::detect_memory_leaks( true ); + debug::detect_memory_leaks( true, runtime_config::memory_leaks_report_file() ); debug::break_memory_alloc( runtime_config::detect_memory_leaks() ); } - // init master unit test suite + // 60. Initialize master unit test suite master_test_suite().argc = argc; master_test_suite().argv = argv; - try { - boost::execution_monitor em; - - ut_detail::test_init_caller tic( init_func ); + using namespace impl; - em.execute( tic ); + // 70. Invoke test module initialization routine + BOOST_TEST_IMPL_TRY { + s_frk_state().m_aux_em.vexecute( boost::bind( &impl::invoke_init_func, init_func ) ); } - catch( execution_exception const& ex ) { - throw setup_error( ex.what() ); + BOOST_TEST_IMPL_CATCH( execution_exception, ex ) { + BOOST_TEST_SETUP_ASSERT( false, ex.what() ); } - - s_frk_impl().m_is_initialized = true; } //____________________________________________________________________________// +void +finalize_setup_phase( test_unit_id master_tu_id ) +{ + if( master_tu_id == INV_TEST_UNIT_ID ) + master_tu_id = master_test_suite().p_id; + + // 10. Apply all decorators to the auto test units + class apply_decorators : public test_tree_visitor { + private: + // test_tree_visitor interface + virtual bool visit( test_unit const& tu ) + { + BOOST_TEST_FOREACH( decorator::base_ptr, d, tu.p_decorators.get() ) + d->apply( const_cast<test_unit&>(tu) ); + + return true; + } + } ad; + traverse_test_tree( master_tu_id, ad, true ); + + // 20. Finalize setup phase + impl::order_info_per_tu tuoi; + impl::s_frk_state().deduce_siblings_order( master_tu_id, master_tu_id, tuoi ); + impl::s_frk_state().finalize_default_run_status( master_tu_id, test_unit::RS_INVALID ); +} + +// ************************************************************************** // +// ************** test_in_progress ************** // +// ************************************************************************** // + bool -is_initialized() +test_in_progress() +{ + return impl::s_frk_state().m_test_in_progress; +} + +//____________________________________________________________________________// + +// ************************************************************************** // +// ************** framework::shutdown ************** // +// ************************************************************************** // + +void +shutdown() { - return s_frk_impl().m_is_initialized; + // eliminating some fake memory leak reports. See for more details: + // http://connect.microsoft.com/VisualStudio/feedback/details/106937/memory-leaks-reported-by-debug-crt-inside-typeinfo-name + +# if BOOST_WORKAROUND(BOOST_MSVC, <= 1600 ) && !defined(_DLL) && defined(_DEBUG) +# if BOOST_WORKAROUND(BOOST_MSVC, < 1600 ) +#define _Next next +#define _MemPtr memPtr +#endif + __type_info_node* pNode = __type_info_root_node._Next; + __type_info_node* tmpNode = &__type_info_root_node; + + for( ; pNode!=NULL; pNode = tmpNode ) { + tmpNode = pNode->_Next; + delete pNode->_MemPtr; + delete pNode; + } +# if BOOST_WORKAROUND(BOOST_MSVC, < 1600 ) +#undef _Next +#undef _MemPtr +#endif +# endif } //____________________________________________________________________________// +// ************************************************************************** // +// ************** register_test_unit ************** // +// ************************************************************************** // + void register_test_unit( test_case* tc ) { BOOST_TEST_SETUP_ASSERT( tc->p_id == INV_TEST_UNIT_ID, BOOST_TEST_L( "test case already registered" ) ); - test_unit_id new_id = s_frk_impl().m_next_test_case_id; + test_unit_id new_id = impl::s_frk_state().m_next_test_case_id; BOOST_TEST_SETUP_ASSERT( new_id != MAX_TEST_CASE_ID, BOOST_TEST_L( "too many test cases" ) ); - typedef framework_impl::test_unit_store::value_type map_value_type; + typedef state::test_unit_store::value_type map_value_type; - s_frk_impl().m_test_units.insert( map_value_type( new_id, tc ) ); - s_frk_impl().m_next_test_case_id++; + impl::s_frk_state().m_test_units.insert( map_value_type( new_id, tc ) ); + impl::s_frk_state().m_next_test_case_id++; - s_frk_impl().set_tu_id( *tc, new_id ); + impl::s_frk_state().set_tu_id( *tc, new_id ); } //____________________________________________________________________________// +// ************************************************************************** // +// ************** register_test_unit ************** // +// ************************************************************************** // + void register_test_unit( test_suite* ts ) { BOOST_TEST_SETUP_ASSERT( ts->p_id == INV_TEST_UNIT_ID, BOOST_TEST_L( "test suite already registered" ) ); - test_unit_id new_id = s_frk_impl().m_next_test_suite_id; + test_unit_id new_id = impl::s_frk_state().m_next_test_suite_id; BOOST_TEST_SETUP_ASSERT( new_id != MAX_TEST_SUITE_ID, BOOST_TEST_L( "too many test suites" ) ); - typedef framework_impl::test_unit_store::value_type map_value_type; - s_frk_impl().m_test_units.insert( map_value_type( new_id, ts ) ); - s_frk_impl().m_next_test_suite_id++; + typedef state::test_unit_store::value_type map_value_type; + + impl::s_frk_state().m_test_units.insert( map_value_type( new_id, ts ) ); + impl::s_frk_state().m_next_test_suite_id++; - s_frk_impl().set_tu_id( *ts, new_id ); + impl::s_frk_state().set_tu_id( *ts, new_id ); } //____________________________________________________________________________// +// ************************************************************************** // +// ************** deregister_test_unit ************** // +// ************************************************************************** // + void deregister_test_unit( test_unit* tu ) { - s_frk_impl().m_test_units.erase( tu->p_id ); + impl::s_frk_state().m_test_units.erase( tu->p_id ); } //____________________________________________________________________________// +// ************************************************************************** // +// ************** clear ************** // +// ************************************************************************** // + void clear() { - s_frk_impl().clear(); + impl::s_frk_state().clear(); } //____________________________________________________________________________// +// ************************************************************************** // +// ************** register_observer ************** // +// ************************************************************************** // + void register_observer( test_observer& to ) { - s_frk_impl().m_observers.insert( &to ); + impl::s_frk_state().m_observers.insert( &to ); } //____________________________________________________________________________// +// ************************************************************************** // +// ************** deregister_observer ************** // +// ************************************************************************** // + void deregister_observer( test_observer& to ) { - s_frk_impl().m_observers.erase( &to ); + impl::s_frk_state().m_observers.erase( &to ); } //____________________________________________________________________________// +// ************************************************************************** // +// ************** add_context ************** // +// ************************************************************************** // + +int +add_context( ::boost::unit_test::lazy_ostream const& context_descr, bool sticky ) +{ + std::stringstream buffer; + context_descr( buffer ); + int res_idx = impl::s_frk_state().m_context_idx++; + + impl::s_frk_state().m_context.push_back( state::context_frame( buffer.str(), res_idx, sticky ) ); + + return res_idx; +} + +//____________________________________________________________________________// + +// ************************************************************************** // +// ************** clear_context ************** // +// ************************************************************************** // + +struct frame_with_id { + explicit frame_with_id( int id ) : m_id( id ) {} + + bool operator()( state::context_frame const& f ) + { + return f.frame_id == m_id; + } + int m_id; +}; + +//____________________________________________________________________________// + void -reset_observers() +clear_context( int frame_id ) +{ + if( frame_id == -1 ) { // clear all non sticky frames + for( int i=static_cast<int>(impl::s_frk_state().m_context.size())-1; i>=0; i-- ) + if( !impl::s_frk_state().m_context[i].is_sticky ) + impl::s_frk_state().m_context.erase( impl::s_frk_state().m_context.begin()+i ); + } + + else { // clear specific frame + state::context_data::iterator it = + std::find_if( impl::s_frk_state().m_context.begin(), impl::s_frk_state().m_context.end(), frame_with_id( frame_id ) ); + + if( it != impl::s_frk_state().m_context.end() ) // really an internal error if this is not true + impl::s_frk_state().m_context.erase( it ); + } +} + +//____________________________________________________________________________// + +// ************************************************************************** // +// ************** get_context ************** // +// ************************************************************************** // + +context_generator +get_context() +{ + return context_generator(); +} + +//____________________________________________________________________________// + +// ************************************************************************** // +// ************** context_generator ************** // +// ************************************************************************** // + +bool +context_generator::is_empty() const { - s_frk_impl().m_observers.clear(); + return impl::s_frk_state().m_context.empty(); } //____________________________________________________________________________// +const_string +context_generator::next() const +{ + return m_curr_frame < impl::s_frk_state().m_context.size() ? impl::s_frk_state().m_context[m_curr_frame++].descr : const_string(); +} + +//____________________________________________________________________________// + +// ************************************************************************** // +// ************** master_test_suite ************** // +// ************************************************************************** // + master_test_suite_t& master_test_suite() { - if( !s_frk_impl().m_master_test_suite ) - s_frk_impl().m_master_test_suite = new master_test_suite_t; + if( !impl::s_frk_state().m_master_test_suite ) + impl::s_frk_state().m_master_test_suite = new master_test_suite_t; - return *s_frk_impl().m_master_test_suite; + return *impl::s_frk_state().m_master_test_suite; } //____________________________________________________________________________// +// ************************************************************************** // +// ************** current_auto_test_suite ************** // +// ************************************************************************** // + +test_suite& +current_auto_test_suite( test_suite* ts, bool push_or_pop ) +{ + if( impl::s_frk_state().m_auto_test_suites.empty() ) + impl::s_frk_state().m_auto_test_suites.push_back( &framework::master_test_suite() ); + + if( !push_or_pop ) + impl::s_frk_state().m_auto_test_suites.pop_back(); + else if( ts ) + impl::s_frk_state().m_auto_test_suites.push_back( ts ); + + return *impl::s_frk_state().m_auto_test_suites.back(); +} + +//____________________________________________________________________________// + +// ************************************************************************** // +// ************** current_test_case ************** // +// ************************************************************************** // + test_case const& current_test_case() { - return get<test_case>( s_frk_impl().m_curr_test_case ); + return get<test_case>( impl::s_frk_state().m_curr_test_case ); } //____________________________________________________________________________// +test_unit_id +current_test_case_id() +{ + return impl::s_frk_state().m_curr_test_case; +} + +//____________________________________________________________________________// + +// ************************************************************************** // +// ************** framework::get ************** // +// ************************************************************************** // + test_unit& get( test_unit_id id, test_unit_type t ) { - test_unit* res = s_frk_impl().m_test_units[id]; + test_unit* res = impl::s_frk_state().m_test_units[id]; if( (res->p_type & t) == 0 ) - throw internal_error( "Invalid test unit type" ); + BOOST_TEST_IMPL_THROW( internal_error( "Invalid test unit type" ) ); return *res; } //____________________________________________________________________________// +// ************************************************************************** // +// ************** framework::run ************** // +// ************************************************************************** // + void run( test_unit_id id, bool continue_test ) { if( id == INV_TEST_UNIT_ID ) id = master_test_suite().p_id; + // Figure out run status for execution phase + impl::s_frk_state().deduce_run_status( id ); + test_case_counter tcc; traverse_test_tree( id, tcc ); - BOOST_TEST_SETUP_ASSERT( tcc.p_count != 0 , runtime_config::test_to_run().is_empty() - ? BOOST_TEST_L( "test tree is empty" ) - : BOOST_TEST_L( "no test cases matching filter" ) ); + BOOST_TEST_SETUP_ASSERT( tcc.p_count != 0 , runtime_config::test_to_run().empty() + ? BOOST_TEST_L( "test tree is empty" ) + : BOOST_TEST_L( "no test cases matching filter or all test cases were disabled" ) ); - bool call_start_finish = !continue_test || !s_frk_impl().m_test_in_progress; - bool was_in_progress = s_frk_impl().m_test_in_progress; + bool was_in_progress = framework::test_in_progress(); + bool call_start_finish = !continue_test || !was_in_progress; - s_frk_impl().m_test_in_progress = true; + impl::s_frk_state().m_test_in_progress = true; if( call_start_finish ) { - BOOST_TEST_FOREACH( test_observer*, to, s_frk_impl().m_observers ) { - boost::execution_monitor em; - - try { - em.execute( ut_detail::test_start_caller( to, tcc.p_count ) ); + BOOST_TEST_FOREACH( test_observer*, to, impl::s_frk_state().m_observers ) { + BOOST_TEST_IMPL_TRY { + impl::s_frk_state().m_aux_em.vexecute( boost::bind( &test_observer::test_start, to, tcc.p_count ) ); } - catch( execution_exception const& ex ) { - throw setup_error( ex.what() ); + BOOST_TEST_IMPL_CATCH( execution_exception, ex ) { + BOOST_TEST_SETUP_ASSERT( false, ex.what() ); } } } @@ -428,7 +1205,7 @@ run( test_unit_id id, bool continue_test ) case 0: break; case 1: { - unsigned int seed = static_cast<unsigned int>( std::time( 0 ) ); + unsigned seed = static_cast<unsigned>( std::time( 0 ) ); BOOST_TEST_MESSAGE( "Test cases order is shuffled using seed: " << seed ); std::srand( seed ); break; @@ -438,19 +1215,14 @@ run( test_unit_id id, bool continue_test ) std::srand( runtime_config::random_seed() ); } - try { - traverse_test_tree( id, s_frk_impl() ); - } - catch( test_being_aborted const& ) { - // abort already reported - } + impl::s_frk_state().execute_test_tree( id ); if( call_start_finish ) { - BOOST_TEST_FOREACH( test_observer*, to, s_frk_impl().m_observers ) + BOOST_TEST_REVERSE_FOREACH( test_observer*, to, impl::s_frk_state().m_observers ) to->test_finish(); } - s_frk_impl().m_test_in_progress = was_in_progress; + impl::s_frk_state().m_test_in_progress = was_in_progress; } //____________________________________________________________________________// @@ -463,41 +1235,49 @@ run( test_unit const* tu, bool continue_test ) //____________________________________________________________________________// +// ************************************************************************** // +// ************** assertion_result ************** // +// ************************************************************************** // + void -assertion_result( bool passed ) +assertion_result( unit_test::assertion_result ar ) { - BOOST_TEST_FOREACH( test_observer*, to, s_frk_impl().m_observers ) - to->assertion_result( passed ); + BOOST_TEST_FOREACH( test_observer*, to, impl::s_frk_state().m_observers ) + to->assertion_result( ar ); } //____________________________________________________________________________// +// ************************************************************************** // +// ************** exception_caught ************** // +// ************************************************************************** // + void exception_caught( execution_exception const& ex ) { - BOOST_TEST_FOREACH( test_observer*, to, s_frk_impl().m_observers ) + BOOST_TEST_FOREACH( test_observer*, to, impl::s_frk_state().m_observers ) to->exception_caught( ex ); } //____________________________________________________________________________// +// ************************************************************************** // +// ************** test_unit_aborted ************** // +// ************************************************************************** // + void test_unit_aborted( test_unit const& tu ) { - BOOST_TEST_FOREACH( test_observer*, to, s_frk_impl().m_observers ) + BOOST_TEST_FOREACH( test_observer*, to, impl::s_frk_state().m_observers ) to->test_unit_aborted( tu ); } //____________________________________________________________________________// } // namespace framework - } // namespace unit_test - } // namespace boost -//____________________________________________________________________________// - #include <boost/test/detail/enable_warnings.hpp> #endif // BOOST_TEST_FRAMEWORK_IPP_021005GER diff --git a/boost/test/impl/interaction_based.ipp b/boost/test/impl/interaction_based.ipp deleted file mode 100644 index ce2893364a..0000000000 --- a/boost/test/impl/interaction_based.ipp +++ /dev/null @@ -1,90 +0,0 @@ -// (C) Copyright Gennadiy Rozental 2005-2008. -// Use, modification, and distribution are subject to the -// Boost Software License, Version 1.0. (See accompanying file -// http://www.boost.org/LICENSE_1_0.txt) - -// See http://www.boost.org/libs/test for the library home page. -// -// File : $RCSfile$ -// -// Version : $Revision$ -// -// Description : Facilities to perform interaction-based testing -// *************************************************************************** - -#ifndef BOOST_TEST_INTERACTION_BASED_IPP_112105GER -#define BOOST_TEST_INTERACTION_BASED_IPP_112105GER - -// Boost.Test -#include <boost/test/detail/config.hpp> - -#if BOOST_TEST_SUPPORT_INTERACTION_TESTING - -// Boost.Test -#include <boost/test/detail/config.hpp> -#include <boost/test/utils/callback.hpp> -#include <boost/test/interaction_based.hpp> -#include <boost/test/mock_object.hpp> -#include <boost/test/framework.hpp> // for setup_error - -#include <boost/test/detail/suppress_warnings.hpp> - -// STL -#include <stdexcept> -#include <string> - -//____________________________________________________________________________// - -namespace boost { - -namespace itest { // interaction-based testing - -// ************************************************************************** // -// ************** manager ************** // -// ************************************************************************** // - -manager::manager() -{ - instance_ptr( true, this ); -} - -//____________________________________________________________________________// - -manager::~manager() -{ - instance_ptr( true ); -} - -//____________________________________________________________________________// - -manager* -manager::instance_ptr( bool reset, manager* new_ptr ) -{ - static manager dummy( 0 ); - - static manager* ptr = &dummy; - - if( reset ) { - if( new_ptr ) { - BOOST_TEST_SETUP_ASSERT( ptr == &dummy, BOOST_TEST_L( "Can't run two interation based test the same time" ) ); - - ptr = new_ptr; - } - else - ptr = &dummy; - } - - return ptr; -} - -} // namespace itest - -} // namespace boost - -//____________________________________________________________________________// - -#include <boost/test/detail/enable_warnings.hpp> - -#endif // not ancient compiler - -#endif // BOOST_TEST_INTERACTION_BASED_IPP_112105GER diff --git a/boost/test/impl/logged_expectations.ipp b/boost/test/impl/logged_expectations.ipp deleted file mode 100644 index ff30628b8e..0000000000 --- a/boost/test/impl/logged_expectations.ipp +++ /dev/null @@ -1,246 +0,0 @@ -// (C) Copyright Gennadiy Rozental 2005-2008. -// Use, modification, and distribution are subject to the -// Boost Software License, ELOG_VER 1.0. (See accompanying file -// http://www.boost.org/LICENSE_1_0.txt) - -// See http://www.boost.org/libs/test for the library home page. -// -// File : $RCSfile$ -// -// Version : $Revision$ -// -// Description : Facilities to perform interaction based testng of logged expectations -// *************************************************************************** - -#ifndef BOOST_TEST_LOGGED_EXPECTATIONS_IPP_120905GER -#define BOOST_TEST_LOGGED_EXPECTATIONS_IPP_120905GER - -// Boost.Test -#include <boost/test/detail/config.hpp> - -#if BOOST_TEST_SUPPORT_INTERACTION_TESTING - -#include <boost/test/detail/global_typedef.hpp> - -#include <boost/test/utils/callback.hpp> -#include <boost/test/utils/iterator/token_iterator.hpp> - -#include <boost/test/interaction_based.hpp> -#include <boost/test/test_tools.hpp> - -#include <boost/test/detail/suppress_warnings.hpp> - -// Boost -#include <boost/lexical_cast.hpp> - -// STL -#include <fstream> - -//____________________________________________________________________________// - -namespace boost { - -using namespace ::boost::unit_test; - -namespace itest { - -// ************************************************************************** // -// ************** logged expectation test implementation ************** // -// ************************************************************************** // - -struct expectations_logger : itest::manager { - // Constructor - expectations_logger( const_string log_file_name, bool test_or_log ); - - virtual bool decision_point( const_string, std::size_t ); - virtual unsigned enter_scope( const_string, std::size_t, const_string scope_name ); - virtual void allocated( const_string, std::size_t, void*, std::size_t s ); - virtual void data_flow( const_string d ); - virtual std::string return_value( const_string default_value ); - -private: - // Data members - bool m_test_or_log; - std::fstream m_log_file; -}; - -literal_string ELOG_VER = "1.0"; -literal_string CLMN_SEP = "|"; -static const char LINE_SEP = '\n'; - -literal_string FILE_SIG = "ELOG"; -literal_string SCOPE_SIG = "SCOPE"; -literal_string ALLOC_SIG = "ALLOC"; -literal_string DP_SIG = "SWITCH"; -literal_string DATA_SIG = "DATA"; -literal_string RETURN_SIG = "RETURN"; - -//____________________________________________________________________________// - -expectations_logger::expectations_logger( const_string log_file_name, bool test_or_log ) -: m_test_or_log( test_or_log ) -{ - BOOST_REQUIRE_MESSAGE( !log_file_name.is_empty(), "Empty expectations log file name" ); - - m_log_file.open( log_file_name.begin(), test_or_log ? std::ios::in : std::ios::out ); - - BOOST_REQUIRE_MESSAGE( m_log_file.is_open(), - "Can't open expectations log file " << log_file_name - << " for " << ( m_test_or_log ? "reading" : "writing") ); - - if( m_test_or_log ) { - std::string line; - - std::getline( m_log_file, line, LINE_SEP ); - - const_string cline( line ); - string_token_iterator tit( cline, (dropped_delimeters = CLMN_SEP, kept_delimeters = dt_none)); - - BOOST_CHECK_EQUAL( *tit, FILE_SIG ); - ++tit; - BOOST_CHECK_EQUAL( *tit, ELOG_VER ); - } - else { - m_log_file << FILE_SIG << CLMN_SEP << ELOG_VER << LINE_SEP; - } -} - -//____________________________________________________________________________// - -bool -expectations_logger::decision_point( const_string, std::size_t ) -{ - if( m_test_or_log ) { - std::string line; - - std::getline( m_log_file, line, LINE_SEP ); - - const_string cline( line ); - string_token_iterator tit( cline, (dropped_delimeters = CLMN_SEP, kept_delimeters = dt_none)); - - BOOST_CHECK_EQUAL( *tit, DP_SIG ); ++tit; - return lexical_cast<bool>( *tit ); - } - else { - m_log_file << DP_SIG << CLMN_SEP << std::boolalpha << true << LINE_SEP; - - return true; - } -} - -//____________________________________________________________________________// - -unsigned -expectations_logger::enter_scope( const_string, std::size_t, const_string scope_name ) -{ - if( m_test_or_log ) { - std::string line; - - std::getline( m_log_file, line, LINE_SEP ); - - const_string cline( line ); - string_token_iterator tit( cline, (dropped_delimeters = CLMN_SEP, kept_delimeters = dt_none)); - - BOOST_CHECK_EQUAL( *tit, SCOPE_SIG ); ++tit; - BOOST_CHECK_EQUAL( *tit, scope_name ); - } - else { - m_log_file << SCOPE_SIG << CLMN_SEP << scope_name << LINE_SEP; - } - - return 0; -} - -//____________________________________________________________________________// - -void -expectations_logger::allocated( const_string, std::size_t, void*, std::size_t s ) -{ - if( m_test_or_log ) { - std::string line; - - std::getline( m_log_file, line, LINE_SEP ); - - const_string cline( line ); - string_token_iterator tit( cline, (dropped_delimeters = CLMN_SEP, kept_delimeters = dt_none)); - - BOOST_CHECK_EQUAL( *tit, ALLOC_SIG ); ++tit; - BOOST_CHECK_EQUAL( lexical_cast<std::size_t>( *tit ), s ); - } - else { - m_log_file << ALLOC_SIG << CLMN_SEP << s << LINE_SEP; - } -} - -//____________________________________________________________________________// - -void -expectations_logger::data_flow( const_string d ) -{ - if( m_test_or_log ) { - std::string line; - - std::getline( m_log_file, line, LINE_SEP ); - - const_string cline( line ); - string_token_iterator tit( cline, (dropped_delimeters = CLMN_SEP, kept_delimeters = dt_none)); - - BOOST_CHECK_EQUAL( *tit, DATA_SIG ); ++tit; - BOOST_CHECK_EQUAL( *tit, d ); - } - else { - m_log_file << DATA_SIG << CLMN_SEP << d << LINE_SEP; - } -} - -//____________________________________________________________________________// - -std::string -expectations_logger::return_value( const_string default_value ) -{ - if( m_test_or_log ) { - std::string line; - - std::getline( m_log_file, line, LINE_SEP ); - - const_string cline( line ); - string_token_iterator tit( cline, (dropped_delimeters = CLMN_SEP, kept_delimeters = dt_none)); - - BOOST_CHECK_EQUAL( *tit, RETURN_SIG ); ++tit; - - return std::string( tit->begin(), tit->size() ); - } - else { - m_log_file << RETURN_SIG << CLMN_SEP << default_value << LINE_SEP; - - return std::string(); - } -} - -//____________________________________________________________________________// - -// ************************************************************************** // -// ************** logged expectations test ************** // -// ************************************************************************** // - -void BOOST_TEST_DECL -logged_expectations( callback0<> const& F, const_string log_file_name, bool test_or_log ) -{ - expectations_logger el( log_file_name, test_or_log ); - - F(); -} - -//____________________________________________________________________________// - -} // namespace itest - -} // namespace boost - -//____________________________________________________________________________// - -#include <boost/test/detail/enable_warnings.hpp> - -#endif // not ancient compiler - -#endif // BOOST_TEST_LOGGED_EXPECTATIONS_IPP_120905GER diff --git a/boost/test/impl/plain_report_formatter.ipp b/boost/test/impl/plain_report_formatter.ipp index 95b662135d..f9e7db772a 100644 --- a/boost/test/impl/plain_report_formatter.ipp +++ b/boost/test/impl/plain_report_formatter.ipp @@ -1,4 +1,4 @@ -// (C) Copyright Gennadiy Rozental 2005-2008. +// (C) Copyright Gennadiy Rozental 2005-2014. // 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) @@ -19,9 +19,13 @@ #include <boost/test/output/plain_report_formatter.hpp> #include <boost/test/utils/custom_manip.hpp> #include <boost/test/results_collector.hpp> -#include <boost/test/unit_test_suite_impl.hpp> + +#include <boost/test/tree/test_unit.hpp> #include <boost/test/utils/basic_cstring/io.hpp> +#include <boost/test/utils/setcolor.hpp> + +#include <boost/test/unit_test_parameters.hpp> // STL #include <iomanip> @@ -37,9 +41,7 @@ namespace std { using ::log10; } //____________________________________________________________________________// namespace boost { - namespace unit_test { - namespace output { namespace { @@ -58,17 +60,16 @@ operator<<( custom_printer<quote> const& p, T const& value ) //____________________________________________________________________________// void -print_stat_value( std::ostream& ostr, counter_t v, counter_t indent, counter_t total, - const_string name, const_string res ) +print_stat_value( std::ostream& ostr, counter_t v, counter_t indent, counter_t total, const_string name, const_string res ) { - if( v > 0 ) { - ostr << std::setw( indent ) << "" - << v << ' ' << name << ( v != 1 ? "s" : "" ); - if( total > 0 ) - ostr << " out of " << total; + if( v == 0 ) + return; - ostr << ' ' << res << '\n'; - } + if( total > 0 ) + ostr << std::setw( static_cast<int>(indent) ) << "" << v << ' ' << name << ( v != 1 ? "s" : "" ) + << " out of " << total << ' ' << res << '\n'; + else + ostr << std::setw( static_cast<int>(indent) ) << "" << v << ' ' << res << ' ' << name << ( v != 1 ? "s" : "" ) << '\n'; } //____________________________________________________________________________// @@ -104,40 +105,42 @@ plain_report_formatter::test_unit_report_start( test_unit const& tu, std::ostrea const_string descr; if( tr.passed() ) - descr = "passed"; + descr = "has passed"; else if( tr.p_skipped ) - descr = "skipped"; + descr = "was skipped"; else if( tr.p_aborted ) - descr = "aborted"; + descr = "was aborted"; else - descr = "failed"; + descr = "has failed"; - ostr << std::setw( m_indent ) << "" - << "Test " << (tu.p_type == tut_case ? "case " : "suite " ) << quote() << tu.p_name << ' ' << descr; + ostr << std::setw( static_cast<int>(m_indent) ) << "" + << "Test " << tu.p_type_name << ' ' << quote() << tu.full_name() << ' ' << descr; if( tr.p_skipped ) { - ostr << " due to " << (tu.check_dependencies() ? "test aborting\n" : "failed dependancy\n" ); + ostr << "\n"; m_indent += 2; return; } - + counter_t total_assertions = tr.p_assertions_passed + tr.p_assertions_failed; - counter_t total_tc = tr.p_test_cases_passed + tr.p_test_cases_failed + tr.p_test_cases_skipped; + counter_t total_tc = tr.p_test_cases_passed + tr.p_test_cases_warned + tr.p_test_cases_failed + tr.p_test_cases_skipped; - if( total_assertions > 0 || total_tc > 0 ) + if( total_assertions > 0 || total_tc > 0 || tr.p_warnings_failed > 0) ostr << " with:"; ostr << '\n'; m_indent += 2; - print_stat_value( ostr, tr.p_assertions_passed, m_indent, total_assertions, "assertion", "passed" ); - print_stat_value( ostr, tr.p_assertions_failed, m_indent, total_assertions, "assertion", "failed" ); - print_stat_value( ostr, tr.p_expected_failures, m_indent, 0 , "failure" , "expected" ); - print_stat_value( ostr, tr.p_test_cases_passed, m_indent, total_tc , "test case", "passed" ); - print_stat_value( ostr, tr.p_test_cases_failed, m_indent, total_tc , "test case", "failed" ); - print_stat_value( ostr, tr.p_test_cases_skipped, m_indent, total_tc , "test case", "skipped" ); - print_stat_value( ostr, tr.p_test_cases_aborted, m_indent, total_tc , "test case", "aborted" ); - + print_stat_value( ostr, tr.p_test_cases_passed , m_indent, total_tc , "test case", "passed" ); + print_stat_value( ostr, tr.p_test_cases_warned , m_indent, total_tc , "test case", "passed with warnings" ); + print_stat_value( ostr, tr.p_test_cases_failed , m_indent, total_tc , "test case", "failed" ); + print_stat_value( ostr, tr.p_test_cases_skipped, m_indent, total_tc , "test case", "skipped" ); + print_stat_value( ostr, tr.p_test_cases_aborted, m_indent, total_tc , "test case", "aborted" ); + print_stat_value( ostr, tr.p_assertions_passed , m_indent, total_assertions, "assertion", "passed" ); + print_stat_value( ostr, tr.p_assertions_failed , m_indent, total_assertions, "assertion", "failed" ); + print_stat_value( ostr, tr.p_warnings_failed , m_indent, 0 , "warning" , "failed" ); + print_stat_value( ostr, tr.p_expected_failures , m_indent, 0 , "failure" , "expected" ); + ostr << '\n'; } @@ -155,44 +158,50 @@ void plain_report_formatter::do_confirmation_report( test_unit const& tu, std::ostream& ostr ) { test_results const& tr = results_collector.results( tu.p_id ); - + if( tr.passed() ) { + BOOST_TEST_SCOPE_SETCOLOR( ostr, term_attr::BRIGHT, term_color::GREEN ); + ostr << "*** No errors detected\n"; return; } - + + BOOST_TEST_SCOPE_SETCOLOR( ostr, term_attr::BRIGHT, term_color::RED ); + if( tr.p_skipped ) { - ostr << "*** Test " << tu.p_type_name << " skipped due to " - << (tu.check_dependencies() ? "test aborting\n" : "failed dependancy\n" ); + ostr << "*** The test " << tu.p_type_name << ' ' << quote() << tu.full_name() << " was skipped" + << "; see standard output for details\n"; return; } - if( tr.p_assertions_failed == 0 ) { - ostr << "*** errors detected in test " << tu.p_type_name << " " << quote() << tu.p_name + if( tr.p_aborted ) { + ostr << "*** The test " << tu.p_type_name << ' ' << quote() << tu.full_name() << " was aborted" << "; see standard output for details\n"; + } + + if( tr.p_assertions_failed == 0 ) { + if( !tr.p_aborted ) + ostr << "*** Errors were detected in the test " << tu.p_type_name << ' ' << quote() << tu.full_name() + << "; see standard output for details\n"; return; } counter_t num_failures = tr.p_assertions_failed; - - ostr << "*** " << num_failures << " failure" << ( num_failures != 1 ? "s" : "" ) << " detected"; - + + ostr << "*** " << num_failures << " failure" << ( num_failures != 1 ? "s are" : " is" ) << " detected"; + if( tr.p_expected_failures > 0 ) - ostr << " (" << tr.p_expected_failures << " failure" << ( tr.p_expected_failures != 1 ? "s" : "" ) << " expected)"; - - ostr << " in test " << tu.p_type_name << " " << quote() << tu.p_name << "\n"; + ostr << " (" << tr.p_expected_failures << " failure" << ( tr.p_expected_failures != 1 ? "s are" : " is" ) << " expected)"; + + ostr << " in the test " << tu.p_type_name << " " << quote() << tu.full_name() << "\n"; } //____________________________________________________________________________// } // namespace output - } // namespace unit_test - } // namespace boost -//____________________________________________________________________________// - #include <boost/test/detail/enable_warnings.hpp> #endif // BOOST_TEST_PLAIN_REPORT_FORMATTER_IPP_020105GER diff --git a/boost/test/impl/progress_monitor.ipp b/boost/test/impl/progress_monitor.ipp index 5175755c3a..ebdd7e9320 100644 --- a/boost/test/impl/progress_monitor.ipp +++ b/boost/test/impl/progress_monitor.ipp @@ -1,4 +1,4 @@ -// (C) Copyright Gennadiy Rozental 2005-2008. +// (C) Copyright Gennadiy Rozental 2005-2014. // 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) @@ -17,12 +17,15 @@ // Boost.Test #include <boost/test/progress_monitor.hpp> -#include <boost/test/unit_test_suite_impl.hpp> -#include <boost/test/detail/unit_test_parameters.hpp> +#include <boost/test/unit_test_parameters.hpp> +#include <boost/test/utils/setcolor.hpp> + +#include <boost/test/tree/test_unit.hpp> +#include <boost/test/tree/test_case_counter.hpp> +#include <boost/test/tree/traverse.hpp> // Boost -#include <boost/progress.hpp> #include <boost/scoped_ptr.hpp> #include <boost/test/detail/suppress_warnings.hpp> @@ -30,13 +33,70 @@ //____________________________________________________________________________// namespace boost { - namespace unit_test { // ************************************************************************** // // ************** progress_monitor ************** // // ************************************************************************** // +struct progress_display { + progress_display( counter_t expected_count, std::ostream& os ) + : m_os(os) + , m_count( 0 ) + , m_expected_count( expected_count ) + , m_next_tic_count( 0 ) + , m_tic( 0 ) + { + + m_os << "\n0% 10 20 30 40 50 60 70 80 90 100%" + << "\n|----|----|----|----|----|----|----|----|----|----|" + << std::endl; + + if( !m_expected_count ) + m_expected_count = 1; // prevent divide by zero + } + + unsigned long operator+=( unsigned long increment ) + { + if( (m_count += increment) < m_next_tic_count ) + return m_count; + + // use of floating point ensures that both large and small counts + // work correctly. static_cast<>() is also used several places + // to suppress spurious compiler warnings. + unsigned int tics_needed = static_cast<unsigned int>( + (static_cast<double>(m_count)/m_expected_count)*50.0 ); + + do { + m_os << '*' << std::flush; + } while( ++m_tic < tics_needed ); + + m_next_tic_count = static_cast<unsigned long>((m_tic/50.0) * m_expected_count); + + if( m_count == m_expected_count ) { + if( m_tic < 51 ) + m_os << '*'; + + m_os << std::endl; + } + + return m_count; + } + unsigned long operator++() { return operator+=( 1 ); } + unsigned long count() const { return m_count; } + +private: + BOOST_DELETED_FUNCTION(progress_display(progress_display const&)) + BOOST_DELETED_FUNCTION(progress_display& operator=(progress_display const&)) + + std::ostream& m_os; // may not be present in all imps + + unsigned long m_count; + unsigned long m_expected_count; + unsigned long m_next_tic_count; + unsigned int m_tic; +}; + namespace { struct progress_monitor_impl { @@ -58,6 +118,8 @@ progress_monitor_impl& s_pm_impl() { static progress_monitor_impl the_inst; retu void progress_monitor_t::test_start( counter_t test_cases_amount ) { + BOOST_TEST_SCOPE_SETCOLOR( *s_pm_impl().m_stream, term_attr::BRIGHT, term_color::MAGENTA ); + s_pm_impl().m_progress_display.reset( new progress_display( test_cases_amount, *s_pm_impl().m_stream ) ); } @@ -66,6 +128,8 @@ progress_monitor_t::test_start( counter_t test_cases_amount ) void progress_monitor_t::test_aborted() { + BOOST_TEST_SCOPE_SETCOLOR( *s_pm_impl().m_stream, term_attr::BRIGHT, term_color::MAGENTA ); + (*s_pm_impl().m_progress_display) += s_pm_impl().m_progress_display->count(); } @@ -74,18 +138,22 @@ progress_monitor_t::test_aborted() void progress_monitor_t::test_unit_finish( test_unit const& tu, unsigned long ) { - if( tu.p_type == tut_case ) + BOOST_TEST_SCOPE_SETCOLOR( *s_pm_impl().m_stream, term_attr::BRIGHT, term_color::MAGENTA ); + + if( tu.p_type == TUT_CASE ) ++(*s_pm_impl().m_progress_display); } //____________________________________________________________________________// void -progress_monitor_t::test_unit_skipped( test_unit const& tu ) +progress_monitor_t::test_unit_skipped( test_unit const& tu, const_string /*reason*/ ) { + BOOST_TEST_SCOPE_SETCOLOR( *s_pm_impl().m_stream, term_attr::BRIGHT, term_color::MAGENTA ); + test_case_counter tcc; traverse_test_tree( tu, tcc ); - + (*s_pm_impl().m_progress_display) += tcc.p_count; } @@ -98,13 +166,10 @@ progress_monitor_t::set_stream( std::ostream& ostr ) } //____________________________________________________________________________// - -} // namespace unit_test +} // namespace unit_test } // namespace boost -//____________________________________________________________________________// - #include <boost/test/detail/enable_warnings.hpp> #endif // BOOST_TEST_PROGRESS_MONITOR_IPP_020105GER diff --git a/boost/test/impl/results_collector.ipp b/boost/test/impl/results_collector.ipp index 0d5691aab6..d04d64fd6d 100644 --- a/boost/test/impl/results_collector.ipp +++ b/boost/test/impl/results_collector.ipp @@ -1,4 +1,4 @@ -// (C) Copyright Gennadiy Rozental 2005-2008. +// (C) Copyright Gennadiy Rozental 2005-2014. // 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) @@ -16,11 +16,15 @@ #define BOOST_TEST_RESULTS_COLLECTOR_IPP_021105GER // Boost.Test -#include <boost/test/unit_test_suite_impl.hpp> #include <boost/test/unit_test_log.hpp> #include <boost/test/results_collector.hpp> #include <boost/test/framework.hpp> +#include <boost/test/tree/test_unit.hpp> +#include <boost/test/tree/visitor.hpp> +#include <boost/test/tree/test_case_counter.hpp> +#include <boost/test/tree/traverse.hpp> + // Boost #include <boost/cstdlib.hpp> @@ -32,7 +36,6 @@ //____________________________________________________________________________// namespace boost { - namespace unit_test { // ************************************************************************** // @@ -52,6 +55,7 @@ test_results::passed() const return !p_skipped && p_test_cases_failed == 0 && p_assertions_failed <= p_expected_failures && + p_test_cases_skipped == 0 && !p_aborted; } @@ -73,7 +77,9 @@ test_results::operator+=( test_results const& tr ) { p_assertions_passed.value += tr.p_assertions_passed; p_assertions_failed.value += tr.p_assertions_failed; + p_warnings_failed.value += tr.p_warnings_failed; p_test_cases_passed.value += tr.p_test_cases_passed; + p_test_cases_warned.value += tr.p_test_cases_warned; p_test_cases_failed.value += tr.p_test_cases_failed; p_test_cases_skipped.value += tr.p_test_cases_skipped; p_test_cases_aborted.value += tr.p_test_cases_aborted; @@ -84,25 +90,25 @@ test_results::operator+=( test_results const& tr ) void test_results::clear() { - p_assertions_passed.value = 0; - p_assertions_failed.value = 0; - p_expected_failures.value = 0; - p_test_cases_passed.value = 0; - p_test_cases_failed.value = 0; - p_test_cases_skipped.value = 0; - p_test_cases_aborted.value = 0; - p_aborted.value = false; - p_skipped.value = true; + p_assertions_passed.value = 0; + p_assertions_failed.value = 0; + p_warnings_failed.value = 0; + p_expected_failures.value = 0; + p_test_cases_passed.value = 0; + p_test_cases_warned.value = 0; + p_test_cases_failed.value = 0; + p_test_cases_skipped.value = 0; + p_test_cases_aborted.value = 0; + p_aborted.value = false; + p_skipped.value = false; } //____________________________________________________________________________// - + // ************************************************************************** // // ************** results_collector ************** // // ************************************************************************** // -#if !BOOST_WORKAROUND(BOOST_MSVC, <1300) - namespace { struct results_collector_impl { @@ -113,16 +119,6 @@ results_collector_impl& s_rc_impl() { static results_collector_impl the_inst; re } // local namespace -#else - -struct results_collector_impl { - std::map<test_unit_id,test_results> m_results_store; -}; - -static results_collector_impl& s_rc_impl() { static results_collector_impl the_inst; return the_inst; } - -#endif - //____________________________________________________________________________// void @@ -134,31 +130,14 @@ results_collector_t::test_start( counter_t ) //____________________________________________________________________________// void -results_collector_t::test_finish() -{ - // do nothing -} - -//____________________________________________________________________________// - -void -results_collector_t::test_aborted() -{ - // do nothing -} - -//____________________________________________________________________________// - -void results_collector_t::test_unit_start( test_unit const& tu ) { // init test_results entry test_results& tr = s_rc_impl().m_results_store[tu.p_id]; tr.clear(); - - tr.p_expected_failures.value = tu.p_expected_failures; - tr.p_skipped.value = false; + + tr.p_expected_failures.value = tu.p_expected_failures; } //____________________________________________________________________________// @@ -172,13 +151,18 @@ public: test_results const& tr = results_collector.results( tc.p_id ); m_tr += tr; - if( tr.passed() ) - m_tr.p_test_cases_passed.value++; + if( tr.passed() ) { + if( tr.p_warnings_failed ) + m_tr.p_test_cases_warned.value++; + else + m_tr.p_test_cases_passed.value++; + } else if( tr.p_skipped ) m_tr.p_test_cases_skipped.value++; else { if( tr.p_aborted ) m_tr.p_test_cases_aborted.value++; + m_tr.p_test_cases_failed.value++; } } @@ -186,10 +170,9 @@ public: { if( m_ts.p_id == ts.p_id ) return true; - else { - m_tr += results_collector.results( ts.p_id ); - return false; - } + + m_tr += results_collector.results( ts.p_id ); + return false; } private: @@ -203,53 +186,55 @@ private: void results_collector_t::test_unit_finish( test_unit const& tu, unsigned long ) { - if( tu.p_type == tut_suite ) { + if( tu.p_type == TUT_SUITE ) { results_collect_helper ch( s_rc_impl().m_results_store[tu.p_id], tu ); traverse_test_tree( tu, ch ); } else { test_results const& tr = s_rc_impl().m_results_store[tu.p_id]; - + bool num_failures_match = tr.p_aborted || tr.p_assertions_failed >= tr.p_expected_failures; if( !num_failures_match ) - BOOST_TEST_MESSAGE( "Test case " << tu.p_name << " has fewer failures than expected" ); + BOOST_TEST_MESSAGE( "Test case " << tu.full_name() << " has fewer failures than expected" ); bool check_any_assertions = tr.p_aborted || (tr.p_assertions_failed != 0) || (tr.p_assertions_passed != 0); if( !check_any_assertions ) - BOOST_TEST_MESSAGE( "Test case " << tu.p_name << " did not check any assertions" ); + BOOST_TEST_MESSAGE( "Test case " << tu.full_name() << " did not check any assertions" ); } } //____________________________________________________________________________// void -results_collector_t::test_unit_skipped( test_unit const& tu ) +results_collector_t::test_unit_skipped( test_unit const& tu, const_string /*reason*/ ) { - if( tu.p_type == tut_suite ) { + test_results& tr = s_rc_impl().m_results_store[tu.p_id]; + + tr.clear(); + + tr.p_skipped.value = true; + + if( tu.p_type == TUT_SUITE ) { test_case_counter tcc; traverse_test_tree( tu, tcc ); - test_results& tr = s_rc_impl().m_results_store[tu.p_id]; - - tr.clear(); - - tr.p_skipped.value = true; - tr.p_test_cases_skipped.value = tcc.p_count; + tr.p_test_cases_skipped.value = tcc.p_count; } } //____________________________________________________________________________// void -results_collector_t::assertion_result( bool passed ) +results_collector_t::assertion_result( unit_test::assertion_result ar ) { - test_results& tr = s_rc_impl().m_results_store[framework::current_test_case().p_id]; + test_results& tr = s_rc_impl().m_results_store[framework::current_test_case_id()]; - if( passed ) - tr.p_assertions_passed.value++; - else - tr.p_assertions_failed.value++; + switch( ar ) { + case AR_PASSED: tr.p_assertions_passed.value++; break; + case AR_FAILED: tr.p_assertions_failed.value++; break; + case AR_TRIGGERED: tr.p_warnings_failed.value++; break; + } if( tr.p_assertions_failed == 1 ) first_failed_assertion(); @@ -260,7 +245,7 @@ results_collector_t::assertion_result( bool passed ) void results_collector_t::exception_caught( execution_exception const& ) { - test_results& tr = s_rc_impl().m_results_store[framework::current_test_case().p_id]; + test_results& tr = s_rc_impl().m_results_store[framework::current_test_case_id()]; tr.p_assertions_failed.value++; } @@ -284,11 +269,8 @@ results_collector_t::results( test_unit_id id ) const //____________________________________________________________________________// } // namespace unit_test - } // namespace boost -//____________________________________________________________________________// - #include <boost/test/detail/enable_warnings.hpp> #endif // BOOST_TEST_RESULTS_COLLECTOR_IPP_021105GER diff --git a/boost/test/impl/results_reporter.ipp b/boost/test/impl/results_reporter.ipp index 54447c3932..885295c928 100644 --- a/boost/test/impl/results_reporter.ipp +++ b/boost/test/impl/results_reporter.ipp @@ -1,4 +1,4 @@ -// (C) Copyright Gennadiy Rozental 2005-2008. +// (C) Copyright Gennadiy Rozental 2005-2014. // 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) @@ -17,13 +17,16 @@ // Boost.Test #include <boost/test/results_reporter.hpp> -#include <boost/test/unit_test_suite_impl.hpp> #include <boost/test/results_collector.hpp> #include <boost/test/framework.hpp> #include <boost/test/output/plain_report_formatter.hpp> #include <boost/test/output/xml_report_formatter.hpp> -#include <boost/test/detail/unit_test_parameters.hpp> +#include <boost/test/tree/visitor.hpp> +#include <boost/test/tree/test_unit.hpp> +#include <boost/test/tree/traverse.hpp> + +#include <boost/test/unit_test_parameters.hpp> // Boost #include <boost/scoped_ptr.hpp> @@ -38,9 +41,7 @@ typedef ::boost::io::ios_base_all_saver io_saver_type; //____________________________________________________________________________// namespace boost { - namespace unit_test { - namespace results_reporter { // ************************************************************************** // @@ -126,14 +127,13 @@ void set_format( output_format rf ) { switch( rf ) { - case CLF: + default: + case OF_CLF: set_format( new output::plain_report_formatter ); break; - case XML: + case OF_XML: set_format( new output::xml_report_formatter ); break; - default: - break; } } @@ -190,13 +190,9 @@ make_report( report_level l, test_unit_id id ) //____________________________________________________________________________// } // namespace results_reporter - } // namespace unit_test - } // namespace boost -//____________________________________________________________________________// - #include <boost/test/detail/enable_warnings.hpp> #endif // BOOST_TEST_RESULTS_REPORTER_IPP_020105GER diff --git a/boost/test/impl/test_main.ipp b/boost/test/impl/test_main.ipp index b08f5e16c7..c95c91e88b 100644 --- a/boost/test/impl/test_main.ipp +++ b/boost/test/impl/test_main.ipp @@ -1,4 +1,4 @@ -// (C) Copyright Gennadiy Rozental 2001-2008. +// (C) Copyright Gennadiy Rozental 2001-2014. // (C) Copyright Beman Dawes 1995-2001. // Distributed under the Boost Software License, Version 1.0. // (See accompanying file LICENSE_1_0.txt or copy at @@ -6,11 +6,8 @@ // See http://www.boost.org/libs/test for the library home page. // -// File : $RCSfile$ -// -// Version : $$Revision$ -// -// Description : implements main function for Test Execution Monitor. +/// @file +/// @brief Implements main function for Test Execution Monitor. // *************************************************************************** #ifndef BOOST_TEST_TEST_MAIN_IPP_012205GER @@ -32,16 +29,16 @@ extern int test_main( int argc, char* argv[] ); // prototype for user's test_ struct test_main_caller { test_main_caller( int argc, char** argv ) : m_argc( argc ), m_argv( argv ) {} - + void operator()() { int test_main_result = test_main( m_argc, m_argv ); // translate a test_main non-success return into a test error BOOST_CHECK( test_main_result == 0 || test_main_result == boost::exit_success ); } - + private: - // Data members + // Data members int m_argc; char** m_argv; }; @@ -53,11 +50,11 @@ private: ::boost::unit_test::test_suite* init_unit_test_suite( int argc, char* argv[] ) { using namespace ::boost::unit_test; - + framework::master_test_suite().p_name.value = "Test Program"; - + framework::master_test_suite().add( BOOST_TEST_CASE( test_main_caller( argc, argv ) ) ); - + return 0; } diff --git a/boost/test/impl/test_tools.ipp b/boost/test/impl/test_tools.ipp index 6f5d7e9edf..03fea91605 100644 --- a/boost/test/impl/test_tools.ipp +++ b/boost/test/impl/test_tools.ipp @@ -1,4 +1,4 @@ -// (C) Copyright Gennadiy Rozental 2005-2008. +// (C) Copyright Gennadiy Rozental 2005-2014. // 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) @@ -16,12 +16,18 @@ #define BOOST_TEST_TEST_TOOLS_IPP_012205GER // Boost.Test -#include <boost/test/test_tools.hpp> #include <boost/test/unit_test_log.hpp> -#include <boost/test/output_test_stream.hpp> +#include <boost/test/tools/context.hpp> +#include <boost/test/tools/output_test_stream.hpp> + +#include <boost/test/tools/detail/fwd.hpp> +#include <boost/test/tools/detail/print_helper.hpp> + #include <boost/test/framework.hpp> +#include <boost/test/tree/test_unit.hpp> #include <boost/test/execution_monitor.hpp> // execution_aborted -#include <boost/test/unit_test_suite_impl.hpp> + +#include <boost/test/detail/throw_exception.hpp> // Boost #include <boost/config.hpp> @@ -33,6 +39,8 @@ #include <cctype> #include <cwchar> #include <stdexcept> +#include <vector> +#include <utility> #include <ios> // !! should we use #include <cstdarg> @@ -50,8 +58,8 @@ namespace std { using ::wcscmp; } # endif namespace boost { - namespace test_tools { +namespace tt_detail { // ************************************************************************** // // ************** print_log_value ************** // @@ -105,119 +113,78 @@ print_log_value<wchar_t const*>::operator()( std::ostream& ostr, wchar_t const* //____________________________________________________________________________// -namespace tt_detail { - // ************************************************************************** // // ************** TOOL BOX Implementation ************** // // ************************************************************************** // using ::boost::unit_test::lazy_ostream; -bool -check_impl( predicate_result const& pr, lazy_ostream const& check_descr, - const_string file_name, std::size_t line_num, - tool_level tl, check_type ct, - std::size_t num_of_args, ... ) +static char const* check_str [] = { " == ", " != ", " < " , " <= ", " > " , " >= " }; +static char const* rever_str [] = { " != ", " == ", " >= ", " > " , " <= ", " < " }; + +template<typename OutStream> +void +format_report( OutStream& os, assertion_result const& pr, unit_test::lazy_ostream const& assertion_descr, + tool_level tl, check_type ct, + std::size_t num_args, va_list args, + char const* prefix, char const* suffix ) { using namespace unit_test; - if( !framework::is_initialized() ) - throw std::runtime_error( "can't use testing tools before framework is initialized" ); - - if( !!pr ) - tl = PASS; - - log_level ll; - char const* prefix; - char const* suffix; - - switch( tl ) { - case PASS: - ll = log_successful_tests; - prefix = "check "; - suffix = " passed"; - break; - case WARN: - ll = log_warnings; - prefix = "condition "; - suffix = " is not satisfied"; - break; - case CHECK: - ll = log_all_errors; - prefix = "check "; - suffix = " failed"; - break; - case REQUIRE: - ll = log_fatal_errors; - prefix = "critical check "; - suffix = " failed"; - break; - default: - return true; - } - switch( ct ) { case CHECK_PRED: - unit_test_log << unit_test::log::begin( file_name, line_num ) - << ll << prefix << check_descr << suffix; - + os << prefix << assertion_descr << suffix; + if( !pr.has_empty_message() ) - unit_test_log << ". " << pr.message(); - - unit_test_log << unit_test::log::end(); + os << ". " << pr.message(); break; + case CHECK_BUILT_ASSERTION: { + os << prefix << assertion_descr << suffix; + + if( tl != PASS ) { + const_string details_message = pr.message(); + + if( !details_message.is_empty() ) { + os << details_message; + } + } + break; + } + case CHECK_MSG: - unit_test_log << unit_test::log::begin( file_name, line_num ) << ll; - if( tl == PASS ) - unit_test_log << prefix << "'" << check_descr << "'" << suffix; + os << prefix << "'" << assertion_descr << "'" << suffix; else - unit_test_log << check_descr; - - if( !pr.has_empty_message() ) - unit_test_log << ". " << pr.message(); + os << assertion_descr; - unit_test_log << unit_test::log::end(); + if( !pr.has_empty_message() ) + os << ". " << pr.message(); break; - case CHECK_EQUAL: - case CHECK_NE: - case CHECK_LT: - case CHECK_LE: - case CHECK_GT: + case CHECK_EQUAL: + case CHECK_NE: + case CHECK_LT: + case CHECK_LE: + case CHECK_GT: case CHECK_GE: { - static char const* check_str [] = { " == ", " != ", " < " , " <= ", " > " , " >= " }; - static char const* rever_str [] = { " != ", " == ", " >= ", " > " , " <= ", " < " }; - - va_list args; - - va_start( args, num_of_args ); char const* arg1_descr = va_arg( args, char const* ); lazy_ostream const* arg1_val = va_arg( args, lazy_ostream const* ); char const* arg2_descr = va_arg( args, char const* ); lazy_ostream const* arg2_val = va_arg( args, lazy_ostream const* ); - unit_test_log << unit_test::log::begin( file_name, line_num ) - << ll << prefix << arg1_descr << check_str[ct-CHECK_EQUAL] << arg2_descr << suffix; + os << prefix << arg1_descr << check_str[ct-CHECK_EQUAL] << arg2_descr << suffix; if( tl != PASS ) - unit_test_log << " [" << *arg1_val << rever_str[ct-CHECK_EQUAL] << *arg2_val << "]" ; + os << " [" << *arg1_val << rever_str[ct-CHECK_EQUAL] << *arg2_val << "]" ; - va_end( args ); - if( !pr.has_empty_message() ) - unit_test_log << ". " << pr.message(); - - unit_test_log << unit_test::log::end(); + os << ". " << pr.message(); break; } case CHECK_CLOSE: case CHECK_CLOSE_FRACTION: { - va_list args; - - va_start( args, num_of_args ); char const* arg1_descr = va_arg( args, char const* ); lazy_ostream const* arg1_val = va_arg( args, lazy_ostream const* ); char const* arg2_descr = va_arg( args, char const* ); @@ -225,151 +192,172 @@ check_impl( predicate_result const& pr, lazy_ostream const& check_descr, /* toler_descr = */ va_arg( args, char const* ); lazy_ostream const* toler_val = va_arg( args, lazy_ostream const* ); - unit_test_log << unit_test::log::begin( file_name, line_num ) << ll; - - unit_test_log << "difference{" << pr.message() << (ct == CHECK_CLOSE ? "%" : "") - << "} between " << arg1_descr << "{" << *arg1_val - << "} and " << arg2_descr << "{" << *arg2_val - << ( tl == PASS ? "} doesn't exceed " : "} exceeds " ) - << *toler_val; + os << "difference{" << pr.message() + << "} between " << arg1_descr << "{" << *arg1_val + << "} and " << arg2_descr << "{" << *arg2_val + << ( tl == PASS ? "} doesn't exceed " : "} exceeds " ) + << *toler_val; if( ct == CHECK_CLOSE ) - unit_test_log << "%"; - - va_end( args ); - - unit_test_log << unit_test::log::end(); + os << "%"; break; } case CHECK_SMALL: { - va_list args; - - va_start( args, num_of_args ); char const* arg1_descr = va_arg( args, char const* ); lazy_ostream const* arg1_val = va_arg( args, lazy_ostream const* ); /* toler_descr = */ va_arg( args, char const* ); lazy_ostream const* toler_val = va_arg( args, lazy_ostream const* ); - unit_test_log << unit_test::log::begin( file_name, line_num ) << ll; - - unit_test_log << "absolute value of " << arg1_descr << "{" << *arg1_val << "}" - << ( tl == PASS ? " doesn't exceed " : " exceeds " ) - << *toler_val; + os << "absolute value of " << arg1_descr << "{" << *arg1_val << "}" + << ( tl == PASS ? " doesn't exceed " : " exceeds " ) + << *toler_val; - va_end( args ); - if( !pr.has_empty_message() ) - unit_test_log << ". " << pr.message(); - - unit_test_log << unit_test::log::end(); + os << ". " << pr.message(); break; } case CHECK_PRED_WITH_ARGS: { - unit_test_log << unit_test::log::begin( file_name, line_num ) - << ll << prefix << check_descr; + std::vector< std::pair<char const*, lazy_ostream const*> > args_copy; + args_copy.reserve( num_args ); + for( std::size_t i = 0; i < num_args; ++i ) { + char const* desc = va_arg( args, char const* ); + lazy_ostream const* value = va_arg( args, lazy_ostream const* ); + args_copy.push_back( std::make_pair( desc, value ) ); + } + + os << prefix << assertion_descr; // print predicate call description - { - va_list args; - va_start( args, num_of_args ); - - unit_test_log << "( "; - for( std::size_t i = 0; i < num_of_args; ++i ) { - unit_test_log << va_arg( args, char const* ); - va_arg( args, lazy_ostream const* ); // skip argument value; - - if( i != num_of_args-1 ) - unit_test_log << ", "; - } - unit_test_log << " )" << suffix; - va_end( args ); + os << "( "; + for( std::size_t i = 0; i < num_args; ++i ) { + os << args_copy[i].first; + + if( i != num_args-1 ) + os << ", "; } - + os << " )" << suffix; + if( tl != PASS ) { - va_list args; - va_start( args, num_of_args ); - - unit_test_log << " for ( "; - for( std::size_t i = 0; i < num_of_args; ++i ) { - va_arg( args, char const* ); // skip argument description; - unit_test_log << *va_arg( args, lazy_ostream const* ); - - if( i != num_of_args-1 ) - unit_test_log << ", "; + os << " for ( "; + for( std::size_t i = 0; i < num_args; ++i ) { + os << *args_copy[i].second; + + if( i != num_args-1 ) + os << ", "; } - unit_test_log << " )"; - va_end( args ); + os << " )"; } - - if( !pr.has_empty_message() ) - unit_test_log << ". " << pr.message(); - unit_test_log << unit_test::log::end(); + if( !pr.has_empty_message() ) + os << ". " << pr.message(); break; } case CHECK_EQUAL_COLL: { - va_list args; - - va_start( args, num_of_args ); char const* left_begin_descr = va_arg( args, char const* ); char const* left_end_descr = va_arg( args, char const* ); char const* right_begin_descr = va_arg( args, char const* ); char const* right_end_descr = va_arg( args, char const* ); - unit_test_log << unit_test::log::begin( file_name, line_num ) - << ll << prefix - << "{ " << left_begin_descr << ", " << left_end_descr << " } == { " - << right_begin_descr << ", " << right_end_descr << " }" - << suffix; + os << prefix << "{ " << left_begin_descr << ", " << left_end_descr << " } == { " + << right_begin_descr << ", " << right_end_descr << " }" + << suffix; - va_end( args ); - if( !pr.has_empty_message() ) - unit_test_log << ". " << pr.message(); - - unit_test_log << unit_test::log::end(); + os << ". " << pr.message(); break; } case CHECK_BITWISE_EQUAL: { - va_list args; - - va_start( args, num_of_args ); char const* left_descr = va_arg( args, char const* ); char const* right_descr = va_arg( args, char const* ); - unit_test_log << unit_test::log::begin( file_name, line_num ) - << ll << prefix << left_descr << " =.= " << right_descr << suffix; + os << prefix << left_descr << " =.= " << right_descr << suffix; - va_end( args ); - if( !pr.has_empty_message() ) - unit_test_log << ". " << pr.message(); - - unit_test_log << unit_test::log::end(); + os << ". " << pr.message(); break; } } +} + +//____________________________________________________________________________// + +bool +report_assertion( assertion_result const& ar, + lazy_ostream const& assertion_descr, + const_string file_name, + std::size_t line_num, + tool_level tl, + check_type ct, + std::size_t num_args, ... ) +{ + using namespace unit_test; + + if( framework::current_test_case_id() == INV_TEST_UNIT_ID ) + BOOST_TEST_IMPL_THROW( + std::runtime_error( "can't use testing tools outside of test case implementation" ) ); + + if( !!ar ) + tl = PASS; + + log_level ll; + char const* prefix; + char const* suffix; switch( tl ) { case PASS: - framework::assertion_result( true ); + ll = log_successful_tests; + prefix = "check "; + suffix = " has passed"; + break; + case WARN: + ll = log_warnings; + prefix = "condition "; + suffix = " is not satisfied"; + break; + case CHECK: + ll = log_all_errors; + prefix = "check "; + suffix = " has failed"; + break; + case REQUIRE: + ll = log_fatal_errors; + prefix = "critical check "; + suffix = " has failed"; + break; + default: + return true; + } + + unit_test_log << unit_test::log::begin( file_name, line_num ) << ll; + va_list args; + va_start( args, num_args ); + + format_report( unit_test_log, ar, assertion_descr, tl, ct, num_args, args, prefix, suffix ); + + va_end( args ); + unit_test_log << unit_test::log::end(); + + switch( tl ) { + case PASS: + framework::assertion_result( AR_PASSED ); return true; case WARN: + framework::assertion_result( AR_TRIGGERED ); return false; case CHECK: - framework::assertion_result( false ); + framework::assertion_result( AR_FAILED ); return false; - + case REQUIRE: - framework::assertion_result( false ); + framework::assertion_result( AR_FAILED ); framework::test_unit_aborted( framework::current_test_case() ); - throw execution_aborted(); + BOOST_TEST_IMPL_THROW( execution_aborted() ); } return true; @@ -377,7 +365,51 @@ check_impl( predicate_result const& pr, lazy_ostream const& check_descr, //____________________________________________________________________________// -predicate_result +assertion_result +format_assertion_result( const_string expr_val, const_string details ) +{ + assertion_result res(false); + + bool starts_new_line = first_char( expr_val ) == '\n'; + + if( !starts_new_line && !expr_val.is_empty() ) + res.message().stream() << " [" << expr_val << "]"; + + if( !details.is_empty() ) { + if( first_char(details) != '[' ) + res.message().stream() << ". "; + else + res.message().stream() << " "; + + res.message().stream() << details; + } + + if( starts_new_line ) + res.message().stream() << "." << expr_val; + + return res; +} + +//____________________________________________________________________________// + +BOOST_TEST_DECL std::string +prod_report_format( assertion_result const& ar, unit_test::lazy_ostream const& assertion_descr, check_type ct, std::size_t num_args, ... ) +{ + std::ostringstream msg_buff; + + va_list args; + va_start( args, num_args ); + + format_report( msg_buff, ar, assertion_descr, CHECK, ct, num_args, args, "assertion ", " failed" ); + + va_end( args ); + + return msg_buff.str(); +} + +//____________________________________________________________________________// + +assertion_result equal_impl( char const* left, char const* right ) { return (left && right) ? std::strcmp( left, right ) == 0 : (left == right); @@ -387,7 +419,7 @@ equal_impl( char const* left, char const* right ) #if !defined( BOOST_NO_CWCHAR ) -predicate_result +assertion_result equal_impl( wchar_t const* left, wchar_t const* right ) { return (left && right) ? std::wcscmp( left, right ) == 0 : (left == right); @@ -406,6 +438,31 @@ is_defined_impl( const_string symbol_name, const_string symbol_value ) //____________________________________________________________________________// +// ************************************************************************** // +// ************** context_frame ************** // +// ************************************************************************** // + +context_frame::context_frame( ::boost::unit_test::lazy_ostream const& context_descr ) +: m_frame_id( unit_test::framework::add_context( context_descr, true ) ) +{ +} + +//____________________________________________________________________________// + +context_frame::~context_frame() +{ + unit_test::framework::clear_context( m_frame_id ); +} + +//____________________________________________________________________________// + +context_frame::operator bool() +{ + return true; +} + +//____________________________________________________________________________// + } // namespace tt_detail // ************************************************************************** // @@ -429,7 +486,7 @@ struct output_test_stream::Impl return res; } - void check_and_fill( predicate_result& res ) + void check_and_fill( assertion_result& res ) { if( !res.p_predicate_value ) res.message() << "Output content: \"" << m_synced_string << '\"'; @@ -448,9 +505,8 @@ output_test_stream::output_test_stream( const_string pattern_file_name, bool mat m_pimpl->m_pattern.open( pattern_file_name.begin(), m ); - BOOST_WARN_MESSAGE( m_pimpl->m_pattern.is_open(), - "Can't open pattern file " << pattern_file_name - << " for " << (match_or_save ? "reading" : "writing") ); + if( !m_pimpl->m_pattern.is_open() ) + BOOST_TEST_MESSAGE( "Can't open pattern file " << pattern_file_name << " for " << (match_or_save ? "reading" : "writing") ); } m_pimpl->m_match_or_save = match_or_save; @@ -466,12 +522,12 @@ output_test_stream::~output_test_stream() //____________________________________________________________________________// -predicate_result +assertion_result output_test_stream::is_empty( bool flush_stream ) { sync(); - result_type res( m_pimpl->m_synced_string.empty() ); + assertion_result res( m_pimpl->m_synced_string.empty() ); m_pimpl->check_and_fill( res ); @@ -483,12 +539,12 @@ output_test_stream::is_empty( bool flush_stream ) //____________________________________________________________________________// -predicate_result +assertion_result output_test_stream::check_length( std::size_t length_, bool flush_stream ) { sync(); - result_type res( m_pimpl->m_synced_string.length() == length_ ); + assertion_result res( m_pimpl->m_synced_string.length() == length_ ); m_pimpl->check_and_fill( res ); @@ -500,12 +556,12 @@ output_test_stream::check_length( std::size_t length_, bool flush_stream ) //____________________________________________________________________________// -predicate_result +assertion_result output_test_stream::is_equal( const_string arg, bool flush_stream ) { sync(); - result_type res( const_string( m_pimpl->m_synced_string ) == arg ); + assertion_result res( const_string( m_pimpl->m_synced_string ) == arg ); m_pimpl->check_and_fill( res ); @@ -517,12 +573,12 @@ output_test_stream::is_equal( const_string arg, bool flush_stream ) //____________________________________________________________________________// -predicate_result +assertion_result output_test_stream::match_pattern( bool flush_stream ) { sync(); - result_type result( true ); + assertion_result result( true ); if( !m_pimpl->m_pattern.is_open() ) { result = false; @@ -548,18 +604,18 @@ output_test_stream::match_pattern( bool flush_stream ) std::string::size_type counter = suffix_size; while( --counter ) { - char c = m_pimpl->get_char(); + char c2 = m_pimpl->get_char(); if( m_pimpl->m_pattern.fail() || m_pimpl->m_pattern.eof() ) break; - result.message() << c; + result.message() << c2; } result.message() << "..."; // skip rest of the bytes. May help for further matching - m_pimpl->m_pattern.ignore( + m_pimpl->m_pattern.ignore( static_cast<std::streamsize>( m_pimpl->m_synced_string.length() - i - suffix_size) ); break; } @@ -618,11 +674,8 @@ output_test_stream::sync() //____________________________________________________________________________// } // namespace test_tools - } // namespace boost -//____________________________________________________________________________// - #include <boost/test/detail/enable_warnings.hpp> #endif // BOOST_TEST_TEST_TOOLS_IPP_012205GER diff --git a/boost/test/impl/test_tree.ipp b/boost/test/impl/test_tree.ipp new file mode 100644 index 0000000000..712cb9ee42 --- /dev/null +++ b/boost/test/impl/test_tree.ipp @@ -0,0 +1,459 @@ +// (C) Copyright Gennadiy Rozental 2005-2014. +// 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 +/// Provides core implementation for Unit Test Framework. +/// Extensions can be provided in separate files +// *************************************************************************** + +#ifndef BOOST_TEST_UNIT_TEST_SUITE_IPP_012205GER +#define BOOST_TEST_UNIT_TEST_SUITE_IPP_012205GER + +// Boost.Test +#include <boost/detail/workaround.hpp> + +#include <boost/test/framework.hpp> +#include <boost/test/results_collector.hpp> + +#include <boost/test/tree/test_unit.hpp> +#include <boost/test/tree/visitor.hpp> +#include <boost/test/tree/traverse.hpp> +#include <boost/test/tree/auto_registration.hpp> +#include <boost/test/tree/global_fixture.hpp> + +#include <boost/test/utils/foreach.hpp> +#include <boost/test/utils/basic_cstring/io.hpp> + +#include <boost/test/unit_test_parameters.hpp> + +// Boost +#include <boost/timer.hpp> + +// STL +#include <algorithm> +#include <vector> + +#include <boost/test/detail/suppress_warnings.hpp> + +#if BOOST_WORKAROUND(__BORLANDC__, < 0x600) && BOOST_WORKAROUND(_STLPORT_VERSION, <= 0x450) + using std::rand; // rand is in std and random_shuffle is in _STL +#endif + +//____________________________________________________________________________// + +namespace boost { +namespace unit_test { + +// ************************************************************************** // +// ************** test_unit ************** // +// ************************************************************************** // + +test_unit::test_unit( const_string name, const_string file_name, std::size_t line_num, test_unit_type t ) +: p_type( t ) +, p_type_name( t == TUT_CASE ? "case" : "suite" ) +, p_file_name( file_name ) +, p_line_num( line_num ) +, p_id( INV_TEST_UNIT_ID ) +, p_parent_id( INV_TEST_UNIT_ID ) +, p_name( std::string( name.begin(), name.size() ) ) +, p_timeout( 0 ) +, p_expected_failures( 0 ) +, p_default_status( RS_INHERIT ) +, p_run_status( RS_INVALID ) +, p_sibling_rank(0) +{ +} + +//____________________________________________________________________________// + +test_unit::test_unit( const_string module_name ) +: p_type( TUT_SUITE ) +, p_type_name( "module" ) +, p_line_num( 0 ) +, p_id( INV_TEST_UNIT_ID ) +, p_parent_id( INV_TEST_UNIT_ID ) +, p_name( std::string( module_name.begin(), module_name.size() ) ) +, p_timeout( 0 ) +, p_expected_failures( 0 ) +, p_default_status( RS_INHERIT ) +, p_run_status( RS_INVALID ) +, p_sibling_rank(0) +{ +} + +//____________________________________________________________________________// + +test_unit::~test_unit() +{ + framework::deregister_test_unit( this ); +} + +//____________________________________________________________________________// + +void +test_unit::depends_on( test_unit* tu ) +{ + BOOST_TEST_SETUP_ASSERT( p_id != framework::master_test_suite().p_id, + "Can't add dependency to the master test suite" ); + + p_dependencies.value.push_back( tu->p_id ); +} + +//____________________________________________________________________________// + +void +test_unit::add_precondition( precondition_t const& pc ) +{ + p_preconditions.value.push_back( pc ); +} + +//____________________________________________________________________________// + +test_tools::assertion_result +test_unit::check_preconditions() const +{ + BOOST_TEST_FOREACH( test_unit_id, dep_id, p_dependencies.get() ) { + test_unit const& dep = framework::get( dep_id, TUT_ANY ); + + if( !dep.is_enabled() ) { + test_tools::assertion_result res(false); + res.message() << "dependency test " << dep.p_type_name << " \"" << dep.full_name() << "\" is disabled"; + return res; + } + + test_results const& test_rslt = unit_test::results_collector.results( dep_id ); + if( !test_rslt.passed() ) { + test_tools::assertion_result res(false); + res.message() << "dependency test " << dep.p_type_name << " \"" << dep.full_name() << "\" has failed"; + return res; + } + + if( test_rslt.p_test_cases_skipped > 0 ) { + test_tools::assertion_result res(false); + res.message() << "dependency test " << dep.p_type_name << " \"" << dep.full_name() << "\" has skipped test cases"; + return res; + } + } + + BOOST_TEST_FOREACH( precondition_t, precondition, p_preconditions.get() ) { + test_tools::assertion_result res = precondition( p_id ); + if( !res ) + return res; + } + + return true; +} + +//____________________________________________________________________________// + +void +test_unit::increase_exp_fail( counter_t num ) +{ + p_expected_failures.value += num; + + if( p_parent_id != INV_TEST_UNIT_ID ) + framework::get<test_suite>( p_parent_id ).increase_exp_fail( num ); +} + +//____________________________________________________________________________// + +std::string +test_unit::full_name() const +{ + if( p_parent_id == INV_TEST_UNIT_ID || p_parent_id == framework::master_test_suite().p_id ) + return p_name; + + std::string res = framework::get<test_suite>( p_parent_id ).full_name(); + res.append("/"); + + res.append( p_name ); + + return res; +} + +//____________________________________________________________________________// + +void +test_unit::add_label( const_string l ) +{ + p_labels.value.push_back( std::string() + l ); +} + +//____________________________________________________________________________// + +bool +test_unit::has_label( const_string l ) const +{ + return std::find( p_labels->begin(), p_labels->end(), l ) != p_labels->end(); +} + +//____________________________________________________________________________// + +// ************************************************************************** // +// ************** test_case ************** // +// ************************************************************************** // + +test_case::test_case( const_string name, boost::function<void ()> const& test_func ) +: test_unit( name, "", 0, static_cast<test_unit_type>(type) ) +, p_test_func( test_func ) +{ + framework::register_test_unit( this ); +} + +//____________________________________________________________________________// + +test_case::test_case( const_string name, const_string file_name, std::size_t line_num, boost::function<void ()> const& test_func ) +: test_unit( name, file_name, line_num, static_cast<test_unit_type>(type) ) +, p_test_func( test_func ) +{ + framework::register_test_unit( this ); +} + +//____________________________________________________________________________// + +// ************************************************************************** // +// ************** test_suite ************** // +// ************************************************************************** // + +//____________________________________________________________________________// + +test_suite::test_suite( const_string name, const_string file_name, std::size_t line_num ) +: test_unit( name, file_name, line_num, static_cast<test_unit_type>(type) ) +{ + framework::register_test_unit( this ); +} + +//____________________________________________________________________________// + +test_suite::test_suite( const_string module_name ) +: test_unit( module_name ) +{ + framework::register_test_unit( this ); +} + +//____________________________________________________________________________// + +void +test_suite::add( test_unit* tu, counter_t expected_failures, unsigned timeout ) +{ + tu->p_timeout.value = timeout; + + m_children.push_back( tu->p_id ); + tu->p_parent_id.value = p_id; + + if( tu->p_expected_failures != 0 ) + increase_exp_fail( tu->p_expected_failures ); + + if( expected_failures ) + tu->increase_exp_fail( expected_failures ); +} + +//____________________________________________________________________________// + +void +test_suite::add( test_unit_generator const& gen, unsigned timeout ) +{ + test_unit* tu; + while((tu = gen.next()) != 0) + add( tu, 0, timeout ); +} + +//____________________________________________________________________________// + +void +test_suite::add( test_unit_generator const& gen, decorator::collector& decorators ) +{ + test_unit* tu; + while((tu = gen.next()) != 0) { + decorators.store_in( *tu ); + add( tu, 0 ); + } + + decorators.reset(); +} + +//____________________________________________________________________________// + +void +test_suite::remove( test_unit_id id ) +{ + test_unit_id_list::iterator it = std::find( m_children.begin(), m_children.end(), id ); + + if( it != m_children.end() ) + m_children.erase( it ); +} + +//____________________________________________________________________________// + +test_unit_id +test_suite::get( const_string tu_name ) const +{ + BOOST_TEST_FOREACH( test_unit_id, id, m_children ) { + if( tu_name == framework::get( id, ut_detail::test_id_2_unit_type( id ) ).p_name.get() ) + return id; + } + + return INV_TEST_UNIT_ID; +} + +//____________________________________________________________________________// + +// ************************************************************************** // +// ************** master_test_suite ************** // +// ************************************************************************** // + +master_test_suite_t::master_test_suite_t() +: test_suite( "Master Test Suite" ) +, argc( 0 ) +, argv( 0 ) +{ + p_default_status.value = RS_ENABLED; +} + +// ************************************************************************** // +// ************** traverse_test_tree ************** // +// ************************************************************************** // + +void +traverse_test_tree( test_case const& tc, test_tree_visitor& V, bool ignore_status ) +{ + if( tc.is_enabled() || ignore_status ) + V.visit( tc ); +} + +//____________________________________________________________________________// + +void +traverse_test_tree( test_suite const& suite, test_tree_visitor& V, bool ignore_status ) +{ + // skip disabled test suite unless we asked to ignore this condition + if( !ignore_status && !suite.is_enabled() ) + return; + + // Invoke test_suite_start callback + if( !V.test_suite_start( suite ) ) + return; + + // Recurse into children + std::size_t total_children = suite.m_children.size(); + for( std::size_t i=0; i < total_children; ) { + // this statement can remove the test unit from this list + traverse_test_tree( suite.m_children[i], V, ignore_status ); + if( total_children > suite.m_children.size() ) + total_children = suite.m_children.size(); + else + ++i; + } + + // Invoke test_suite_finish callback + V.test_suite_finish( suite ); +} + +//____________________________________________________________________________// + +void +traverse_test_tree( test_unit_id id, test_tree_visitor& V, bool ignore_status ) +{ + if( ut_detail::test_id_2_unit_type( id ) == TUT_CASE ) + traverse_test_tree( framework::get<test_case>( id ), V, ignore_status ); + else + traverse_test_tree( framework::get<test_suite>( id ), V, ignore_status ); +} + +//____________________________________________________________________________// + +// ************************************************************************** // +// ************** object generators ************** // +// ************************************************************************** // + +namespace ut_detail { + +std::string +normalize_test_case_name( const_string name ) +{ + std::string norm_name( name.begin(), name.size() ); + + if( name[0] == '&' ) + norm_name = norm_name.substr( 1 ); + + std::replace(norm_name.begin(), norm_name.end(), ' ', '_'); + + return norm_name; +} + +//____________________________________________________________________________// + +// ************************************************************************** // +// ************** auto_test_unit_registrar ************** // +// ************************************************************************** // + +auto_test_unit_registrar::auto_test_unit_registrar( test_case* tc, decorator::collector& decorators, counter_t exp_fail ) +{ + framework::current_auto_test_suite().add( tc, exp_fail ); + + decorators.store_in( *tc ); + decorators.reset(); +} + +//____________________________________________________________________________// + +auto_test_unit_registrar::auto_test_unit_registrar( const_string ts_name, const_string ts_file, std::size_t ts_line, decorator::collector& decorators ) +{ + test_unit_id id = framework::current_auto_test_suite().get( ts_name ); + + test_suite* ts; + + if( id != INV_TEST_UNIT_ID ) { + ts = &framework::get<test_suite>( id ); + BOOST_ASSERT( ts->p_parent_id == framework::current_auto_test_suite().p_id ); + } + else { + ts = new test_suite( ts_name, ts_file, ts_line ); + framework::current_auto_test_suite().add( ts ); + } + + decorators.store_in( *ts ); + decorators.reset(); + + framework::current_auto_test_suite( ts ); +} + +//____________________________________________________________________________// + +auto_test_unit_registrar::auto_test_unit_registrar( test_unit_generator const& tc_gen, decorator::collector& decorators ) +{ + framework::current_auto_test_suite().add( tc_gen, decorators ); +} + +//____________________________________________________________________________// + +auto_test_unit_registrar::auto_test_unit_registrar( int ) +{ + framework::current_auto_test_suite( 0, false ); +} + +//____________________________________________________________________________// + +} // namespace ut_detail + +// ************************************************************************** // +// ************** global_fixture ************** // +// ************************************************************************** // + +global_fixture::global_fixture() +{ + framework::register_observer( *this ); +} + +//____________________________________________________________________________// + +} // namespace unit_test +} // namespace boost + +#include <boost/test/detail/enable_warnings.hpp> + +#endif // BOOST_TEST_UNIT_TEST_SUITE_IPP_012205GER diff --git a/boost/test/impl/unit_test_log.ipp b/boost/test/impl/unit_test_log.ipp index 7cb4f4b4a8..f202f5027d 100644 --- a/boost/test/impl/unit_test_log.ipp +++ b/boost/test/impl/unit_test_log.ipp @@ -1,4 +1,4 @@ -// (C) Copyright Gennadiy Rozental 2005-2008. +// (C) Copyright Gennadiy Rozental 2005-2014. // 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) @@ -18,10 +18,10 @@ // Boost.Test #include <boost/test/unit_test_log.hpp> #include <boost/test/unit_test_log_formatter.hpp> -#include <boost/test/unit_test_suite_impl.hpp> #include <boost/test/execution_monitor.hpp> +#include <boost/test/framework.hpp> -#include <boost/test/detail/unit_test_parameters.hpp> +#include <boost/test/unit_test_parameters.hpp> #include <boost/test/utils/basic_cstring/compare.hpp> @@ -38,7 +38,6 @@ typedef ::boost::io::ios_base_all_saver io_saver_type; //____________________________________________________________________________// namespace boost { - namespace unit_test { // ************************************************************************** // @@ -57,7 +56,7 @@ entry_value_collector::operator<<( lazy_ostream const& v ) const //____________________________________________________________________________// -entry_value_collector const& +entry_value_collector const& entry_value_collector::operator<<( const_string v ) const { unit_test_log << v; @@ -194,7 +193,7 @@ unit_test_log_t::test_unit_finish( test_unit const& tu, unsigned long elapsed ) //____________________________________________________________________________// void -unit_test_log_t::test_unit_skipped( test_unit const& tu ) +unit_test_log_t::test_unit_skipped( test_unit const& tu, const_string reason ) { if( s_log_impl().m_threshold_level > log_test_units ) return; @@ -202,23 +201,7 @@ unit_test_log_t::test_unit_skipped( test_unit const& tu ) if( s_log_impl().m_entry_in_progress ) *this << log::end(); - s_log_impl().m_log_formatter->test_unit_skipped( s_log_impl().stream(), tu ); -} - -//____________________________________________________________________________// - -void -unit_test_log_t::test_unit_aborted( test_unit const& ) -{ - // do nothing -} - -//____________________________________________________________________________// - -void -unit_test_log_t::assertion_result( bool ) -{ - // do nothing + s_log_impl().m_log_formatter->test_unit_skipped( s_log_impl().stream(), tu, reason ); } //____________________________________________________________________________// @@ -235,8 +218,14 @@ unit_test_log_t::exception_caught( execution_exception const& ex ) if( s_log_impl().m_entry_in_progress ) *this << log::end(); - s_log_impl().m_log_formatter->log_exception( s_log_impl().stream(), s_log_impl().m_checkpoint_data, ex ); + s_log_impl().m_log_formatter->log_exception_start( s_log_impl().stream(), s_log_impl().m_checkpoint_data, ex ); + + log_entry_context( l ); + + s_log_impl().m_log_formatter->log_exception_finish( s_log_impl().stream() ); } + + clear_entry_context(); } //____________________________________________________________________________// @@ -254,7 +243,7 @@ set_unix_slash( char in ) { return in == '\\' ? '/' : in; } - + unit_test_log_t& unit_test_log_t::operator<<( log::begin const& b ) { @@ -282,10 +271,15 @@ unit_test_log_t::operator<<( log::begin const& b ) unit_test_log_t& unit_test_log_t::operator<<( log::end const& ) { - if( s_log_impl().m_entry_in_progress ) + if( s_log_impl().m_entry_in_progress ) { + log_entry_context( s_log_impl().m_entry_data.m_level ); + s_log_impl().m_log_formatter->log_entry_finish( s_log_impl().stream() ); - s_log_impl().m_entry_in_progress = false; + s_log_impl().m_entry_in_progress = false; + } + + clear_entry_context(); return *this; } @@ -315,7 +309,7 @@ unit_test_log_t::operator()( log_level l ) bool unit_test_log_t::log_entry_start() { - if( s_log_impl().m_entry_in_progress ) + if( s_log_impl().m_entry_in_progress ) return true; switch( s_log_impl().m_entry_data.m_level ) { @@ -377,6 +371,33 @@ unit_test_log_t::operator<<( lazy_ostream const& value ) //____________________________________________________________________________// void +unit_test_log_t::log_entry_context( log_level l ) +{ + framework::context_generator const& context = framework::get_context(); + if( context.is_empty() ) + return; + + const_string frame; + + s_log_impl().m_log_formatter->entry_context_start( s_log_impl().stream(), l ); + + while( !(frame=context.next()).is_empty() ) + s_log_impl().m_log_formatter->log_entry_context( s_log_impl().stream(), frame ); + + s_log_impl().m_log_formatter->entry_context_finish( s_log_impl().stream() ); +} + +//____________________________________________________________________________// + +void +unit_test_log_t::clear_entry_context() +{ + framework::clear_context(); +} + +//____________________________________________________________________________// + +void unit_test_log_t::set_stream( std::ostream& str ) { if( s_log_impl().m_entry_in_progress ) @@ -405,10 +426,15 @@ unit_test_log_t::set_format( output_format log_format ) if( s_log_impl().m_entry_in_progress ) return; - if( log_format == CLF ) + switch( log_format ) { + default: + case OF_CLF: set_formatter( new output::compiler_log_formatter ); - else + break; + case OF_XML: set_formatter( new output::xml_log_formatter ); + break; + } } //____________________________________________________________________________// @@ -434,11 +460,8 @@ unit_test_log_formatter::log_entry_value( std::ostream& ostr, lazy_ostream const //____________________________________________________________________________// } // namespace unit_test - } // namespace boost -//____________________________________________________________________________// - #include <boost/test/detail/enable_warnings.hpp> #endif // BOOST_TEST_UNIT_TEST_LOG_IPP_012205GER diff --git a/boost/test/impl/unit_test_main.ipp b/boost/test/impl/unit_test_main.ipp index adedf35180..327e14de30 100644 --- a/boost/test/impl/unit_test_main.ipp +++ b/boost/test/impl/unit_test_main.ipp @@ -1,4 +1,4 @@ -// (C) Copyright Gennadiy Rozental 2001-2008. +// (C) Copyright Gennadiy Rozental 2001-2014. // 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) @@ -18,154 +18,164 @@ // Boost.Test #include <boost/test/framework.hpp> #include <boost/test/results_collector.hpp> -#include <boost/test/unit_test_suite_impl.hpp> #include <boost/test/results_reporter.hpp> -#include <boost/test/detail/unit_test_parameters.hpp> +#include <boost/test/tree/visitor.hpp> +#include <boost/test/tree/test_unit.hpp> +#include <boost/test/tree/traverse.hpp> -#if !defined(__BORLANDC__) && !BOOST_WORKAROUND( BOOST_MSVC, < 1300 ) && !BOOST_WORKAROUND( __SUNPRO_CC, < 0x5100 ) -#define BOOST_TEST_SUPPORT_RUN_BY_NAME -#include <boost/test/utils/iterator/token_iterator.hpp> -#endif +#include <boost/test/unit_test_parameters.hpp> + +#include <boost/test/utils/foreach.hpp> +#include <boost/test/utils/basic_cstring/io.hpp> // Boost #include <boost/cstdlib.hpp> -#include <boost/bind.hpp> // STL +#include <cstdio> #include <stdexcept> #include <iostream> +#include <iomanip> +#include <set> #include <boost/test/detail/suppress_warnings.hpp> //____________________________________________________________________________// namespace boost { - namespace unit_test { +namespace ut_detail { + // ************************************************************************** // -// ************** test_case_filter ************** // +// ************** hrf_content_reporter ************** // // ************************************************************************** // -class test_case_filter : public test_tree_visitor { -public: - struct single_filter { - single_filter( const_string in ) - { - if( in == "*" ) - m_kind = SFK_ALL; - else if( first_char( in ) == '*' && last_char( in ) == '*' ) { - m_kind = SFK_SUBSTR; - m_value = in.substr( 1, in.size()-1 ); - } - else if( first_char( in ) == '*' ) { - m_kind = SFK_TRAILING; - m_value = in.substr( 1 ); - } - else if( last_char( in ) == '*' ) { - m_kind = SFK_LEADING; - m_value = in.substr( 0, in.size()-1 ); - } - else { - m_kind = SFK_MATCH; - m_value = in; - } - }; +struct hrf_content_reporter : test_tree_visitor { + explicit hrf_content_reporter( std::ostream& os ) : m_os( os ), m_indent( -4 ) {} // skip master test suite - bool pass( test_unit const& tu ) const - { - const_string name( tu.p_name ); - - switch( m_kind ) { - default: - case SFK_ALL: - return true; +private: + void report_test_unit( test_unit const& tu ) + { + m_os << std::setw( m_indent ) << "" << tu.p_name; + m_os << (tu.p_default_status == test_unit::RS_ENABLED ? "*" : " "); + //m_os << '[' << tu.p_sibling_rank << ']'; + if( !tu.p_description->empty() ) + m_os << ": " << tu.p_description; - case SFK_LEADING: - return name.substr( 0, m_value.size() ) == m_value; + m_os << "\n"; + } + virtual void visit( test_case const& tc ) { report_test_unit( tc ); } + virtual bool test_suite_start( test_suite const& ts ) + { + if( m_indent >= 0 ) + report_test_unit( ts ); + m_indent += 4; + return true; + } + virtual void test_suite_finish( test_suite const& ) + { + m_indent -= 4; + } - case SFK_TRAILING: - return name.size() >= m_value.size() && name.substr( name.size() - m_value.size() ) == m_value; + // Data members + std::ostream& m_os; + int m_indent; +}; - case SFK_SUBSTR: - return name.find( m_value ) != const_string::npos; +// ************************************************************************** // +// ************** dot_content_reporter ************** // +// ************************************************************************** // - case SFK_MATCH: - return m_value == tu.p_name.get(); - } - } - enum kind { SFK_ALL, SFK_LEADING, SFK_TRAILING, SFK_SUBSTR, SFK_MATCH }; - - kind m_kind; - const_string m_value; - }; - // Constructor -#ifndef BOOST_TEST_SUPPORT_RUN_BY_NAME - explicit test_case_filter( const_string ) : m_depth( 0 ) {} -#else - explicit test_case_filter( const_string tc_to_run ) - : m_depth( 0 ) +struct dot_content_reporter : test_tree_visitor { + explicit dot_content_reporter( std::ostream& os ) : m_os( os ) {} + +private: + void report_test_unit( test_unit const& tu ) { - string_token_iterator tit( tc_to_run, (dropped_delimeters = "/", kept_delimeters = dt_none) ); + bool master_ts = tu.p_parent_id == INV_TEST_UNIT_ID; - while( tit != string_token_iterator() ) { - m_filters.push_back( - std::vector<single_filter>( string_token_iterator( *tit, (dropped_delimeters = ",", kept_delimeters = dt_none) ), - string_token_iterator() ) ); + m_os << "tu" << tu.p_id; - ++tit; - } - } -#endif - - void filter_unit( test_unit const& tu ) - { - if( (++m_depth - 1) > m_filters.size() ) { - tu.p_enabled.value = true; - return; - } + m_os << (master_ts ? "[shape=ellipse,peripheries=2" : "[shape=Mrecord" ); - if( m_depth == 1 ) - return; + m_os << ",fontname=Helvetica"; - std::vector<single_filter> const& filters = m_filters[m_depth-2]; + m_os << (tu.is_enabled() ? ",color=green" : ",color=yellow"); - tu.p_enabled.value = - std::find_if( filters.begin(), filters.end(), bind( &single_filter::pass, _1, boost::ref(tu) ) ) != filters.end(); - } + if( master_ts ) + m_os << ",label=\"" << tu.p_name << "\"];\n"; + else { + m_os << ",label=\"" << tu.p_name << "|" << tu.p_file_name << "(" << tu.p_line_num << ")"; + if( tu.p_timeout > 0 ) + m_os << "|timeout=" << tu.p_timeout; + if( tu.p_expected_failures != 0 ) + m_os << "|expected failures=" << tu.p_expected_failures; + if( !tu.p_labels->empty() ) { + m_os << "|labels:"; - // test tree visitor interface - virtual void visit( test_case const& tc ) - { - if( m_depth < m_filters.size() ) { - tc.p_enabled.value = false; - return; + BOOST_TEST_FOREACH( std::string const&, l, tu.p_labels.get() ) + m_os << " @" << l; + } + m_os << "\"];\n"; } - filter_unit( tc ); + if( !master_ts ) + m_os << "tu" << tu.p_parent_id << " -> " << "tu" << tu.p_id << ";\n"; - --m_depth; - } + BOOST_TEST_FOREACH( test_unit_id, dep_id, tu.p_dependencies.get() ) { + test_unit const& dep = framework::get( dep_id, TUT_ANY ); - virtual bool test_suite_start( test_suite const& ts ) + m_os << "tu" << tu.p_id << " -> " << "tu" << dep.p_id << "[color=red,style=dotted,constraint=false];\n"; + } + + } + virtual void visit( test_case const& tc ) { - filter_unit( ts ); + report_test_unit( tc ); + } + virtual bool test_suite_start( test_suite const& ts ) + { + if( ts.p_parent_id == INV_TEST_UNIT_ID ) + m_os << "digraph G {rankdir=LR;\n"; - if( !ts.p_enabled ) - --m_depth; + report_test_unit( ts ); - return ts.p_enabled; + m_os << "{\n"; + + return true; + } + virtual void test_suite_finish( test_suite const& ts ) + { + m_os << "}\n"; + if( ts.p_parent_id == INV_TEST_UNIT_ID ) + m_os << "}\n"; } - virtual void test_suite_finish( test_suite const& ) { --m_depth; } + std::ostream& m_os; +}; + +// ************************************************************************** // +// ************** labels_collector ************** // +// ************************************************************************** // + +struct labels_collector : test_tree_visitor { + std::set<std::string> const& labels() const { return m_labels; } private: + virtual bool visit( test_unit const& tu ) + { + m_labels.insert( tu.p_labels->begin(), tu.p_labels->end() ); + return true; + } + // Data members - std::vector<std::vector<single_filter> > m_filters; - unsigned m_depth; + std::set<std::string> m_labels; }; +} // namespace ut_detail + // ************************************************************************** // // ************** unit_test_main ************** // // ************************************************************************** // @@ -173,45 +183,81 @@ private: int BOOST_TEST_DECL unit_test_main( init_unit_test_func init_func, int argc, char* argv[] ) { - try { + int result_code = 0; + + BOOST_TEST_IMPL_TRY { framework::init( init_func, argc, argv ); - if( !runtime_config::test_to_run().is_empty() ) { - test_case_filter filter( runtime_config::test_to_run() ); + if( runtime_config::wait_for_debugger() ) { + results_reporter::get_stream() << "Press any key to continue..." << std::endl; + + std::getchar(); + results_reporter::get_stream() << "Continuing..." << std::endl; + } + + framework::finalize_setup_phase(); + + if( runtime_config::list_content() != unit_test::OF_INVALID ) { + if( runtime_config::list_content() == unit_test::OF_DOT ) { + ut_detail::dot_content_reporter reporter( results_reporter::get_stream() ); + + traverse_test_tree( framework::master_test_suite().p_id, reporter, true ); + } + else { + ut_detail::hrf_content_reporter reporter( results_reporter::get_stream() ); + + traverse_test_tree( framework::master_test_suite().p_id, reporter, true ); + } - traverse_test_tree( framework::master_test_suite().p_id, filter ); + return boost::exit_success; + } + + if( runtime_config::list_labels() ) { + ut_detail::labels_collector collector; + + traverse_test_tree( framework::master_test_suite().p_id, collector, true ); + + results_reporter::get_stream() << "Available labels:\n "; + std::copy( collector.labels().begin(), collector.labels().end(), + std::ostream_iterator<std::string>( results_reporter::get_stream(), "\n " ) ); + results_reporter::get_stream() << "\n"; + + return boost::exit_success; } framework::run(); results_reporter::make_report(); - return runtime_config::no_result_code() - ? boost::exit_success - : results_collector.results( framework::master_test_suite().p_id ).result_code(); + result_code = runtime_config::no_result_code() + ? boost::exit_success + : results_collector.results( framework::master_test_suite().p_id ).result_code(); } - catch( framework::nothing_to_test const& ) { - return boost::exit_success; + BOOST_TEST_IMPL_CATCH0( framework::nothing_to_test ) { + result_code = boost::exit_success; } - catch( framework::internal_error const& ex ) { + BOOST_TEST_IMPL_CATCH( framework::internal_error, ex ) { results_reporter::get_stream() << "Boost.Test framework internal error: " << ex.what() << std::endl; - - return boost::exit_exception_failure; + + result_code = boost::exit_exception_failure; } - catch( framework::setup_error const& ex ) { + BOOST_TEST_IMPL_CATCH( framework::setup_error, ex ) { results_reporter::get_stream() << "Test setup error: " << ex.what() << std::endl; - - return boost::exit_exception_failure; + + result_code = boost::exit_exception_failure; } - catch( ... ) { + BOOST_TEST_IMPL_CATCHALL() { results_reporter::get_stream() << "Boost.Test framework internal error: unknown reason" << std::endl; - - return boost::exit_exception_failure; + + result_code = boost::exit_exception_failure; } + + framework::shutdown(); + + return result_code; } } // namespace unit_test - } // namespace boost #if !defined(BOOST_TEST_DYN_LINK) && !defined(BOOST_TEST_NO_MAIN) diff --git a/boost/test/impl/unit_test_monitor.ipp b/boost/test/impl/unit_test_monitor.ipp index dc912f544e..8c931f203f 100644 --- a/boost/test/impl/unit_test_monitor.ipp +++ b/boost/test/impl/unit_test_monitor.ipp @@ -1,4 +1,4 @@ -// (C) Copyright Gennadiy Rozental 2005-2008. +// (C) Copyright Gennadiy Rozental 2005-2014. // 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) @@ -18,57 +18,34 @@ // Boost.Test #include <boost/test/unit_test_monitor.hpp> -#include <boost/test/unit_test_suite_impl.hpp> -#include <boost/test/test_tools.hpp> #include <boost/test/framework.hpp> - -#include <boost/test/detail/unit_test_parameters.hpp> +#include <boost/test/tree/test_unit.hpp> +#include <boost/test/unit_test_parameters.hpp> #include <boost/test/detail/suppress_warnings.hpp> //____________________________________________________________________________// namespace boost { - namespace unit_test { -namespace { - -template<typename F> -struct zero_return_wrapper_t { - explicit zero_return_wrapper_t( F const& f ) : m_f( f ) {} - - int operator()() { m_f(); return 0; } - - F const& m_f; -}; - -template<typename F> -zero_return_wrapper_t<F> -zero_return_wrapper( F const& f ) -{ - return zero_return_wrapper_t<F>( f ); -} - -} - // ************************************************************************** // // ************** unit_test_monitor ************** // // ************************************************************************** // unit_test_monitor_t::error_level -unit_test_monitor_t::execute_and_translate( test_case const& tc ) +unit_test_monitor_t::execute_and_translate( boost::function<void ()> const& func, unsigned timeout ) { - try { + BOOST_TEST_IMPL_TRY { p_catch_system_errors.value = runtime_config::catch_sys_errors(); - p_timeout.value = tc.p_timeout.get(); + p_timeout.value = timeout; p_auto_start_dbg.value = runtime_config::auto_start_dbg(); p_use_alt_stack.value = runtime_config::use_alt_stack(); p_detect_fp_exceptions.value = runtime_config::detect_fp_exceptions(); - execute( callback0<int>( zero_return_wrapper( tc.test_func() ) ) ); + vexecute( func ); } - catch( execution_exception const& ex ) { + BOOST_TEST_IMPL_CATCH( execution_exception, ex ) { framework::exception_caught( ex ); framework::test_unit_aborted( framework::current_test_case() ); @@ -91,11 +68,8 @@ unit_test_monitor_t::execute_and_translate( test_case const& tc ) //____________________________________________________________________________// } // namespace unit_test - } // namespace boost -//____________________________________________________________________________// - #include <boost/test/detail/enable_warnings.hpp> #endif // BOOST_TEST_UNIT_TEST_MONITOR_IPP_012205GER diff --git a/boost/test/impl/unit_test_parameters.ipp b/boost/test/impl/unit_test_parameters.ipp index f220792b34..2ffa495e67 100644 --- a/boost/test/impl/unit_test_parameters.ipp +++ b/boost/test/impl/unit_test_parameters.ipp @@ -1,4 +1,4 @@ -// (C) Copyright Gennadiy Rozental 2001-2008. +// (C) Copyright Gennadiy Rozental 2001-2014. // 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) @@ -19,7 +19,7 @@ #define BOOST_TEST_UNIT_TEST_PARAMETERS_IPP_012205GER // Boost.Test -#include <boost/test/detail/unit_test_parameters.hpp> +#include <boost/test/unit_test_parameters.hpp> #include <boost/test/utils/basic_cstring/basic_cstring.hpp> #include <boost/test/utils/basic_cstring/compare.hpp> #include <boost/test/utils/basic_cstring/io.hpp> @@ -27,6 +27,8 @@ #include <boost/test/debug.hpp> #include <boost/test/framework.hpp> +#include <boost/test/detail/throw_exception.hpp> + // Boost.Runtime.Param #include <boost/test/utils/runtime/cla/dual_name_parameter.hpp> #include <boost/test/utils/runtime/cla/parser.hpp> @@ -34,14 +36,12 @@ namespace rt = boost::runtime; namespace cla = rt::cla; - #ifndef UNDER_CE #include <boost/test/utils/runtime/env/variable.hpp> namespace env = rt::env; #endif - // Boost #include <boost/config.hpp> #include <boost/test/detail/suppress_warnings.hpp> @@ -63,7 +63,6 @@ namespace std { using ::getenv; using ::strncmp; using ::strcmp; } # endif namespace boost { - namespace unit_test { // ************************************************************************** // @@ -127,18 +126,19 @@ std::istream& operator>>( std::istream& in, unit_test::output_format& of ) { fixed_mapping<const_string,unit_test::output_format,case_ins_less<char const> > output_format_name ( - "HRF", unit_test::CLF, - "CLF", unit_test::CLF, - "XML", unit_test::XML, + "HRF", unit_test::OF_CLF, + "CLF", unit_test::OF_CLF, + "XML", unit_test::OF_XML, + "DOT", unit_test::OF_DOT, - unit_test::INV_OF + unit_test::OF_INVALID ); std::string val; in >> val; of = output_format_name[val]; - BOOST_TEST_SETUP_ASSERT( of != unit_test::INV_OF, "invalid output format " + val ); + BOOST_TEST_SETUP_ASSERT( of != unit_test::OF_INVALID, "invalid output format " + val ); return in; } @@ -158,8 +158,11 @@ std::string AUTO_START_DBG = "auto_start_dbg"; std::string BREAK_EXEC_PATH = "break_exec_path"; std::string BUILD_INFO = "build_info"; std::string CATCH_SYS_ERRORS = "catch_system_errors"; +std::string COLOR_OUTPUT = "color_output"; std::string DETECT_FP_EXCEPT = "detect_fp_exceptions"; std::string DETECT_MEM_LEAKS = "detect_memory_leaks"; +std::string LIST_CONTENT = "list_content"; +std::string LIST_LABELS = "list_labels"; std::string LOG_FORMAT = "log_format"; std::string LOG_LEVEL = "log_level"; std::string LOG_SINK = "log_sink"; @@ -173,39 +176,55 @@ std::string TESTS_TO_RUN = "run_test"; std::string SAVE_TEST_PATTERN = "save_pattern"; std::string SHOW_PROGRESS = "show_progress"; std::string USE_ALT_STACK = "use_alt_stack"; +std::string WAIT_FOR_DEBUGGER = "wait_for_debugger"; + +static const_string +parameter_2_env_var( const_string param_name ) +{ + typedef std::map<const_string,const_string> mtype; + static mtype s_mapping; + + if( s_mapping.empty() ) { + s_mapping[AUTO_START_DBG] = "BOOST_TEST_AUTO_START_DBG"; + s_mapping[BREAK_EXEC_PATH] = "BOOST_TEST_BREAK_EXEC_PATH"; + s_mapping[BUILD_INFO] = "BOOST_TEST_BUILD_INFO"; + s_mapping[CATCH_SYS_ERRORS] = "BOOST_TEST_CATCH_SYSTEM_ERRORS"; + s_mapping[COLOR_OUTPUT] = "BOOST_TEST_COLOR_OUTPUT"; + s_mapping[DETECT_FP_EXCEPT] = "BOOST_TEST_DETECT_FP_EXCEPTIONS"; + s_mapping[DETECT_MEM_LEAKS] = "BOOST_TEST_DETECT_MEMORY_LEAK"; + s_mapping[LIST_CONTENT] = "BOOST_TEST_LIST_CONTENT"; + s_mapping[LIST_CONTENT] = "BOOST_TEST_LIST_LABELS"; + s_mapping[LOG_FORMAT] = "BOOST_TEST_LOG_FORMAT"; + s_mapping[LOG_LEVEL] = "BOOST_TEST_LOG_LEVEL"; + s_mapping[LOG_SINK] = "BOOST_TEST_LOG_SINK"; + s_mapping[OUTPUT_FORMAT] = "BOOST_TEST_OUTPUT_FORMAT"; + s_mapping[RANDOM_SEED] = "BOOST_TEST_RANDOM"; + s_mapping[REPORT_FORMAT] = "BOOST_TEST_REPORT_FORMAT"; + s_mapping[REPORT_LEVEL] = "BOOST_TEST_REPORT_LEVEL"; + s_mapping[REPORT_SINK] = "BOOST_TEST_REPORT_SINK"; + s_mapping[RESULT_CODE] = "BOOST_TEST_RESULT_CODE"; + s_mapping[TESTS_TO_RUN] = "BOOST_TESTS_TO_RUN"; + s_mapping[SAVE_TEST_PATTERN] = "BOOST_TEST_SAVE_PATTERN"; + s_mapping[SHOW_PROGRESS] = "BOOST_TEST_SHOW_PROGRESS"; + s_mapping[USE_ALT_STACK] = "BOOST_TEST_USE_ALT_STACK"; + s_mapping[WAIT_FOR_DEBUGGER] = "BOOST_TEST_WAIT_FOR_DEBUGGER"; + } -fixed_mapping<const_string,const_string> parameter_2_env_var( - AUTO_START_DBG , "BOOST_TEST_AUTO_START_DBG", - BREAK_EXEC_PATH , "BOOST_TEST_BREAK_EXEC_PATH", - BUILD_INFO , "BOOST_TEST_BUILD_INFO", - CATCH_SYS_ERRORS , "BOOST_TEST_CATCH_SYSTEM_ERRORS", - DETECT_FP_EXCEPT , "BOOST_TEST_DETECT_FP_EXCEPTIONS", - DETECT_MEM_LEAKS , "BOOST_TEST_DETECT_MEMORY_LEAK", - LOG_FORMAT , "BOOST_TEST_LOG_FORMAT", - LOG_LEVEL , "BOOST_TEST_LOG_LEVEL", - LOG_SINK , "BOOST_TEST_LOG_SINK", - OUTPUT_FORMAT , "BOOST_TEST_OUTPUT_FORMAT", - RANDOM_SEED , "BOOST_TEST_RANDOM", - REPORT_FORMAT , "BOOST_TEST_REPORT_FORMAT", - REPORT_LEVEL , "BOOST_TEST_REPORT_LEVEL", - REPORT_SINK , "BOOST_TEST_REPORT_SINK", - RESULT_CODE , "BOOST_TEST_RESULT_CODE", - TESTS_TO_RUN , "BOOST_TESTS_TO_RUN", - SAVE_TEST_PATTERN , "BOOST_TEST_SAVE_PATTERN", - SHOW_PROGRESS , "BOOST_TEST_SHOW_PROGRESS", - USE_ALT_STACK , "BOOST_TEST_USE_ALT_STACK", - - "" -); + mtype::const_iterator it = s_mapping.find( param_name ); + + return it == s_mapping.end() ? const_string() : it->second; +} //____________________________________________________________________________// // storage for the CLAs -cla::parser s_cla_parser; -std::string s_empty; +cla::parser s_cla_parser; +std::string s_empty; + +output_format s_report_format; +output_format s_log_format; -output_format s_report_format; -output_format s_log_format; +std::list<std::string> s_test_to_run; //____________________________________________________________________________// @@ -229,7 +248,7 @@ retrieve_parameter( const_string parameter_name, cla::parser const& s_cla_parser boost::optional<T> v; #ifndef UNDER_CE - env::get( parameter_2_env_var[parameter_name], v ); + env::get( parameter_2_env_var(parameter_name), v ); #endif if( v ) @@ -240,101 +259,127 @@ retrieve_parameter( const_string parameter_name, cla::parser const& s_cla_parser //____________________________________________________________________________// -} // local namespace +void +disable_use( cla::parameter const&, std::string const& ) +{ + BOOST_TEST_SETUP_ASSERT( false, "parameter break_exec_path is disabled in this release" ); +} + +//____________________________________________________________________________// + +} // local namespace void init( int& argc, char** argv ) { using namespace cla; - try { - s_cla_parser - cla::ignore_mismatch - << cla::dual_name_parameter<bool>( AUTO_START_DBG + "|d" ) - - (cla::prefix = "--|-",cla::separator = "=| ",cla::guess_name,cla::optional, - cla::description = "Automatically starts debugger if system level error (signal) occurs") - << cla::named_parameter<std::string>( BREAK_EXEC_PATH ) - - (cla::prefix = "--",cla::separator = "=",cla::guess_name,cla::optional, - cla::description = "For the exception safety testing allows to break at specific execution path") - << cla::dual_name_parameter<bool>( BUILD_INFO + "|i" ) - - (cla::prefix = "--|-",cla::separator = "=| ",cla::guess_name,cla::optional, - cla::description = "Shows library build information" ) - << cla::dual_name_parameter<bool>( CATCH_SYS_ERRORS + "|s" ) - - (cla::prefix = "--|-",cla::separator = "=| ",cla::guess_name,cla::optional, - cla::description = "Allows to switch between catching and ignoring system errors (signals)") - << cla::named_parameter<bool>( DETECT_FP_EXCEPT ) - - (cla::prefix = "--",cla::separator = "=",cla::guess_name,cla::optional, - cla::description = "Allows to switch between catching and ignoring floating point exceptions") - << cla::named_parameter<long>( DETECT_MEM_LEAKS ) - - (cla::prefix = "--",cla::separator = "=",cla::guess_name,cla::optional, - cla::description = "Allows to switch between catching and ignoring memory leaks") - << cla::dual_name_parameter<unit_test::output_format>( LOG_FORMAT + "|f" ) - - (cla::prefix = "--|-",cla::separator = "=| ",cla::guess_name,cla::optional, - cla::description = "Specifies log format") - << cla::dual_name_parameter<unit_test::log_level>( LOG_LEVEL + "|l" ) - - (cla::prefix = "--|-",cla::separator = "=| ",cla::guess_name,cla::optional, - cla::description = "Specifies log level") - << cla::dual_name_parameter<std::string>( LOG_SINK + "|k" ) - - (cla::prefix = "--|-",cla::separator = "=| ",cla::guess_name,cla::optional, - cla::description = "Specifies log sink:stdout(default),stderr or file name") - << cla::dual_name_parameter<unit_test::output_format>( OUTPUT_FORMAT + "|o" ) - - (cla::prefix = "--|-",cla::separator = "=| ",cla::guess_name,cla::optional, - cla::description = "Specifies output format (both log and report)") - << cla::dual_name_parameter<int>( RANDOM_SEED + "|a" ) - - (cla::prefix = "--|-",cla::separator = "=| ",cla::guess_name,cla::optional,cla::optional_value, - cla::description = "Allows to switch between sequential and random order of test units execution.\n" - "Optionally allows to specify concrete seed for random number generator") - << cla::dual_name_parameter<unit_test::output_format>( REPORT_FORMAT + "|m" ) - - (cla::prefix = "--|-",cla::separator = "=| ",cla::guess_name,cla::optional, - cla::description = "Specifies report format") - << cla::dual_name_parameter<unit_test::report_level>(REPORT_LEVEL + "|r") - - (cla::prefix = "--|-",cla::separator = "=| ",cla::guess_name,cla::optional, - cla::description = "Specifies report level") - << cla::dual_name_parameter<std::string>( REPORT_SINK + "|e" ) - - (cla::prefix = "--|-",cla::separator = "=| ",cla::guess_name,cla::optional, - cla::description = "Specifies report sink:stderr(default),stdout or file name") - << cla::dual_name_parameter<bool>( RESULT_CODE + "|c" ) - - (cla::prefix = "--|-",cla::separator = "=| ",cla::guess_name,cla::optional, - cla::description = "Allows to disable test modules's result code generation") - << cla::dual_name_parameter<std::string>( TESTS_TO_RUN + "|t" ) - - (cla::prefix = "--|-",cla::separator = "=| ",cla::guess_name,cla::optional, - cla::description = "Allows to filter which test units to run") - << cla::named_parameter<bool>( SAVE_TEST_PATTERN ) - - (cla::prefix = "--",cla::separator = "=",cla::guess_name,cla::optional, - cla::description = "Allows to switch between saving and matching against test pattern file") - << cla::dual_name_parameter<bool>( SHOW_PROGRESS + "|p" ) - - (cla::prefix = "--|-",cla::separator = "=| ",cla::guess_name,cla::optional, - cla::description = "Turns on progress display") - << cla::named_parameter<bool>( USE_ALT_STACK ) - - (cla::prefix = "--",cla::separator = "=",cla::guess_name,cla::optional, - cla::description = "Turns on/off usage of an alternative stack for signal handling") - - << cla::dual_name_parameter<bool>( "help|?" ) - - (cla::prefix = "--|-",cla::separator = "=",cla::guess_name,cla::optional, - cla::description = "this help message") - ; + BOOST_TEST_IMPL_TRY { + if( s_cla_parser.num_params() != 0 ) + s_cla_parser.reset(); + else + s_cla_parser - cla::ignore_mismatch + << cla::dual_name_parameter<bool>( AUTO_START_DBG + "|d" ) + - (cla::prefix = "--|-",cla::separator = "=| ",cla::guess_name,cla::optional, + cla::description = "Automatically starts debugger if system level error (signal) occurs") + << cla::named_parameter<std::string>( BREAK_EXEC_PATH ) + - (cla::prefix = "--",cla::separator = "=",cla::guess_name,cla::optional, + cla::description = "For the exception safety testing allows to break at specific execution path", + cla::handler = &disable_use) + << cla::dual_name_parameter<bool>( BUILD_INFO + "|i" ) + - (cla::prefix = "--|-",cla::separator = "=| ",cla::guess_name,cla::optional, + cla::description = "Shows library build information" ) + << cla::dual_name_parameter<bool>( CATCH_SYS_ERRORS + "|s" ) + - (cla::prefix = "--|-",cla::separator = "=| ",cla::guess_name,cla::optional, + cla::description = "Allows to switch between catching and ignoring system errors (signals)") + << cla::dual_name_parameter<bool>( COLOR_OUTPUT + "|x" ) + - (cla::prefix = "--|-",cla::separator = "=| ",cla::guess_name,cla::optional, + cla::description = "Allows to switch between catching and ignoring system errors (signals)") + << cla::named_parameter<bool>( DETECT_FP_EXCEPT ) + - (cla::prefix = "--",cla::separator = "=",cla::guess_name,cla::optional, + cla::description = "Allows to switch between catching and ignoring floating point exceptions") + << cla::named_parameter<std::string>( DETECT_MEM_LEAKS ) + - (cla::prefix = "--",cla::separator = "=",cla::guess_name,cla::optional,cla::optional_value, + cla::description = "Allows to switch between catching and ignoring memory leaks") + << cla::dual_name_parameter<unit_test::output_format>( LOG_FORMAT + "|f" ) + - (cla::prefix = "--|-",cla::separator = "=| ",cla::guess_name,cla::optional, + cla::description = "Specifies log format") + << cla::dual_name_parameter<unit_test::log_level>( LOG_LEVEL + "|l" ) + - (cla::prefix = "--|-",cla::separator = "=| ",cla::guess_name,cla::optional, + cla::description = "Specifies log level") + << cla::dual_name_parameter<std::string>( LOG_SINK + "|k" ) + - (cla::prefix = "--|-",cla::separator = "=| ",cla::guess_name,cla::optional, + cla::description = "Specifies log sink:stdout(default),stderr or file name") + << cla::dual_name_parameter<unit_test::output_format>( OUTPUT_FORMAT + "|o" ) + - (cla::prefix = "--|-",cla::separator = "=| ",cla::guess_name,cla::optional, + cla::description = "Specifies output format (both log and report)") + << cla::dual_name_parameter<unsigned>( RANDOM_SEED + "|a" ) + - (cla::prefix = "--|-",cla::separator = "=| ",cla::guess_name,cla::optional,cla::optional_value, + cla::description = "Allows to switch between sequential and random order of test units execution.\n" + "Optionally allows to specify concrete seed for random number generator") + << cla::dual_name_parameter<unit_test::output_format>( REPORT_FORMAT + "|m" ) + - (cla::prefix = "--|-",cla::separator = "=| ",cla::guess_name,cla::optional, + cla::description = "Specifies report format") + << cla::dual_name_parameter<unit_test::report_level>(REPORT_LEVEL + "|r") + - (cla::prefix = "--|-",cla::separator = "=| ",cla::guess_name,cla::optional, + cla::description = "Specifies report level") + << cla::dual_name_parameter<std::string>( REPORT_SINK + "|e" ) + - (cla::prefix = "--|-",cla::separator = "=| ",cla::guess_name,cla::optional, + cla::description = "Specifies report sink:stderr(default),stdout or file name") + << cla::dual_name_parameter<bool>( RESULT_CODE + "|c" ) + - (cla::prefix = "--|-",cla::separator = "=| ",cla::guess_name,cla::optional, + cla::description = "Allows to disable test modules's result code generation") + << cla::dual_name_parameter<std::string>( TESTS_TO_RUN + "|t" ) + - (cla::prefix = "--|-",cla::separator = "=| ",cla::guess_name,cla::optional,cla::multiplicable, + cla::description = "Allows to filter which test units to run") + << cla::named_parameter<bool>( SAVE_TEST_PATTERN ) + - (cla::prefix = "--",cla::separator = "=",cla::guess_name,cla::optional, + cla::description = "Allows to switch between saving and matching against test pattern file") + << cla::dual_name_parameter<bool>( SHOW_PROGRESS + "|p" ) + - (cla::prefix = "--|-",cla::separator = "=| ",cla::guess_name,cla::optional, + cla::description = "Turns on progress display") + << cla::dual_name_parameter<unit_test::output_format>( LIST_CONTENT + "|j" ) + - (cla::prefix = "--|-",cla::separator = "=| ",cla::guess_name,cla::optional,cla::optional_value, + cla::description = "Lists the content of test tree - names of all test suites and test cases") + << cla::named_parameter<bool>( LIST_LABELS ) + - (cla::prefix = "--",cla::separator = "= ",cla::guess_name,cla::optional, + cla::description = "Lists all available labels") + << cla::named_parameter<bool>( USE_ALT_STACK ) + - (cla::prefix = "--",cla::separator = "=",cla::guess_name,cla::optional, + cla::description = "Turns on/off usage of an alternative stack for signal handling") + << cla::dual_name_parameter<bool>( WAIT_FOR_DEBUGGER + "|w" ) + - (cla::prefix = "--|-",cla::separator = "=| ",cla::guess_name,cla::optional,cla::optional_value, + cla::description = "Forces test module to wait for button to be pressed before starting test run") + + << cla::dual_name_parameter<bool>( "help|?" ) + - (cla::prefix = "--|-",cla::separator = "=",cla::guess_name,cla::optional, + cla::description = "this help message") + ; s_cla_parser.parse( argc, argv ); if( s_cla_parser["help"] ) { s_cla_parser.help( std::cout ); - throw framework::nothing_to_test(); + BOOST_TEST_IMPL_THROW( framework::nothing_to_test() ); } - s_report_format = retrieve_parameter( REPORT_FORMAT, s_cla_parser, unit_test::CLF ); - s_log_format = retrieve_parameter( LOG_FORMAT, s_cla_parser, unit_test::CLF ); + s_report_format = retrieve_parameter( REPORT_FORMAT, s_cla_parser, unit_test::OF_CLF ); + s_log_format = retrieve_parameter( LOG_FORMAT, s_cla_parser, unit_test::OF_CLF ); - unit_test::output_format of = retrieve_parameter( OUTPUT_FORMAT, s_cla_parser, unit_test::INV_OF ); + unit_test::output_format of = retrieve_parameter( OUTPUT_FORMAT, s_cla_parser, unit_test::OF_INVALID ); - if( of != unit_test::INV_OF ) + if( of != unit_test::OF_INVALID ) s_report_format = s_log_format = of; + + s_test_to_run = retrieve_parameter<std::list<std::string> >( TESTS_TO_RUN, s_cla_parser ); } - catch( rt::logic_error const& ex ) { + BOOST_TEST_IMPL_CATCH( rt::logic_error, ex ) { std::ostringstream err; - + err << "Fail to process runtime parameters: " << ex.msg() << std::endl; s_cla_parser.usage( err ); - throw framework::setup_error( err.str() ); + BOOST_TEST_SETUP_ASSERT( false, err.str() ); } } @@ -364,11 +409,9 @@ report_level() //____________________________________________________________________________// -const_string +std::list<std::string> const& test_to_run() { - static std::string s_test_to_run = retrieve_parameter( TESTS_TO_RUN, s_cla_parser, s_empty ); - return s_test_to_run; } @@ -408,14 +451,30 @@ show_build_info() //____________________________________________________________________________// +output_format +list_content() +{ + return retrieve_parameter( LIST_CONTENT, s_cla_parser, unit_test::OF_INVALID, unit_test::OF_CLF ); +} + +//____________________________________________________________________________// + +bool +list_labels() +{ + return retrieve_parameter( LIST_LABELS, s_cla_parser, false ); +} + +//____________________________________________________________________________// + bool catch_sys_errors() { - return retrieve_parameter( CATCH_SYS_ERRORS, s_cla_parser, + return retrieve_parameter( CATCH_SYS_ERRORS, s_cla_parser, #ifdef BOOST_TEST_DEFAULTS_TO_CORE_DUMP false #else - true + true #endif ); } @@ -423,9 +482,17 @@ catch_sys_errors() //____________________________________________________________________________// bool +color_output() +{ + return retrieve_parameter( COLOR_OUTPUT, s_cla_parser, false ); +} + +//____________________________________________________________________________// + +bool auto_start_dbg() { - // !! set debugger as an option + // !! ?? set debugger as an option return retrieve_parameter( AUTO_START_DBG, s_cla_parser, false ); ; } @@ -433,6 +500,14 @@ auto_start_dbg() //____________________________________________________________________________// bool +wait_for_debugger() +{ + return retrieve_parameter( WAIT_FOR_DEBUGGER, s_cla_parser, false ); +} + +//____________________________________________________________________________// + +bool use_alt_stack() { return retrieve_parameter( USE_ALT_STACK, s_cla_parser, true ); @@ -470,13 +545,13 @@ report_sink() std::string sink_name = retrieve_parameter( REPORT_SINK, s_cla_parser, s_empty ); if( sink_name.empty() || sink_name == "stderr" ) - return &std::cerr; - + return &std::cerr; + if( sink_name == "stdout" ) return &std::cout; - static std::ofstream log_file( sink_name.c_str() ); - return &log_file; + static std::ofstream report_file( sink_name.c_str() ); + return &report_file; } //____________________________________________________________________________// @@ -487,13 +562,13 @@ log_sink() std::string sink_name = retrieve_parameter( LOG_SINK, s_cla_parser, s_empty ); if( sink_name.empty() || sink_name == "stdout" ) - return &std::cout; + return &std::cout; if( sink_name == "stderr" ) - return &std::cerr; + return &std::cerr; - static std::ofstream report_file( sink_name.c_str() ); - return &report_file; + static std::ofstream log_file( sink_name.c_str() ); + return &log_file; } //____________________________________________________________________________// @@ -501,27 +576,65 @@ log_sink() long detect_memory_leaks() { - return retrieve_parameter( DETECT_MEM_LEAKS, s_cla_parser, static_cast<long>(1) ); + static long s_value = -1; + + if( s_value >= 0 ) + return s_value; + + std::string value = retrieve_parameter( DETECT_MEM_LEAKS, s_cla_parser, s_empty ); + + optional<bool> bool_val; + if( runtime::interpret_argument_value_impl<bool>::_( value, bool_val ) ) + s_value = *bool_val ? 1L : 0L; + else { + BOOST_TEST_IMPL_TRY { + // if representable as long - this is leak number + s_value = boost::lexical_cast<long>( value ); + } + BOOST_TEST_IMPL_CATCH0( boost::bad_lexical_cast ) { + // value is leak report file and detection is enabled + s_value = 1L; + } + } + + return s_value; +} + +//____________________________________________________________________________// + +const_string +memory_leaks_report_file() +{ + if( detect_memory_leaks() != 1 ) + return const_string(); + + static std::string s_value; + + if( s_value.empty() ) { + s_value = retrieve_parameter<std::string>( DETECT_MEM_LEAKS, s_cla_parser ); + + optional<bool> bool_val; + if( runtime::interpret_argument_value_impl<bool>::_( s_value, bool_val ) ) + s_value.clear(); + } + + return s_value; } //____________________________________________________________________________// -int +unsigned random_seed() { - return retrieve_parameter( RANDOM_SEED, s_cla_parser, 0, 1 ); + return retrieve_parameter( RANDOM_SEED, s_cla_parser, 0U, 1U ); } //____________________________________________________________________________// } // namespace runtime_config - } // namespace unit_test - } // namespace boost -//____________________________________________________________________________// - #include <boost/test/detail/enable_warnings.hpp> #endif // BOOST_TEST_UNIT_TEST_PARAMETERS_IPP_012205GER diff --git a/boost/test/impl/unit_test_suite.ipp b/boost/test/impl/unit_test_suite.ipp deleted file mode 100644 index 32efc6059e..0000000000 --- a/boost/test/impl/unit_test_suite.ipp +++ /dev/null @@ -1,346 +0,0 @@ -// (C) Copyright Gennadiy Rozental 2005-2008. -// 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 : $RCSfile$ -// -// Version : $Revision$ -// -// Description : privides core implementation for Unit Test Framework. -// Extensions can be provided in separate files -// *************************************************************************** - -#ifndef BOOST_TEST_UNIT_TEST_SUITE_IPP_012205GER -#define BOOST_TEST_UNIT_TEST_SUITE_IPP_012205GER - -// Boost.Test -#include <boost/detail/workaround.hpp> -#include <boost/test/unit_test_suite_impl.hpp> -#include <boost/test/framework.hpp> -#include <boost/test/utils/foreach.hpp> -#include <boost/test/results_collector.hpp> -#include <boost/test/detail/unit_test_parameters.hpp> - -// Boost -#include <boost/timer.hpp> - -// STL -#include <algorithm> -#include <vector> - -#include <boost/test/detail/suppress_warnings.hpp> - -#if BOOST_WORKAROUND(__BORLANDC__, < 0x600) && \ - BOOST_WORKAROUND(_STLPORT_VERSION, <= 0x450) \ - /**/ - using std::rand; // rand is in std and random_shuffle is in _STL -#endif - -//____________________________________________________________________________// - -namespace boost { - -namespace unit_test { - -// ************************************************************************** // -// ************** test_unit ************** // -// ************************************************************************** // - -test_unit::test_unit( const_string name, test_unit_type t ) -: p_type( t ) -, p_type_name( t == tut_case ? "case" : "suite" ) -, p_id( INV_TEST_UNIT_ID ) -, p_name( std::string( name.begin(), name.size() ) ) -, p_enabled( true ) -{ -} - -//____________________________________________________________________________// - -test_unit::~test_unit() -{ - framework::deregister_test_unit( this ); -} - -//____________________________________________________________________________// - -void -test_unit::depends_on( test_unit* tu ) -{ - m_dependencies.push_back( tu->p_id ); -} - -//____________________________________________________________________________// - -bool -test_unit::check_dependencies() const -{ - BOOST_TEST_FOREACH( test_unit_id, tu_id, m_dependencies ) { - if( !unit_test::results_collector.results( tu_id ).passed() ) - return false; - } - - return true; -} - -//____________________________________________________________________________// - -void -test_unit::increase_exp_fail( unsigned num ) -{ - p_expected_failures.value += num; - - if( p_parent_id != 0 ) - framework::get<test_suite>( p_parent_id ).increase_exp_fail( num ); -} - -//____________________________________________________________________________// - -// ************************************************************************** // -// ************** test_case ************** // -// ************************************************************************** // - -test_case::test_case( const_string name, callback0<> const& test_func ) -: test_unit( name, static_cast<test_unit_type>(type) ) -, m_test_func( test_func ) -{ - // !! weirdest MSVC BUG; try to remove this statement; looks like it eats first token of next statement -#if BOOST_WORKAROUND(BOOST_MSVC,<1300) - 0; -#endif - framework::register_test_unit( this ); -} - -//____________________________________________________________________________// - -// ************************************************************************** // -// ************** test_suite ************** // -// ************************************************************************** // - -//____________________________________________________________________________// - -test_suite::test_suite( const_string name ) -: test_unit( name, static_cast<test_unit_type>(type) ) -{ - framework::register_test_unit( this ); -} - -//____________________________________________________________________________// - -void -test_suite::add( test_unit* tu, counter_t expected_failures, unsigned timeout ) -{ - if( timeout != 0 ) - tu->p_timeout.value = timeout; - - m_members.push_back( tu->p_id ); - tu->p_parent_id.value = p_id; - - if( tu->p_expected_failures ) - increase_exp_fail( tu->p_expected_failures ); - - if( expected_failures ) - tu->increase_exp_fail( expected_failures ); -} - -//____________________________________________________________________________// - -void -test_suite::add( test_unit_generator const& gen, unsigned timeout ) -{ - test_unit* tu; - while((tu = gen.next(), tu)) - add( tu, 0, timeout ); -} - -//____________________________________________________________________________// - -void -test_suite::remove( test_unit_id id ) -{ - std::vector<test_unit_id>::iterator it = std::find( m_members.begin(), m_members.end(), id ); - - if( it != m_members.end() ) - m_members.erase( it ); -} - -//____________________________________________________________________________// - -test_unit_id -test_suite::get( const_string tu_name ) const -{ - BOOST_TEST_FOREACH( test_unit_id, id, m_members ) { - if( tu_name == framework::get( id, ut_detail::test_id_2_unit_type( id ) ).p_name.get() ) - return id; - } - - return INV_TEST_UNIT_ID; -} - -//____________________________________________________________________________// - -// ************************************************************************** // -// ************** traverse_test_tree ************** // -// ************************************************************************** // - -void -traverse_test_tree( test_case const& tc, test_tree_visitor& V ) -{ - if( tc.p_enabled ) - V.visit( tc ); -} - -//____________________________________________________________________________// - -void -traverse_test_tree( test_suite const& suite, test_tree_visitor& V ) -{ - if( !suite.p_enabled || !V.test_suite_start( suite ) ) - return; - - try { - if( runtime_config::random_seed() == 0 ) { - BOOST_TEST_FOREACH( test_unit_id, id, suite.m_members ) - traverse_test_tree( id, V ); - } - else { - std::vector<test_unit_id> members( suite.m_members ); - std::random_shuffle( members.begin(), members.end() ); - BOOST_TEST_FOREACH( test_unit_id, id, members ) - traverse_test_tree( id, V ); - } - - } catch( test_being_aborted const& ) { - V.test_suite_finish( suite ); - framework::test_unit_aborted( suite ); - - throw; - } - - V.test_suite_finish( suite ); -} - -//____________________________________________________________________________// - -void -traverse_test_tree( test_unit_id id, test_tree_visitor& V ) -{ - if( ut_detail::test_id_2_unit_type( id ) == tut_case ) - traverse_test_tree( framework::get<test_case>( id ), V ); - else - traverse_test_tree( framework::get<test_suite>( id ), V ); -} - -//____________________________________________________________________________// - -// ************************************************************************** // -// ************** test_case_counter ************** // -// ************************************************************************** // - -void -test_case_counter::visit( test_case const& tc ) -{ - if( tc.p_enabled ) - ++p_count.value; -} - -//____________________________________________________________________________// - -// ************************************************************************** // -// ************** object generators ************** // -// ************************************************************************** // - -namespace ut_detail { - -std::string -normalize_test_case_name( const_string name ) -{ - return ( name[0] == '&' - ? std::string( name.begin()+1, name.size()-1 ) - : std::string( name.begin(), name.size() ) ); -} - -//____________________________________________________________________________// - -// ************************************************************************** // -// ************** auto_test_unit_registrar ************** // -// ************************************************************************** // - -auto_test_unit_registrar::auto_test_unit_registrar( test_case* tc, counter_t exp_fail ) -{ - curr_ts_store().back()->add( tc, exp_fail ); -} - -//____________________________________________________________________________// - -auto_test_unit_registrar::auto_test_unit_registrar( const_string ts_name ) -{ - test_unit_id id = curr_ts_store().back()->get( ts_name ); - - test_suite* ts; - - if( id != INV_TEST_UNIT_ID ) { - ts = &framework::get<test_suite>( id ); // !! test for invalid tu type - BOOST_ASSERT( ts->p_parent_id == curr_ts_store().back()->p_id ); - } - else { - ts = new test_suite( ts_name ); - curr_ts_store().back()->add( ts ); - } - - curr_ts_store().push_back( ts ); -} - -//____________________________________________________________________________// - -auto_test_unit_registrar::auto_test_unit_registrar( test_unit_generator const& tc_gen ) -{ - curr_ts_store().back()->add( tc_gen ); -} - -//____________________________________________________________________________// - -auto_test_unit_registrar::auto_test_unit_registrar( int ) -{ - if( curr_ts_store().size() == 0 ) - return; // report error? - - curr_ts_store().pop_back(); -} - -//____________________________________________________________________________// - -std::list<test_suite*>& -auto_test_unit_registrar::curr_ts_store() -{ - static std::list<test_suite*> inst( 1, &framework::master_test_suite() ); - return inst; -} - -//____________________________________________________________________________// - -} // namespace ut_detail - -// ************************************************************************** // -// ************** global_fixture ************** // -// ************************************************************************** // - -global_fixture::global_fixture() -{ - framework::register_observer( *this ); -} - -//____________________________________________________________________________// - -} // namespace unit_test - -} // namespace boost - -//____________________________________________________________________________// - -#include <boost/test/detail/enable_warnings.hpp> - -#endif // BOOST_TEST_UNIT_TEST_SUITE_IPP_012205GER diff --git a/boost/test/impl/xml_log_formatter.ipp b/boost/test/impl/xml_log_formatter.ipp index 6c0127bb57..286cd60005 100644 --- a/boost/test/impl/xml_log_formatter.ipp +++ b/boost/test/impl/xml_log_formatter.ipp @@ -1,6 +1,6 @@ -// (C) Copyright Gennadiy Rozental 2005-2008. +// (C) Copyright Gennadiy Rozental 2005-2014. // Distributed under the Boost Software License, Version 1.0. -// (See accompanying file LICENSE_1_0.txt or copy at +// (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. @@ -9,7 +9,7 @@ // // Version : $Revision$ // -// Description : implements XML Log formatter +// Description : implements OF_XML Log formatter // *************************************************************************** #ifndef BOOST_TEST_XML_LOG_FORMATTER_IPP_020105GER @@ -17,10 +17,10 @@ // Boost.Test #include <boost/test/output/xml_log_formatter.hpp> -#include <boost/test/unit_test_suite_impl.hpp> +#include <boost/test/execution_monitor.hpp> #include <boost/test/framework.hpp> +#include <boost/test/tree/test_unit.hpp> #include <boost/test/utils/basic_cstring/io.hpp> - #include <boost/test/utils/xml_printer.hpp> // Boost @@ -34,14 +34,12 @@ //____________________________________________________________________________// namespace boost { - namespace unit_test { - namespace output { static const_string tu_type_name( test_unit const& tu ) { - return tu.p_type == tut_case ? "TestCase" : "TestSuite"; + return tu.p_type == TUT_CASE ? "TestCase" : "TestSuite"; } // ************************************************************************** // @@ -82,7 +80,13 @@ xml_log_formatter::log_build_info( std::ostream& ostr ) void xml_log_formatter::test_unit_start( std::ostream& ostr, test_unit const& tu ) { - ostr << "<" << tu_type_name( tu ) << " name" << attr_value() << tu.p_name.get() << ">"; + ostr << "<" << tu_type_name( tu ) << " name" << attr_value() << tu.p_name.get(); + + if( !tu.p_file_name.get().empty() ) + ostr << BOOST_TEST_L( " file" ) << attr_value() << tu.p_file_name + << BOOST_TEST_L( " line" ) << attr_value() << tu.p_line_num; + + ostr << ">"; } //____________________________________________________________________________// @@ -90,27 +94,28 @@ xml_log_formatter::test_unit_start( std::ostream& ostr, test_unit const& tu ) void xml_log_formatter::test_unit_finish( std::ostream& ostr, test_unit const& tu, unsigned long elapsed ) { - if( tu.p_type == tut_case ) + if( tu.p_type == TUT_CASE ) ostr << "<TestingTime>" << elapsed << "</TestingTime>"; - + ostr << "</" << tu_type_name( tu ) << ">"; } //____________________________________________________________________________// void -xml_log_formatter::test_unit_skipped( std::ostream& ostr, test_unit const& tu ) +xml_log_formatter::test_unit_skipped( std::ostream& ostr, test_unit const& tu, const_string reason ) { ostr << "<" << tu_type_name( tu ) << " name" << attr_value() << tu.p_name.get() << " skipped" << attr_value() << "yes" + << " reason" << attr_value() << reason << "/>"; } - + //____________________________________________________________________________// void -xml_log_formatter::log_exception( std::ostream& ostr, log_checkpoint_data const& checkpoint_data, execution_exception const& ex ) +xml_log_formatter::log_exception_start( std::ostream& ostr, log_checkpoint_data const& checkpoint_data, execution_exception const& ex ) { execution_exception::location const& loc = ex.where(); @@ -129,7 +134,13 @@ xml_log_formatter::log_exception( std::ostream& ostr, log_checkpoint_data const& << cdata() << checkpoint_data.m_message << "</LastCheckpoint>"; } +} + +//____________________________________________________________________________// +void +xml_log_formatter::log_exception_finish( std::ostream& ostr ) +{ ostr << "</Exception>"; } @@ -145,6 +156,8 @@ xml_log_formatter::log_entry_start( std::ostream& ostr, log_entry_data const& en << BOOST_TEST_L( " file" ) << attr_value() << entry_data.m_file_name << BOOST_TEST_L( " line" ) << attr_value() << entry_data.m_line_num << BOOST_TEST_L( "><![CDATA[" ); + + m_value_closed = false; } //____________________________________________________________________________// @@ -152,7 +165,7 @@ xml_log_formatter::log_entry_start( std::ostream& ostr, log_entry_data const& en void xml_log_formatter::log_entry_value( std::ostream& ostr, const_string value ) { - ostr << value; + print_escaped_cdata( ostr, value ); } //____________________________________________________________________________// @@ -160,21 +173,52 @@ xml_log_formatter::log_entry_value( std::ostream& ostr, const_string value ) void xml_log_formatter::log_entry_finish( std::ostream& ostr ) { - ostr << BOOST_TEST_L( "]]></" ) << m_curr_tag << BOOST_TEST_L( ">" ); + if( !m_value_closed ) { + ostr << BOOST_TEST_L( "]]>" ); + m_value_closed = true; + } + + ostr << BOOST_TEST_L( "</" ) << m_curr_tag << BOOST_TEST_L( ">" ); m_curr_tag.clear(); } //____________________________________________________________________________// -} // namespace output +void +xml_log_formatter::entry_context_start( std::ostream& ostr, log_level ) +{ + if( !m_value_closed ) { + ostr << BOOST_TEST_L( "]]>" ); + m_value_closed = true; + } -} // namespace unit_test + ostr << BOOST_TEST_L( "<Context>" ); -} // namespace boost +} + +//____________________________________________________________________________// + +void +xml_log_formatter::entry_context_finish( std::ostream& ostr ) +{ + ostr << BOOST_TEST_L( "</Context>" ); +} //____________________________________________________________________________// +void +xml_log_formatter::log_entry_context( std::ostream& ostr, const_string context_descr ) +{ + ostr << BOOST_TEST_L( "<Frame>" ) << cdata() << context_descr << BOOST_TEST_L( "</Frame>" ); +} + +//____________________________________________________________________________// + +} // namespace output +} // namespace unit_test +} // namespace boost + #include <boost/test/detail/enable_warnings.hpp> #endif // BOOST_TEST_XML_LOG_FORMATTER_IPP_020105GER diff --git a/boost/test/impl/xml_report_formatter.ipp b/boost/test/impl/xml_report_formatter.ipp index 261db788b3..5606fdc0b1 100644 --- a/boost/test/impl/xml_report_formatter.ipp +++ b/boost/test/impl/xml_report_formatter.ipp @@ -1,6 +1,6 @@ -// (C) Copyright Gennadiy Rozental 2005-2008. +// (C) Copyright Gennadiy Rozental 2005-2014. // Distributed under the Boost Software License, Version 1.0. -// (See accompanying file LICENSE_1_0.txt or copy at +// (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. @@ -9,7 +9,7 @@ // // Version : $Revision$ // -// Description : XML report formatter +// Description : OF_XML report formatter // *************************************************************************** #ifndef BOOST_TEST_XML_REPORT_FORMATTER_IPP_020105GER @@ -17,9 +17,9 @@ // Boost.Test #include <boost/test/results_collector.hpp> -#include <boost/test/unit_test_suite_impl.hpp> #include <boost/test/output/xml_report_formatter.hpp> +#include <boost/test/tree/test_unit.hpp> #include <boost/test/utils/xml_printer.hpp> #include <boost/test/utils/basic_cstring/io.hpp> @@ -28,9 +28,7 @@ //____________________________________________________________________________// namespace boost { - namespace unit_test { - namespace output { void @@ -66,20 +64,23 @@ xml_report_formatter::test_unit_report_start( test_unit const& tu, std::ostream& else descr = "failed"; - ostr << '<' << ( tu.p_type == tut_case ? "TestCase" : "TestSuite" ) + ostr << '<' << ( tu.p_type == TUT_CASE ? "TestCase" : "TestSuite" ) << " name" << attr_value() << tu.p_name.get() << " result" << attr_value() << descr << " assertions_passed" << attr_value() << tr.p_assertions_passed << " assertions_failed" << attr_value() << tr.p_assertions_failed + << " warnings_failed" << attr_value() << tr.p_warnings_failed << " expected_failures" << attr_value() << tr.p_expected_failures; - if( tu.p_type == tut_suite ) + if( tu.p_type == TUT_SUITE ) { ostr << " test_cases_passed" << attr_value() << tr.p_test_cases_passed + << " test_cases_passed_with_warnings" << attr_value() << tr.p_test_cases_warned << " test_cases_failed" << attr_value() << tr.p_test_cases_failed << " test_cases_skipped" << attr_value() << tr.p_test_cases_skipped << " test_cases_aborted" << attr_value() << tr.p_test_cases_aborted; - - + } + + ostr << '>'; } @@ -88,7 +89,7 @@ xml_report_formatter::test_unit_report_start( test_unit const& tu, std::ostream& void xml_report_formatter::test_unit_report_finish( test_unit const& tu, std::ostream& ostr ) { - ostr << "</" << ( tu.p_type == tut_case ? "TestCase" : "TestSuite" ) << '>'; + ostr << "</" << ( tu.p_type == TUT_CASE ? "TestCase" : "TestSuite" ) << '>'; } //____________________________________________________________________________// @@ -97,19 +98,15 @@ void xml_report_formatter::do_confirmation_report( test_unit const& tu, std::ostream& ostr ) { test_unit_report_start( tu, ostr ); - test_unit_report_finish( tu, ostr ); + test_unit_report_finish( tu, ostr ); } //____________________________________________________________________________// } // namespace output - } // namespace unit_test - } // namespace boost -//____________________________________________________________________________// - #include <boost/test/detail/enable_warnings.hpp> #endif // BOOST_TEST_XML_REPORT_FORMATTER_IPP_020105GER |