From b8cf34c691623e4ec329053cbbf68522a855882d Mon Sep 17 00:00:00 2001 From: DongHun Kwak Date: Thu, 5 Dec 2019 15:12:59 +0900 Subject: Imported Upstream version 1.67.0 --- boost/test/data/test_case.hpp | 12 +- boost/test/impl/compiler_log_formatter.ipp | 2 +- boost/test/impl/debug.ipp | 2 +- boost/test/impl/execution_monitor.ipp | 12 +- boost/test/impl/framework.ipp | 74 +++++++-- boost/test/impl/junit_log_formatter.ipp | 12 +- boost/test/impl/test_tools.ipp | 8 - boost/test/impl/test_tree.ipp | 32 +++- boost/test/impl/unit_test_log.ipp | 11 ++ boost/test/impl/unit_test_main.ipp | 2 - boost/test/impl/unit_test_parameters.ipp | 121 +++++++------- boost/test/parameterized_test.hpp | 6 +- boost/test/tools/detail/print_helper.hpp | 7 +- boost/test/tree/test_case_template.hpp | 71 ++++++-- boost/test/unit_test_log.hpp | 7 + boost/test/unit_test_parameters.hpp | 39 ++++- boost/test/utils/basic_cstring/basic_cstring.hpp | 4 +- boost/test/utils/is_forward_iterable.hpp | 42 ++++- boost/test/utils/named_params.hpp | 4 +- boost/test/utils/runtime/cla/parser.hpp | 118 +++++++++---- boost/test/utils/runtime/errors.hpp | 4 +- boost/test/utils/runtime/parameter.hpp | 94 ++++++++--- boost/test/utils/setcolor.hpp | 201 ++++++++++++++++++++++- 23 files changed, 698 insertions(+), 187 deletions(-) (limited to 'boost/test') diff --git a/boost/test/data/test_case.hpp b/boost/test/data/test_case.hpp index 2275f90fff..01dc91b06a 100644 --- a/boost/test/data/test_case.hpp +++ b/boost/test/data/test_case.hpp @@ -33,13 +33,16 @@ #include #include - #include -#include #include #include +#include +#include + +#include + #if defined(BOOST_NO_CXX11_VARIADIC_TEMPLATES) \ && !defined(BOOST_TEST_DATASET_MAX_ARITY) # define BOOST_TEST_DATASET_MAX_ARITY 10 @@ -161,6 +164,7 @@ public: #if !defined(BOOST_TEST_DATASET_VARIADIC) // see BOOST_TEST_DATASET_MAX_ARITY to increase the default supported arity + // there is also a limit on boost::bind #define TC_MAKE(z,arity,_) \ template \ void operator()( BOOST_PP_ENUM_BINARY_PARAMS(arity, Arg, const& arg) ) const \ @@ -179,8 +183,8 @@ public: new test_case( genTestCaseName(), m_tc_file, m_tc_line, - boost::bind( &TestCase::template test_method, - boost_bind_rvalue_holder_helper(std::forward(arg))...))); + std::bind( &TestCase::template test_method, + boost_bind_rvalue_holder_helper(std::forward(arg))...))); } #endif diff --git a/boost/test/impl/compiler_log_formatter.ipp b/boost/test/impl/compiler_log_formatter.ipp index 0e83448b14..aa0a0e229f 100644 --- a/boost/test/impl/compiler_log_formatter.ipp +++ b/boost/test/impl/compiler_log_formatter.ipp @@ -282,7 +282,7 @@ compiler_log_formatter::entry_context_finish( std::ostream& output, log_level l //____________________________________________________________________________// void -compiler_log_formatter::log_entry_context( std::ostream& output, log_level l, const_string context_descr ) +compiler_log_formatter::log_entry_context( std::ostream& output, log_level /*l*/, const_string context_descr ) { output << "\n " << context_descr; } diff --git a/boost/test/impl/debug.ipp b/boost/test/impl/debug.ipp index f547052ded..a5e5f6da06 100644 --- a/boost/test/impl/debug.ipp +++ b/boost/test/impl/debug.ipp @@ -938,7 +938,7 @@ attach_debugger( bool break_or_continue ) return true; #else // ****************************************************** default - + (void) break_or_continue; // silence 'unused variable' warning return false; #endif diff --git a/boost/test/impl/execution_monitor.ipp b/boost/test/impl/execution_monitor.ipp index 94b6f9fbe7..035bb958c1 100644 --- a/boost/test/impl/execution_monitor.ipp +++ b/boost/test/impl/execution_monitor.ipp @@ -63,11 +63,15 @@ using std::va_list; #endif // to use vsnprintf -#if defined(__QNXNTO__) +#if defined(__QNXNTO__) || defined(__VXWORKS__) # include using std::va_list; #endif +#if defined(__VXWORKS__) +# define BOOST_TEST_LIMITED_SIGNAL_DETAILS +#endif + #ifdef BOOST_SEH_BASED_SIGNAL_HANDLING # include @@ -363,11 +367,17 @@ system_signal_exception::report() const return; // no error actually occur? switch( m_sig_info->si_code ) { +#ifdef __VXWORKS__ +// a bit of a hack to adapt code to small m_sig_info VxWorks uses +#define si_addr si_value.sival_int +#define si_band si_value.sival_int +#else case SI_USER: report_error( execution_exception::system_error, "signal: generated by kill() (or family); uid=%d; pid=%d", (int)m_sig_info->si_uid, (int)m_sig_info->si_pid ); break; +#endif case SI_QUEUE: report_error( execution_exception::system_error, "signal: sent by sigqueue()" ); diff --git a/boost/test/impl/framework.ipp b/boost/test/impl/framework.ipp index ca35ce1c2a..496e7de859 100644 --- a/boost/test/impl/framework.ipp +++ b/boost/test/impl/framework.ipp @@ -347,12 +347,10 @@ public: , m_dep_collector( dep_collector ) {} -private: // test_tree_visitor interface virtual bool visit( test_unit const& tu ) { const_cast(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 ); @@ -369,6 +367,7 @@ private: return true; } +private: // Data members test_unit::run_status m_new_status; test_unit_id_list* m_dep_collector; @@ -491,7 +490,8 @@ unsigned const TIMEOUT_EXCEEDED = static_cast( -1 ); class state { public: state() - : m_curr_test_unit( INV_TEST_UNIT_ID ) + : m_master_test_suite( 0 ) + , m_curr_test_unit( INV_TEST_UNIT_ID ) , m_next_test_case_id( MIN_TEST_CASE_ID ) , m_next_test_suite_id( MIN_TEST_SUITE_ID ) , m_test_in_progress( false ) @@ -610,13 +610,27 @@ public: tu_to_enable.pop_back(); - // 35. Ignore test units which already enabled + // 35. Ignore test units which are already enabled if( tu.is_enabled() ) continue; // set new status and add all dependencies into tu_to_enable set_run_status enabler( test_unit::RS_ENABLED, &tu_to_enable ); traverse_test_tree( tu.p_id, enabler, true ); + + // Add the dependencies of the parent suites, see trac #13149 + test_unit_id parent_id = tu.p_parent_id; + while( parent_id != INV_TEST_UNIT_ID + && parent_id != master_tu_id ) + { + // we do not use the traverse_test_tree as otherwise it would enable the sibblings and subtree + // of the test case we want to enable (we need to enable the parent suites and their dependencies only) + // the parent_id needs to be enabled in order to be properly parsed by finalize_run_status, the visit + // does the job + test_unit& tu_parent = framework::get( parent_id, TUT_ANY ); + enabler.visit( tu_parent ); + parent_id = tu_parent.p_parent_id; + } } // 40. Apply all disablers @@ -705,6 +719,9 @@ public: // 40. We are going to time the execution boost::timer tu_timer; + // we pass the random generator + const random_generator_helper& rand_gen = p_random_generator ? *p_random_generator : random_generator_helper(); + if( tu.p_type == TUT_SUITE ) { test_suite const& ts = static_cast( tu ); @@ -714,14 +731,14 @@ public: 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 ) ); + result = (std::min)( result, execute_test_tree( chld.second, chld_timeout, &rand_gen ) ); if( unit_test_monitor.is_critical_error( result ) ) break; } } else { - // Go through ranges of chldren with the same dependency rank and shuffle them + // Go through ranges of children with the same dependency rank and shuffle them // independently. Execute each subtree in this order test_unit_id_list children_with_the_same_rank; @@ -737,8 +754,6 @@ public: it++; } - const random_generator_helper& rand_gen = p_random_generator ? *p_random_generator : random_generator_helper(); - #ifdef BOOST_NO_CXX98_RANDOM_SHUFFLE impl::random_shuffle( children_with_the_same_rank.begin(), children_with_the_same_rank.end(), rand_gen ); #else @@ -894,6 +909,13 @@ struct sum_to_first_only { bool is_first; }; +void +shutdown_loggers_and_reports() +{ + s_frk_state().m_log_sinks.clear(); + s_frk_state().m_report_sink.setup( "stderr" ); +} + void setup_loggers() { @@ -913,8 +935,15 @@ setup_loggers() unit_test_log.set_format( format ); runtime_config::stream_holder& stream_logger = s_frk_state().m_log_sinks[format]; - if( runtime_config::has( runtime_config::btrt_log_sink ) ) - stream_logger.setup( runtime_config::get( runtime_config::btrt_log_sink ) ); + if( runtime_config::has( runtime_config::btrt_log_sink ) ) { + // we remove all streams in this case, so we do not specify the format + boost::function< void () > log_cleaner = boost::bind( &unit_test_log_t::set_stream, + &unit_test_log, + boost::ref(std::cout) + ); + stream_logger.setup( runtime_config::get( runtime_config::btrt_log_sink ), + log_cleaner ); + } unit_test_log.set_stream( stream_logger.ref() ); } else @@ -1026,7 +1055,6 @@ setup_loggers() } } - BOOST_TEST_I_ASSRT( formatter_log_level != invalid_log_level, boost::runtime::access_to_missing_argument() << "Unable to determine the log level from '" @@ -1041,12 +1069,18 @@ setup_loggers() unit_test_log.set_threshold_level( format, formatter_log_level ); runtime_config::stream_holder& stream_logger = s_frk_state().m_log_sinks[format]; + boost::function< void () > log_cleaner = boost::bind( &unit_test_log_t::set_stream, + &unit_test_log, + format, + boost::ref(std::cout) ); if( ++current_format_specs != utils::string_token_iterator() && current_format_specs->size() ) { - stream_logger.setup( *current_format_specs ); + stream_logger.setup( *current_format_specs, + log_cleaner ); } else { - stream_logger.setup( formatter->get_default_stream_description() ); + stream_logger.setup( formatter->get_default_stream_description(), + log_cleaner ); } unit_test_log.set_stream( format, stream_logger.ref() ); } @@ -1092,8 +1126,14 @@ init( init_unit_test_func init_func, int argc, char* argv[] ) results_reporter::set_level( runtime_config::get( runtime_config::btrt_report_level ) ); results_reporter::set_format( runtime_config::get( runtime_config::btrt_report_format ) ); - if( runtime_config::has( runtime_config::btrt_report_sink ) ) - s_frk_state().m_report_sink.setup( runtime_config::get( runtime_config::btrt_report_sink ) ); + if( runtime_config::has( runtime_config::btrt_report_sink ) ) { + boost::function< void () > report_cleaner = boost::bind( &results_reporter::set_stream, + boost::ref(std::cerr) + ); + s_frk_state().m_report_sink.setup( runtime_config::get( runtime_config::btrt_report_sink ), + report_cleaner ); + } + results_reporter::set_stream( s_frk_state().m_report_sink.ref() ); // 40. Register default test observers @@ -1173,6 +1213,7 @@ test_in_progress() void shutdown() { + impl::shutdown_loggers_and_reports(); // 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 @@ -1568,6 +1609,7 @@ run( test_unit_id id, bool continue_test ) break; case 1: seed = static_cast( std::rand() ^ std::time( 0 ) ); // better init using std::rand() ^ ... + BOOST_FALLTHROUGH; default: BOOST_TEST_FRAMEWORK_MESSAGE( "Test cases order is shuffled using seed: " << seed ); std::srand( seed ); @@ -1581,6 +1623,8 @@ run( test_unit_id id, bool continue_test ) impl::s_frk_state().m_test_in_progress = false; + results_reporter::make_report( INV_REPORT_LEVEL, id ); + unit_test::framework_init_observer.clear(); if( call_start_finish ) { // indicates the framework that no test is in progress anymore if observers need to be notified diff --git a/boost/test/impl/junit_log_formatter.ipp b/boost/test/impl/junit_log_formatter.ipp index 0ec8d43832..e82e2bd1b0 100644 --- a/boost/test/impl/junit_log_formatter.ipp +++ b/boost/test/impl/junit_log_formatter.ipp @@ -431,13 +431,13 @@ public: if(m_display_build_info) { m_stream << "" << std::endl; - m_stream << "" << std::endl; + m_stream << "" << std::endl; + m_stream << "" << std::endl; std::ostringstream o; o << BOOST_VERSION/100000 << "." << BOOST_VERSION/100 % 1000 << "." << BOOST_VERSION % 100; - m_stream << "" << std::endl; m_stream << "" << std::endl; } } @@ -646,7 +646,7 @@ junit_log_formatter::log_entry_start( std::ostream& /*ostr*/, log_entry_data con last_entry.skipping = true; break; } - // no break on purpose + BOOST_FALLTHROUGH; } case unit_test_log_formatter::BOOST_UTL_ET_MESSAGE: { @@ -654,7 +654,7 @@ junit_log_formatter::log_entry_start( std::ostream& /*ostr*/, log_entry_data con last_entry.skipping = true; break; } - // no break on purpose + BOOST_FALLTHROUGH; } case unit_test_log_formatter::BOOST_UTL_ET_WARNING: { diff --git a/boost/test/impl/test_tools.ipp b/boost/test/impl/test_tools.ipp index 7e01453313..2956879326 100644 --- a/boost/test/impl/test_tools.ipp +++ b/boost/test/impl/test_tools.ipp @@ -119,14 +119,6 @@ print_log_value::operator()( std::ostream& ostr, wchar_t const* ostr << ( t ? t : L"null string" ); } -#if !defined(BOOST_NO_CXX11_NULLPTR) -void -print_log_value::operator()( std::ostream& ostr, std::nullptr_t ) -{ - ostr << "nullptr"; -} -#endif - //____________________________________________________________________________// // ************************************************************************** // diff --git a/boost/test/impl/test_tree.ipp b/boost/test/impl/test_tree.ipp index 81995bb29f..e0839e3dd1 100644 --- a/boost/test/impl/test_tree.ipp +++ b/boost/test/impl/test_tree.ipp @@ -223,7 +223,7 @@ test_case::test_case( const_string name, const_string file_name, std::size_t lin //____________________________________________________________________________// 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(type) ) +: test_unit( ut_detail::normalize_test_case_name( name ), file_name, line_num, static_cast(type) ) { framework::register_test_unit( this ); } @@ -241,6 +241,14 @@ test_suite::test_suite( const_string module_name ) void test_suite::add( test_unit* tu, counter_t expected_failures, unsigned timeout ) { + // check for clashing names #12597 + for( test_unit_id_list::const_iterator it(m_children.begin()), ite(m_children.end()); + it < ite; + ++it) { + BOOST_TEST_SETUP_ASSERT( tu->p_name != framework::get(*it, TUT_ANY).p_name, + "test unit with name '" + tu->p_name.value + std::string("' registered multiple times") ); + } + tu->p_timeout.value = timeout; m_children.push_back( tu->p_id ); @@ -380,9 +388,25 @@ normalize_test_case_name( const_string name ) if( name[0] == '&' ) norm_name = norm_name.substr( 1 ); - - std::replace(norm_name.begin(), norm_name.end(), ' ', '_'); - std::replace(norm_name.begin(), norm_name.end(), ':', '_'); + + // trim spaces + std::size_t first_not_space = norm_name.find_first_not_of(' '); + if( first_not_space ) { + norm_name.erase(0, first_not_space); + } + + std::size_t last_not_space = norm_name.find_last_not_of(' '); + if( last_not_space !=std::string::npos ) { + norm_name.erase(last_not_space + 1); + } + + // sanitize all chars that might be used in runtime filters + static const char to_replace[] = { ':', '*', '@', '+', '!', '/' }; + for(std::size_t index = 0; + index < sizeof(to_replace)/sizeof(to_replace[0]); + index++) { + std::replace(norm_name.begin(), norm_name.end(), to_replace[index], '_'); + } return norm_name; } diff --git a/boost/test/impl/unit_test_log.ipp b/boost/test/impl/unit_test_log.ipp index 6ef7d930a2..2a6c0f4bc6 100644 --- a/boost/test/impl/unit_test_log.ipp +++ b/boost/test/impl/unit_test_log.ipp @@ -525,6 +525,17 @@ unit_test_log_t::set_stream( output_format log_format, std::ostream& str ) } } +std::ostream* +unit_test_log_t::get_stream( output_format log_format ) const +{ + BOOST_TEST_FOREACH( unit_test_log_data_helper_impl&, current_logger_data, s_log_impl().m_log_formatter_data ) { + if( current_logger_data.m_format == log_format) { + return current_logger_data.m_stream; + } + } + return 0; +} + //____________________________________________________________________________// void diff --git a/boost/test/impl/unit_test_main.ipp b/boost/test/impl/unit_test_main.ipp index dabe328c8c..1780c6b93b 100644 --- a/boost/test/impl/unit_test_main.ipp +++ b/boost/test/impl/unit_test_main.ipp @@ -230,8 +230,6 @@ unit_test_main( init_unit_test_func init_func, int argc, char* argv[] ) framework::run(); - results_reporter::make_report(); - result_code = !runtime_config::get( runtime_config::btrt_result_code ) ? boost::exit_success : results_collector.results( framework::master_test_suite().p_id ).result_code(); diff --git a/boost/test/impl/unit_test_parameters.ipp b/boost/test/impl/unit_test_parameters.ipp index b825c46d6a..428c10116f 100644 --- a/boost/test/impl/unit_test_parameters.ipp +++ b/boost/test/impl/unit_test_parameters.ipp @@ -43,7 +43,6 @@ #include #include #include -#include #include // STL @@ -112,7 +111,7 @@ register_parameters( rt::parameters_store& store ) rt::description = "Automatically attaches debugger in case of system level failure (signal).", rt::env_var = "BOOST_TEST_AUTO_START_DBG", - rt::help = "Option " + btrt_auto_start_dbg + " specifies whether Boost.Test should attempt " + rt::help = "Specifies whether Boost.Test should attempt " "to attach a debugger when fatal system error occurs. At the moment this feature " "is only available on a few selected platforms: Win32 and *nix. There is a " "default debugger configured for these platforms. You can manually configure " @@ -145,7 +144,7 @@ register_parameters( rt::parameters_store& store ) rt::option build_info( btrt_build_info, ( rt::description = "Displays library build information.", rt::env_var = "BOOST_TEST_BUILD_INFO", - rt::help = "Option " + btrt_build_info + " displays library build information, including: platform, " + rt::help = "Displays library build information, including: platform, " "compiler, STL version and Boost version." )); @@ -164,7 +163,7 @@ register_parameters( rt::parameters_store& store ) #else true, #endif - rt::help = "If option " + btrt_catch_sys_errors + " has value no the frameworks does not attempt to catch " + rt::help = "If option " + btrt_catch_sys_errors + " has value 'no' the frameworks does not attempt to catch " "asynchronous system failure events (signals on *NIX platforms or structured exceptions on Windows). " " Default value is " #ifdef BOOST_TEST_DEFAULTS_TO_CORE_DUMP @@ -183,9 +182,9 @@ register_parameters( rt::parameters_store& store ) rt::option color_output( btrt_color_output, ( rt::description = "Enables color output of the framework log and report messages.", rt::env_var = "BOOST_TEST_COLOR_OUTPUT", - rt::help = "The framework is able to produce color output on systems which supports it. " - "To enable this behavior set this option to yes. By default the framework " - "does not produces color output." + rt::default_value = true, + rt::help = "Produces color output for logs, reports and help. " + "Defaults to true. " )); color_output.add_cla_id( "--", btrt_color_output, "=", true ); @@ -197,7 +196,7 @@ register_parameters( rt::parameters_store& store ) rt::option detect_fp_except( btrt_detect_fp_except, ( rt::description = "Enables/disables floating point exceptions traps.", rt::env_var = "BOOST_TEST_DETECT_FP_EXCEPTIONS", - rt::help = "Option " + btrt_detect_fp_except + " enables/disables hardware traps for the floating " + rt::help = "Enables/disables hardware traps for the floating " "point exceptions (if supported on your platfrom)." )); @@ -212,7 +211,7 @@ register_parameters( rt::parameters_store& store ) rt::default_value = 1L, rt::optional_value = 1L, rt::value_hint = "", - rt::help = "Parameter " + btrt_detect_mem_leaks + " enables/disables memory leaks detection. " + rt::help = "Enables/disables memory leaks detection. " "This parameter has optional long integer value. The default value is 1, which " "enables the memory leak detection. The value 0 disables memory leak detection. " "Any value N greater than 1 is treated as leak allocation number and tells the " @@ -242,9 +241,9 @@ register_parameters( rt::parameters_store& store ) ( "DOT", OF_DOT ) , #endif - rt::help = "Parameter " + btrt_list_content + " instructs the framework to list the content " - "of the test module instead of executing the test cases. Parameter accepts " - "optional string value indicating the format of the output. Currently the " + rt::help = "Lists the test suites and cases " + "of the test module instead of executing the test cases. The format of the " + "desired output can be passed to the command. Currently the " "framework supports two formats: human readable format (HRF) and dot graph " "format (DOT). If value is omitted HRF value is assumed." )); @@ -285,7 +284,7 @@ register_parameters( rt::parameters_store& store ) ( "JUNIT", OF_JUNIT ) , #endif - rt::help = "Parameter " + btrt_log_format + " allows to set the frameowrk's log format to one " + rt::help = "Set the frameowrk's log format to one " "of the formats supplied by the framework. The only acceptable values for this " "parameter are the names of the output formats supplied by the framework. By " "default the framework uses human readable format (HRF) for testing log. This " @@ -300,7 +299,7 @@ register_parameters( rt::parameters_store& store ) /////////////////////////////////////////////// rt::enum_parameter log_level( btrt_log_level, ( - rt::description = "Specifies log level.", + rt::description = "Specifies the logging level of the test execution.", rt::env_var = "BOOST_TEST_LOG_LEVEL", rt::default_value = log_all_errors, rt::enum_values::value = @@ -333,8 +332,8 @@ register_parameters( rt::parameters_store& store ) ( "nothing" , log_nothing ) , #endif - rt::help = "Parameter " + btrt_log_level + " allows to set the framework's log level. " - "Log level defines the verbosity of testing log produced by a testing " + rt::help = "Set the framework's log level. " + "The log level defines the verbosity of the testing logs produced by a test " "module. The verbosity ranges from a complete log, when all assertions " "(both successful and failing) are reported, all notifications about " "test units start and finish are included, to an empty log when nothing " @@ -348,11 +347,11 @@ register_parameters( rt::parameters_store& store ) /////////////////////////////////////////////// rt::parameter log_sink( btrt_log_sink, ( - rt::description = "Specifies log sink: stdout(default), stderr or file name.", + rt::description = "Specifies log sink: stdout (default), stderr or file name.", rt::env_var = "BOOST_TEST_LOG_SINK", rt::value_hint = "", - rt::help = "Parameter " + btrt_log_sink + " allows to set the log sink - location " - "where we report the log to, thus it allows to easily redirect the " + rt::help = "Sets the log sink - the location " + "where Boost.Test writes the logs of the test execution. it allows to easily redirect the " "test logs to file or standard streams. By default testing log is " "directed to standard output." )); @@ -380,7 +379,7 @@ register_parameters( rt::parameters_store& store ) ( "XML", OF_XML ) , #endif - rt::help = "Parameter " + btrt_output_format + " combines an effect of " + btrt_report_format + + rt::help = "Combines an effect of " + btrt_report_format + " and " + btrt_log_format + " parameters. This parameter has higher priority " "than either one of them. In other words if this parameter is specified " "it overrides the value of other two parameters. This parameter does not " @@ -398,9 +397,12 @@ register_parameters( rt::parameters_store& store ) rt::parameter combined_logger( btrt_combined_logger, ( rt::description = "Specifies log level and sink for one or several log format", rt::env_var = "BOOST_TEST_LOGGER", - rt::value_hint = "log_format:log_level:log_sink", - rt::help = "Parameter " + btrt_combined_logger + " allows to specify the logger type, level and sink\n" - "in one command." + rt::value_hint = "log_format,log_level,log_sink[:log_format,log_level,log_sink]", + rt::help = "Specify one or more logging definition, which include the logger type, level and sink. " + "The log format, level and sink follow the same format as for the argument '--" + btrt_log_format + + "', '--" + btrt_log_level + "' and '--" + btrt_log_sink + "' respetively. " + "This command can take several logging definition separated by a ':', or be repeated " + "on the command line." )); combined_logger.add_cla_id( "--", btrt_combined_logger, "=" ); @@ -415,14 +417,14 @@ register_parameters( rt::parameters_store& store ) rt::default_value = 0U, rt::optional_value = 1U, rt::value_hint = "", - rt::help = "Parameter " + btrt_random_seed + " instructs the framework to execute the " - "test cases in random order. This parameter accepts optional unsigned " - "integer argument. By default test cases are executed in some specific " - "order defined by order of test units in test files and dependency between " - "test units. If parameter is specified without the argument value testing " + rt::help = "Instructs the framework to execute the " + "test cases in random order. This parameter accepts an optional unsigned " + "integer argument. If parameter is specified without the argument value testing " "order is randomized based on current time. Alternatively you can specify " "any positive value greater than 1 and it will be used as random seed for " - "the run." + "the run. " + "By default, the test cases are executed in an " + "order defined by their declaration and the optional dependencies among the test units." )); random_seed.add_cla_id( "--", btrt_random_seed, "=" ); @@ -431,7 +433,7 @@ register_parameters( rt::parameters_store& store ) /////////////////////////////////////////////// rt::enum_parameter report_format( btrt_report_format, ( - rt::description = "Specifies report format.", + rt::description = "Specifies the test report format.", rt::env_var = "BOOST_TEST_REPORT_FORMAT", rt::default_value = OF_CLF, rt::enum_values::value = @@ -448,7 +450,7 @@ register_parameters( rt::parameters_store& store ) ( "XML", OF_XML ) , #endif - rt::help = "Parameter " + btrt_report_format + " allows to set the framework's report format " + rt::help = "Set the framework's report format " "to one of the formats supplied by the framework. The only acceptable values " "for this parameter are the names of the output formats. By default the framework " "uses human readable format (HRF) for results reporting. Alternatively you can " @@ -463,7 +465,7 @@ register_parameters( rt::parameters_store& store ) /////////////////////////////////////////////// rt::enum_parameter report_level( btrt_report_level, ( - rt::description = "Specifies report level.", + rt::description = "Specifies test report level.", rt::env_var = "BOOST_TEST_REPORT_LEVEL", rt::default_value = CONFIRMATION_REPORT, rt::enum_values::value = @@ -482,9 +484,9 @@ register_parameters( rt::parameters_store& store ) ( "no", NO_REPORT ) , #endif - rt::help = "Parameter " + btrt_report_level + " allows to set the verbosity level of the " - "testing result report generated by the framework. Use value 'no' to " - "eliminate the results report completely." + rt::help = "Set the verbosity level of the " + "result report generated by the testing framework. Use value 'no' to " + "disable the results report completely." )); report_level.add_cla_id( "--", btrt_report_level, "=" ); @@ -512,10 +514,10 @@ register_parameters( rt::parameters_store& store ) rt::description = "Specifies report sink: stderr(default), stdout or file name.", rt::env_var = "BOOST_TEST_REPORT_SINK", rt::value_hint = "", - rt::help = "Parameter " + btrt_report_sink + " allows to set the result report sink - " - "the location where the framework writes the result report to, thus it " - "allows to easily redirect the result report to a file or a standard " - "stream. By default the testing result report is directed to the " + rt::help = "Sets the result report sink - " + "the location where the framework writes the result report to. " + "The sink may be a a file or a standard " + "stream. The default is 'stderr': the " "standard error stream." )); @@ -541,13 +543,13 @@ register_parameters( rt::parameters_store& store ) /////////////////////////////////////////////// rt::parameter tests_to_run( btrt_run_filters, ( - rt::description = "Filters, which test units to include or exclude from test module execution.", + rt::description = "Filters which tests to execute.", rt::env_var = "BOOST_TEST_RUN_FILTERS", rt::value_hint = "", - rt::help = "Parameter " + btrt_run_filters + " allows to filter which test units to execute during " - "testing. The framework supports both 'selection filters', which allow to select " + rt::help = "Filters which test units to execute. " + "The framework supports both 'selection filters', which allow to select " "which test units to enable from the set of available test units, and 'disabler " - "filters', which allow to disable some test units. The __UTF__ also supports " + "filters', which allow to disable some test units. Boost.test also supports " "enabling/disabling test units at compile time. These settings identify the default " "set of test units to run. Parameter " + btrt_run_filters + " is used to change this default. " "This parameter is repeatable, so you can specify more than one filter if necessary." @@ -576,8 +578,8 @@ register_parameters( rt::parameters_store& store ) rt::option show_progress( btrt_show_progress, ( rt::description = "Turns on progress display.", rt::env_var = "BOOST_TEST_SHOW_PROGRESS", - rt::help = "Parameter " + btrt_show_progress + " instructs the framework to display test progress " - "information. By default the test progress is not shown." + rt::help = "Instructs the framework to display the progress of the tests. " + "This feature is turned off by default." )); show_progress.add_cla_id( "--", btrt_show_progress, "=" ); @@ -590,9 +592,9 @@ register_parameters( rt::parameters_store& store ) rt::description = "Turns on/off usage of an alternative stack for signal handling.", rt::env_var = "BOOST_TEST_USE_ALT_STACK", rt::default_value = true, - rt::help = "Parameter " + btrt_use_alt_stack + " instructs the framework to use alternative " - "stack for signals processing, on platforms where they are supported. The feature " - "is enabled by default, but can be disabled using this parameter." + rt::help = "Instructs the framework to use an alternative " + "stack for operating system's signals handling (on platforms where this is supported). " + "The feature is enabled by default, but can be disabled using this command line switch." )); use_alt_stack.add_cla_id( "--", btrt_use_alt_stack, "=", true ); @@ -603,9 +605,9 @@ register_parameters( rt::parameters_store& store ) rt::option wait_for_debugger( btrt_wait_for_debugger, ( rt::description = "Forces test module to wait for button to be pressed before starting test run.", rt::env_var = "BOOST_TEST_WAIT_FOR_DEBUGGER", - rt::help = "Parameter " + btrt_wait_for_debugger + " instructs the framework to pause before starting " - "test units execution, so that you can attach a debugger to running test module. By " - "default this parameters turned off." + rt::help = "Instructs the framework to pause before starting " + "test units execution, so that you can attach a debugger to the test module process. " + "This feature is turned off by default." )); wait_for_debugger.add_cla_id( "--", btrt_wait_for_debugger, "=" ); @@ -618,10 +620,10 @@ register_parameters( rt::parameters_store& store ) rt::description = "Help for framework parameters.", rt::optional_value = std::string(), rt::value_hint = "", - rt::help = "Parameter " + btrt_help + " displays help on the framework's parameters. " + rt::help = "Displays help on the framework's parameters. " "The parameter accepts an optional argument value. If present, an argument value is " "interpreted as a parameter name (name guessing works as well, so for example " - "--help=rand displays help on the parameter random). If the parameter name is unknown " + "'--help=rand' displays help on the parameter 'random'). If the parameter name is unknown " "or ambiguous error is reported. If argument value is absent, a summary of all " "framework's parameter is displayed." )); @@ -675,17 +677,26 @@ init( int& argc, char** argv ) // Set arguments to default values if defined and perform all the validations rt::finalize_arguments( s_parameters_store, s_arguments_store ); + // check if colorized output is enabled + bool use_color = true; + if( s_arguments_store.has(btrt_color_output ) ) { + use_color = runtime_config::get(runtime_config::btrt_color_output); + } + // Report help if requested if( runtime_config::get( btrt_version ) ) { parser->version( std::cerr ); BOOST_TEST_I_THROW( framework::nothing_to_test( boost::exit_success ) ); } else if( runtime_config::get( btrt_usage ) ) { - parser->usage( std::cerr ); + parser->usage( std::cerr, runtime::cstring(), use_color ); BOOST_TEST_I_THROW( framework::nothing_to_test( boost::exit_success ) ); } else if( s_arguments_store.has( btrt_help ) ) { - parser->help( std::cerr, s_parameters_store, runtime_config::get( btrt_help ) ); + parser->help(std::cerr, + s_parameters_store, + runtime_config::get( btrt_help ), + use_color ); BOOST_TEST_I_THROW( framework::nothing_to_test( boost::exit_success ) ); } diff --git a/boost/test/parameterized_test.hpp b/boost/test/parameterized_test.hpp index b94e7ec8b3..cc9487abc2 100644 --- a/boost/test/parameterized_test.hpp +++ b/boost/test/parameterized_test.hpp @@ -14,6 +14,7 @@ // Boost.Test #include +#include // Boost #include @@ -65,6 +66,7 @@ public: , m_tc_line( tc_line ) , m_par_begin( par_begin ) , m_par_end( par_end ) + , m_index( 0 ) {} virtual test_unit* next() const @@ -72,9 +74,10 @@ public: if( m_par_begin == m_par_end ) return (test_unit*)0; - test_unit* res = new test_case( m_tc_name, m_tc_file, m_tc_line, boost::bind( m_test_func, *m_par_begin ) ); + test_unit* res = new test_case( m_tc_name + "_" + utils::string_cast(m_index), m_tc_file, m_tc_line, boost::bind( m_test_func, *m_par_begin ) ); ++m_par_begin; + ++m_index; return res; } @@ -87,6 +90,7 @@ private: std::size_t m_tc_line; mutable ParamIter m_par_begin; ParamIter m_par_end; + mutable std::size_t m_index; }; //____________________________________________________________________________// diff --git a/boost/test/tools/detail/print_helper.hpp b/boost/test/tools/detail/print_helper.hpp index 1e4dd6e3c0..2c6a3b5e80 100644 --- a/boost/test/tools/detail/print_helper.hpp +++ b/boost/test/tools/detail/print_helper.hpp @@ -166,8 +166,11 @@ struct BOOST_TEST_DECL print_log_value { #if !defined(BOOST_NO_CXX11_NULLPTR) template<> -struct BOOST_TEST_DECL print_log_value { - void operator()( std::ostream& ostr, std::nullptr_t t ); +struct print_log_value { + // declaration and definition is here because of #12969 https://svn.boost.org/trac10/ticket/12969 + void operator()( std::ostream& ostr, std::nullptr_t /*t*/ ) { + ostr << "nullptr"; + } }; #endif diff --git a/boost/test/tree/test_case_template.hpp b/boost/test/tree/test_case_template.hpp index 6a1fc3e57b..83a13f00f5 100644 --- a/boost/test/tree/test_case_template.hpp +++ b/boost/test/tree/test_case_template.hpp @@ -41,6 +41,12 @@ #include // for std::string #include // for std::list +#if !defined(BOOST_NO_CXX11_VARIADIC_TEMPLATES) && \ + !defined(BOOST_NO_CXX11_HDR_TUPLE) && \ + !defined(BOOST_NO_CXX11_AUTO_DECLARATIONS) + #include +#endif + #include @@ -64,7 +70,7 @@ public: // ************** generate_test_case_4_type ************** // // ************************************************************************** // -template +template struct generate_test_case_4_type { explicit generate_test_case_4_type( const_string tc_name, const_string tc_file, std::size_t tc_line, Generator& G ) : m_test_case_name( tc_name ) @@ -106,17 +112,8 @@ private: // ************** test_case_template ************** // // ************************************************************************** // -template -class template_test_case_gen : public test_unit_generator { +class template_test_case_gen_base : public test_unit_generator { public: - // Constructor - template_test_case_gen( const_string tc_name, const_string tc_file, std::size_t tc_line ) - { - typedef generate_test_case_4_type,TestCaseTemplate> single_test_gen; - - mpl::for_each >( single_test_gen( tc_name, tc_file, tc_line, *this ) ); - } - virtual test_unit* next() const { if( m_test_cases.empty() ) @@ -132,6 +129,58 @@ public: mutable std::list m_test_cases; }; +template +class template_test_case_gen : public template_test_case_gen_base { +public: + // Constructor + template_test_case_gen( const_string tc_name, const_string tc_file, std::size_t tc_line ) + { + typedef generate_test_case_4_type,TestCaseTemplate> single_test_gen; + + mpl::for_each >( single_test_gen( tc_name, tc_file, tc_line, *this ) ); + } +}; + +// adding support for tuple +#if !defined(BOOST_NO_CXX11_VARIADIC_TEMPLATES) && \ + !defined(BOOST_NO_CXX11_HDR_TUPLE) && \ + !defined(BOOST_NO_CXX11_AUTO_DECLARATIONS) + +template +class template_test_case_gen > : public template_test_case_gen_base { + + template + struct seq { }; + + template + struct gen_seq : gen_seq { }; + + template + struct gen_seq<0, Is...> : seq { }; + + template + void for_each(F &f, seq) + { + auto l = { (f(mpl::identity::type>()), 0)... }; + (void)l; // silence warning + } + +public: + // Constructor + template_test_case_gen( const_string tc_name, const_string tc_file, std::size_t tc_line ) + { + using tuple_t = std::tuple; + using this_type = template_test_case_gen; + using single_test_gen = generate_test_case_4_type; + + single_test_gen op( tc_name, tc_file, tc_line, *this ); + + this->for_each(op, gen_seq()); + } +}; + +#endif /* C++11 variadic and tuples */ + } // namespace ut_detail } // unit_test } // namespace boost diff --git a/boost/test/unit_test_log.hpp b/boost/test/unit_test_log.hpp index 4e6a97b3c2..6944ffa79a 100644 --- a/boost/test/unit_test_log.hpp +++ b/boost/test/unit_test_log.hpp @@ -137,6 +137,13 @@ public: //! @par Since Boost 1.62 void set_stream( output_format, std::ostream& ); + //! Returns a pointer to the stream associated to specific logger + //! + //! @note Returns a null pointer if the format is not found + //! @par Since Boost 1.67 + std::ostream* get_stream( output_format ) const; + + //! Sets the threshold level for all loggers/formatters. //! //! This will override the log level of all loggers, whether enabled or not. diff --git a/boost/test/unit_test_parameters.hpp b/boost/test/unit_test_parameters.hpp index 0b77f37197..e01bbd7aed 100644 --- a/boost/test/unit_test_parameters.hpp +++ b/boost/test/unit_test_parameters.hpp @@ -19,6 +19,9 @@ #include #include +// Boost +#include + // STL #include #include @@ -96,24 +99,29 @@ BOOST_TEST_DECL bool save_pattern(); class stream_holder { public: // Constructor - explicit stream_holder( std::ostream& default_stream = std::cout) + explicit stream_holder( std::ostream& default_stream = std::cout ) : m_stream( &default_stream ) { } - void setup( const const_string& stream_name ) + void setup( const const_string& stream_name, + boost::function const &cleaner_callback = boost::function() ) { if(stream_name.empty()) return; - if( stream_name == "stderr" ) + if( stream_name == "stderr" ) { m_stream = &std::cerr; - else if( stream_name == "stdout" ) + m_cleaner.reset(); + } + else if( stream_name == "stdout" ) { m_stream = &std::cout; + m_cleaner.reset(); + } else { - m_file = boost::make_shared(); - m_file->open( std::string(stream_name.begin(), stream_name.end()).c_str() ); - m_stream = m_file.get(); + m_cleaner = boost::make_shared(cleaner_callback); + m_cleaner->m_file.open( std::string(stream_name.begin(), stream_name.end()).c_str() ); + m_stream = &m_cleaner->m_file; } } @@ -121,9 +129,22 @@ public: std::ostream& ref() const { return *m_stream; } private: + struct callback_cleaner { + callback_cleaner(boost::function cleaner_callback) + : m_cleaner_callback(cleaner_callback) + , m_file() { + } + ~callback_cleaner() { + if( m_cleaner_callback ) + m_cleaner_callback(); + } + boost::function m_cleaner_callback; + std::ofstream m_file; + }; + // Data members - boost::shared_ptr m_file; - std::ostream* m_stream; + boost::shared_ptr m_cleaner; + std::ostream* m_stream; }; } // namespace runtime_config diff --git a/boost/test/utils/basic_cstring/basic_cstring.hpp b/boost/test/utils/basic_cstring/basic_cstring.hpp index fdd87d5211..cec0214b73 100644 --- a/boost/test/utils/basic_cstring/basic_cstring.hpp +++ b/boost/test/utils/basic_cstring/basic_cstring.hpp @@ -60,8 +60,8 @@ public: // !! should also present reverse_iterator, const_reverse_iterator -#if !BOOST_WORKAROUND(__IBMCPP__, BOOST_TESTED_AT(600)) - enum npos_type { npos = static_cast(-1) }; +#if !BOOST_WORKAROUND(__IBMCPP__, BOOST_TESTED_AT(600)) && !defined(__DCC__) + BOOST_STATIC_CONSTANT(size_type, npos = static_cast(-1)); #else // IBM/VisualAge version 6 is not able to handle enums larger than 4 bytes. // But size_type is 8 bytes in 64bit mode. diff --git a/boost/test/utils/is_forward_iterable.hpp b/boost/test/utils/is_forward_iterable.hpp index e8f5d39467..1c9108054b 100644 --- a/boost/test/utils/is_forward_iterable.hpp +++ b/boost/test/utils/is_forward_iterable.hpp @@ -16,7 +16,7 @@ defined(BOOST_NO_CXX11_NULLPTR) || \ defined(BOOST_NO_CXX11_TRAILING_RESULT_TYPES) - // some issues with boost.config + // this feature works with VC2012 upd 5 while BOOST_NO_CXX11_TRAILING_RESULT_TYPES is defined #if !defined(BOOST_MSVC) || BOOST_MSVC_FULL_VER < 170061030 /* VC2012 upd 5 */ #define BOOST_TEST_FWD_ITERABLE_CXX03 #endif @@ -35,8 +35,8 @@ #else // Boost +#include #include -#include #include #include #include @@ -122,8 +122,6 @@ private: template static nil_t test( ... ); public: static bool const value = !std::is_same< decltype(test( nullptr )), nil_t>::value; - - }; //____________________________________________________________________________// @@ -196,14 +194,27 @@ struct is_container_forward_iterable { #endif /* defined(BOOST_TEST_FWD_ITERABLE_CXX03) */ + +//! Helper structure for accessing the content of a container or an array template ::value > struct bt_iterator_traits; template struct bt_iterator_traits< T, true >{ - BOOST_STATIC_ASSERT((is_forward_iterable::value)); //, "only for forward iterable types"); + BOOST_STATIC_ASSERT((is_forward_iterable::value)); + +#if defined(BOOST_TEST_FWD_ITERABLE_CXX03) || \ + (defined(BOOST_MSVC) && (BOOST_MSVC_FULL_VER <= 170061030)) typedef typename T::const_iterator const_iterator; - typedef typename T::value_type value_type; + typedef typename std::iterator_traits::value_type value_type; +#else + typedef decltype(boost::declval< + typename boost::add_const< + typename boost::remove_reference::type + >::type>().begin()) const_iterator; + + typedef typename std::iterator_traits::value_type value_type; +#endif /* BOOST_TEST_FWD_ITERABLE_CXX03 */ static const_iterator begin(T const& container) { return container.begin(); @@ -211,9 +222,26 @@ struct bt_iterator_traits< T, true >{ static const_iterator end(T const& container) { return container.end(); } - static std::size_t size(T const& container) { + +#if defined(BOOST_TEST_FWD_ITERABLE_CXX03) || \ + (defined(BOOST_MSVC) && (BOOST_MSVC_FULL_VER <= 170061030)) + static std::size_t + size(T const& container) { return container.size(); } +#else + static std::size_t + size(T const& container) { + return size(container, + std::integral_constant::value>()); + } +private: + static std::size_t + size(T const& container, std::true_type) { return container.size(); } + + static std::size_t + size(T const& container, std::false_type) { return std::distance(begin(container), end(container)); } +#endif /* BOOST_TEST_FWD_ITERABLE_CXX03 */ }; template diff --git a/boost/test/utils/named_params.hpp b/boost/test/utils/named_params.hpp index 88b8a883fe..50de5bfba0 100644 --- a/boost/test/utils/named_params.hpp +++ b/boost/test/utils/named_params.hpp @@ -72,7 +72,7 @@ struct is_named_param_pack > : public mpl::true // ************** param_type ************** // // ************************************************************************** // -/// param_type::type is is the type of the parameter +/// param_type::type is the type of the parameter /// corresponding to the Keyword (if parameter is present) or Default template @@ -91,7 +91,7 @@ struct param_type,Keyword,DefaultType> // ************** has_param ************** // // ************************************************************************** // -/// has_param::value is true id Params has parameter corresponding +/// has_param::value is true if Params has parameter corresponding /// to the Keyword template diff --git a/boost/test/utils/runtime/cla/parser.hpp b/boost/test/utils/runtime/cla/parser.hpp index 9fe8e1bbd9..a57091b474 100644 --- a/boost/test/utils/runtime/cla/parser.hpp +++ b/boost/test/utils/runtime/cla/parser.hpp @@ -287,57 +287,119 @@ public: } void - usage( std::ostream& ostr, cstring param_name = cstring() ) + usage(std::ostream& ostr, + cstring param_name = cstring(), + bool use_color = true) { + namespace utils = unit_test::utils; + namespace ut_detail = unit_test::ut_detail; + if( !param_name.is_empty() ) { basic_param_ptr param = locate_parameter( m_param_trie[help_prefix], param_name, "" ).second; param->usage( ostr, m_negation_prefix ); } else { - ostr << "Usage: " << m_program_name << " [Boost.Test argument]... "; - if( !m_end_of_param_indicator.empty() ) - ostr << m_end_of_param_indicator << " [custom test module argument]..."; - ostr << "\n"; + ostr << "\n The program '" << m_program_name << "' is a Boost.test module containing unit tests."; + + { + BOOST_TEST_SCOPE_SETCOLOR( use_color, ostr, term_attr::BRIGHT, term_color::ORIGINAL ); + ostr << "\n\n Usage\n "; + } + + { + BOOST_TEST_SCOPE_SETCOLOR( use_color, ostr, term_attr::BRIGHT, term_color::GREEN ); + ostr << m_program_name << " [Boost.Test argument]... "; + } + if( !m_end_of_param_indicator.empty() ) { + BOOST_TEST_SCOPE_SETCOLOR( use_color, ostr, term_attr::BRIGHT, term_color::YELLOW ); + ostr << '[' << m_end_of_param_indicator << " [custom test module argument]...]"; + } } - ostr << "\nFor detailed help on Boost.Test parameters use:\n" - << " " << m_program_name << " --help\n" - << "or\n" - << " " << m_program_name << " --help=\n"; + ostr << "\n\n Use\n "; + { + + BOOST_TEST_SCOPE_SETCOLOR( use_color, ostr, term_attr::BRIGHT, term_color::GREEN ); + ostr << m_program_name << " --help"; + } + ostr << "\n or "; + { + BOOST_TEST_SCOPE_SETCOLOR( use_color, ostr, term_attr::BRIGHT, term_color::GREEN ); + ostr << m_program_name << " --help="; + } + ostr << "\n for detailed help on Boost.Test parameters.\n"; } void - help( std::ostream& ostr, parameters_store const& parameters, cstring param_name ) + help(std::ostream& ostr, + parameters_store const& parameters, + cstring param_name, + bool use_color = true) { + namespace utils = unit_test::utils; + namespace ut_detail = unit_test::ut_detail; + if( !param_name.is_empty() ) { basic_param_ptr param = locate_parameter( m_param_trie[help_prefix], param_name, "" ).second; - param->help( ostr, m_negation_prefix ); + param->help( ostr, m_negation_prefix, use_color); return; } - ostr << "Usage: " << m_program_name << " [Boost.Test argument]... "; - if( !m_end_of_param_indicator.empty() ) - ostr << m_end_of_param_indicator << " [custom test module argument]..."; + usage(ostr, cstring(), use_color); + + ostr << "\n\n"; + { + BOOST_TEST_SCOPE_SETCOLOR( use_color, ostr, term_attr::BRIGHT, term_color::ORIGINAL ); + ostr << " Command line flags:\n"; + } + runtime::commandline_pretty_print( + ostr, + " ", + "The command line flags of Boost.Test are listed below. " + "All parameters are optional. You can specify parameter value either " + "as a command line argument or as a value of its corresponding environment " + "variable. If a flag is specified as a command line argument and an environment variable " + "at the same time, the command line takes precedence. " + "The command line argument " + "support name guessing, and works with shorter names as long as those are not ambiguous." + ); + + if( !m_end_of_param_indicator.empty() ) { + ostr << "\n\n All the arguments after the '"; + { + BOOST_TEST_SCOPE_SETCOLOR( use_color, ostr, term_attr::BRIGHT, term_color::YELLOW ); + ostr << m_end_of_param_indicator; + } + ostr << "' are ignored by Boost.Test."; + } + - ostr << "\n\nBoost.Test arguments correspond to parameters listed below. " - "All parameters are optional. You can use specify parameter value either " - "as a command line argument or as a value of corresponding environment " - "variable. In case if argument for the same parameter is specified in both " - "places, command line is taking precedence. Command line argument format " - "supports parameter name guessing, so you can use any unambiguous " - "prefix to identify a parameter."; - if( !m_end_of_param_indicator.empty() ) - ostr << " All the arguments after the " << m_end_of_param_indicator << " are ignored by the Boost.Test."; + { + BOOST_TEST_SCOPE_SETCOLOR( use_color, ostr, term_attr::BRIGHT, term_color::ORIGINAL ); + ostr << "\n\n Environment variables:\n"; + } + runtime::commandline_pretty_print( + ostr, + " ", + "Every argument listed below may also be set by a corresponding environment" + "variable. For an argument '--argument_x=', the corresponding " + "environment variable is 'BOOST_TEST_ARGUMENT_X=value" + ); - ostr << "\n\nBoost.Test supports following parameters:\n"; - BOOST_TEST_FOREACH( parameters_store::storage_type::value_type const&, v, parameters.all() ) { - basic_param_ptr param = v.second; - param->usage( ostr, m_negation_prefix ); + ostr << "\n\n The following parameters are supported:\n"; + + BOOST_TEST_FOREACH( + parameters_store::storage_type::value_type const&, + v, + parameters.all() ) + { + basic_param_ptr param = v.second; + ostr << "\n"; + param->usage( ostr, m_negation_prefix, use_color); } - ostr << "\nUse --help= to display detailed help for specific parameter.\n"; } private: diff --git a/boost/test/utils/runtime/errors.hpp b/boost/test/utils/runtime/errors.hpp index 37f8d9371b..5b263d21c5 100644 --- a/boost/test/utils/runtime/errors.hpp +++ b/boost/test/utils/runtime/errors.hpp @@ -86,7 +86,7 @@ public: { this->msg.append( val ); - return reinterpret_cast(*this); + return static_cast(*this); } //____________________________________________________________________________// @@ -96,7 +96,7 @@ public: { this->msg.append( unit_test::utils::string_cast( val ) ); - return reinterpret_cast(*this); + return static_cast(*this); } //____________________________________________________________________________// diff --git a/boost/test/utils/runtime/parameter.hpp b/boost/test/utils/runtime/parameter.hpp index f11ce9813c..420b60264d 100644 --- a/boost/test/utils/runtime/parameter.hpp +++ b/boost/test/utils/runtime/parameter.hpp @@ -24,6 +24,7 @@ // Boost.Test #include #include +#include // Boost #include @@ -37,6 +38,40 @@ namespace boost { namespace runtime { +inline +std::ostream& commandline_pretty_print( + std::ostream& ostr, + std::string const& prefix, + std::string const& to_print) { + + const int split_at = 80; + + std::string::size_type current = 0; + + while(current < to_print.size()) { + + // discards spaces at the beginning + std::string::size_type startpos = to_print.find_first_not_of(" \t\n", current); + current += startpos - current; + + bool has_more_lines = (current + split_at) < to_print.size(); + + if(has_more_lines) { + std::string::size_type endpos = to_print.find_last_of(" \t\n", current + split_at); + std::string sub(to_print.substr(current, endpos - current)); + ostr << prefix << sub; + ostr << "\n"; + current += endpos - current; + } + else + { + ostr << prefix << to_print.substr(current, split_at); + current += split_at; + } + } + return ostr; +} + // ************************************************************************** // // ************** runtime::parameter_cla_id ************** // // ************************************************************************** // @@ -142,23 +177,37 @@ public: virtual void produce_default( arguments_store& store ) const = 0; /// interfaces for help message reporting - virtual void usage( std::ostream& ostr, cstring negation_prefix_ ) + virtual void usage( std::ostream& ostr, cstring negation_prefix_, bool use_color = true ) { - ostr << "Parameter: " << p_name << '\n'; - if( !p_description.empty() ) - ostr << ' ' << p_description << '\n'; + namespace utils = unit_test::utils; + namespace ut_detail = unit_test::ut_detail; + + // + ostr << " "; + { + + BOOST_TEST_SCOPE_SETCOLOR( use_color, ostr, term_attr::BRIGHT, term_color::GREEN ); + ostr << p_name; + } + + ostr << '\n'; + + if( !p_description.empty() ) { + commandline_pretty_print(ostr, " ", p_description) << '\n'; + } - ostr << " Command line formats:\n"; BOOST_TEST_FOREACH( parameter_cla_id const&, id, cla_ids() ) { if( id.m_prefix == help_prefix ) continue; - ostr << " " << id.m_prefix; + ostr << " " << id.m_prefix; + if( id.m_negatable ) - cla_name_help( ostr, id.m_tag, negation_prefix_ ); + cla_name_help( ostr, id.m_tag, negation_prefix_, use_color ); else - cla_name_help( ostr, id.m_tag, "" ); + cla_name_help( ostr, id.m_tag, "", use_color ); + BOOST_TEST_SCOPE_SETCOLOR( use_color, ostr, term_attr::BRIGHT, term_color::YELLOW ); bool optional_value_ = false; if( p_has_optional_value ) { @@ -166,6 +215,7 @@ public: ostr << '['; } + if( id.m_value_separator.empty() ) ostr << ' '; else { @@ -179,16 +229,16 @@ public: ostr << '\n'; } - if( !p_env_var.empty() ) - ostr << " Environment variable: " << p_env_var << '\n'; } - virtual void help( std::ostream& ostr, cstring negation_prefix_ ) + virtual void help( std::ostream& ostr, cstring negation_prefix_, bool use_color = true ) { - usage( ostr, negation_prefix_ ); + usage( ostr, negation_prefix_, use_color ); - if( !p_help.empty() ) - ostr << '\n' << p_help << '\n'; + if( !p_help.empty() ) { + ostr << '\n'; + commandline_pretty_print(ostr, " ", p_help); + } } protected: @@ -220,7 +270,7 @@ protected: private: /// interface for usage/help customization - virtual void cla_name_help( std::ostream& ostr, cstring cla_tag, cstring /* negation_prefix_ */) const + virtual void cla_name_help( std::ostream& ostr, cstring cla_tag, cstring /*negation_prefix_*/, bool /*use_color*/ = true) const { ostr << cla_tag; } @@ -337,12 +387,16 @@ private: { m_arg_factory.produce_default( p_name, store ); } - virtual void cla_name_help( std::ostream& ostr, cstring cla_tag, cstring negation_prefix_ ) const + virtual void cla_name_help( std::ostream& ostr, cstring cla_tag, cstring negation_prefix_, bool use_color = true ) const { - if( negation_prefix_.is_empty() ) - ostr << cla_tag; - else - ostr << '[' << negation_prefix_ << ']' << cla_tag; + namespace utils = unit_test::utils; + namespace ut_detail = unit_test::ut_detail; + + if( !negation_prefix_.is_empty() ) { + BOOST_TEST_SCOPE_SETCOLOR( use_color, ostr, term_attr::BRIGHT, term_color::YELLOW ); + ostr << '[' << negation_prefix_ << ']'; + } + ostr << cla_tag; } virtual void value_help( std::ostream& ostr ) const { diff --git a/boost/test/utils/setcolor.hpp b/boost/test/utils/setcolor.hpp index c70209038a..91b068ae6f 100644 --- a/boost/test/utils/setcolor.hpp +++ b/boost/test/utils/setcolor.hpp @@ -24,6 +24,15 @@ #include +#ifdef _WIN32 + #include + + #if defined(__MINGW32__) && !defined(COMMON_LVB_UNDERSCORE) + // mingw badly mimicking windows.h + #define COMMON_LVB_UNDERSCORE 0x8000 + #endif +#endif + //____________________________________________________________________________// namespace boost { @@ -64,6 +73,7 @@ struct term_color { enum _ { // ************** setcolor ************** // // ************************************************************************** // +#ifndef _WIN32 class setcolor { public: // Constructor @@ -77,7 +87,10 @@ public: friend std::ostream& operator<<( std::ostream& os, setcolor const& sc ) { - return os.write( sc.m_control_command, sc.m_command_size ); + if (&os == &std::cout || &os == &std::cerr) { + return os.write( sc.m_control_command, sc.m_command_size ); + } + return os; } private: @@ -86,10 +99,151 @@ private: int m_command_size; }; +#else + +class setcolor { + +protected: + void set_console_color(std::ostream& os, WORD *attributes = NULL) const { + DWORD console_type; + if (&os == &std::cout) { + console_type = STD_OUTPUT_HANDLE; + } + else if (&os == &std::cerr) { + console_type = STD_ERROR_HANDLE; + } + else { + return; + } + HANDLE hConsole = GetStdHandle(console_type); + + if(hConsole == INVALID_HANDLE_VALUE || hConsole == NULL ) + return; + + if(attributes != NULL) { + SetConsoleTextAttribute(hConsole, *attributes); + return; + } + + CONSOLE_SCREEN_BUFFER_INFO consoleInfo; + GetConsoleScreenBufferInfo(hConsole, &consoleInfo); + //if(!has_written_console_ext) { + saved_attributes = consoleInfo.wAttributes; + //} + + WORD fg_attr = 0; + switch(m_fg) + { + case term_color::WHITE: + fg_attr = FOREGROUND_RED | FOREGROUND_GREEN | FOREGROUND_BLUE; + break; + case term_color::BLACK: + fg_attr = 0; + break; + case term_color::RED: + fg_attr = FOREGROUND_RED; + break; + case term_color::GREEN: + fg_attr = FOREGROUND_GREEN; + break; + case term_color::CYAN: + fg_attr = FOREGROUND_GREEN | FOREGROUND_BLUE; + break; + case term_color::MAGENTA: + fg_attr = FOREGROUND_RED | FOREGROUND_BLUE; + break; + case term_color::BLUE: + fg_attr = FOREGROUND_BLUE; + break; + case term_color::YELLOW: + fg_attr = FOREGROUND_RED | FOREGROUND_GREEN; + break; + case term_color::ORIGINAL: + default: + fg_attr = saved_attributes & (FOREGROUND_RED | FOREGROUND_GREEN | FOREGROUND_BLUE); + break; + } + + WORD bg_attr = 0; + switch(m_bg) + { + case term_color::BLACK: + bg_attr = 0; + break; + case term_color::WHITE: + bg_attr = BACKGROUND_RED | BACKGROUND_GREEN | BACKGROUND_BLUE; + break; + case term_color::RED: + bg_attr = BACKGROUND_RED; + break; + case term_color::GREEN: + bg_attr = BACKGROUND_GREEN; + break; + case term_color::BLUE: + bg_attr = BACKGROUND_BLUE; + break; + case term_color::ORIGINAL: + default: + bg_attr = saved_attributes & (BACKGROUND_RED | BACKGROUND_GREEN | BACKGROUND_BLUE); + break; + } + + WORD text_attr = 0; + switch(m_attr) + { + case term_attr::BRIGHT: + text_attr = FOREGROUND_INTENSITY; + break; + case term_attr::UNDERLINE: + text_attr = COMMON_LVB_UNDERSCORE; + break; + default: + break; + } + + SetConsoleTextAttribute(hConsole, fg_attr | bg_attr | text_attr); + + //has_written_console_ext = true; + return; + } + +public: + // Constructor + explicit setcolor( + term_attr::_ attr = term_attr::NORMAL, + term_color::_ fg = term_color::ORIGINAL, + term_color::_ bg = term_color::ORIGINAL ) + : /*has_written_console_ext(false) + , */m_attr(attr) + , m_fg(fg) + , m_bg(bg) + {} + + friend std::ostream& + operator<<( std::ostream& os, setcolor const& sc ) + { + sc.set_console_color(os); + return os; + } + +private: + term_attr::_ m_attr; + term_color::_ m_fg; + term_color::_ m_bg; + +protected: + // Data members + mutable WORD saved_attributes; + //mutable bool has_written_console_ext; +}; + +#endif // ************************************************************************** // // ************** scope_setcolor ************** // // ************************************************************************** // +#ifndef _WIN32 + struct scope_setcolor { scope_setcolor() : m_os( 0 ) {} explicit scope_setcolor( std::ostream& os, @@ -106,15 +260,50 @@ struct scope_setcolor { *m_os << setcolor(); } private: + scope_setcolor(const scope_setcolor& r); + scope_setcolor& operator=(const scope_setcolor& r); // Data members std::ostream* m_os; }; -#define BOOST_TEST_SCOPE_SETCOLOR( is_color_output, os, attr, color ) \ - utils::scope_setcolor const& sc = is_color_output \ - ? utils::scope_setcolor( os, utils::attr, utils::color ) \ - : utils::scope_setcolor(); \ - ut_detail::ignore_unused_variable_warning( sc ) \ +#else + +struct scope_setcolor : setcolor { + scope_setcolor() : m_os( 0 ) {} + explicit scope_setcolor( + std::ostream& os, + term_attr::_ attr = term_attr::NORMAL, + term_color::_ fg = term_color::ORIGINAL, + term_color::_ bg = term_color::ORIGINAL ) + : + setcolor(attr, fg, bg), + m_os( &os ) + { + os << *this; + } + + ~scope_setcolor() + { + if (m_os) { + set_console_color(*m_os, &this->saved_attributes); + } + } +private: + scope_setcolor(const scope_setcolor& r); + scope_setcolor& operator=(const scope_setcolor& r); + // Data members + std::ostream* m_os; +}; + + +#endif + +#define BOOST_TEST_SCOPE_SETCOLOR( is_color_output, os, attr, color ) \ + utils::scope_setcolor const sc( \ + os, \ + is_color_output ? utils::attr : utils::term_attr::NORMAL, \ + is_color_output ? utils::color : utils::term_color::ORIGINAL);\ + ut_detail::ignore_unused_variable_warning( sc ) \ /**/ } // namespace utils -- cgit v1.2.3