1// (C) Copyright Gennadiy Rozental 2001-2008. 2// Distributed under the Boost Software License, Version 1.0. 3// (See accompanying file LICENSE_1_0.txt or copy at 4// http://www.boost.org/LICENSE_1_0.txt) 5 6// See http://www.boost.org/libs/test for the library home page. 7// 8// File : $RCSfile$ 9// 10// Version : $Revision: 63640 $ 11// 12// Description : simple implementation for Unit Test Framework parameter 13// handling routines. May be rewritten in future to use some kind of 14// command-line arguments parsing facility and environment variable handling 15// facility 16// *************************************************************************** 17 18#ifndef BOOST_TEST_UNIT_TEST_PARAMETERS_IPP_012205GER 19#define BOOST_TEST_UNIT_TEST_PARAMETERS_IPP_012205GER 20 21// Boost.Test 22#include <boost/test/detail/unit_test_parameters.hpp> 23#include <boost/test/utils/basic_cstring/basic_cstring.hpp> 24#include <boost/test/utils/basic_cstring/compare.hpp> 25#include <boost/test/utils/basic_cstring/io.hpp> 26#include <boost/test/utils/fixed_mapping.hpp> 27#include <boost/test/debug.hpp> 28#include <boost/test/framework.hpp> 29 30// Boost.Runtime.Param 31#include <boost/test/utils/runtime/cla/dual_name_parameter.hpp> 32#include <boost/test/utils/runtime/cla/parser.hpp> 33 34namespace rt = boost::runtime; 35namespace cla = rt::cla; 36 37 38#ifndef UNDER_CE 39#include <boost/test/utils/runtime/env/variable.hpp> 40 41namespace env = rt::env; 42#endif 43 44 45// Boost 46#include <boost/config.hpp> 47#include <boost/test/detail/suppress_warnings.hpp> 48#include <boost/lexical_cast.hpp> 49#include <boost/test/detail/enable_warnings.hpp> 50 51// STL 52#include <map> 53#include <cstdlib> 54#include <iostream> 55#include <fstream> 56 57#include <boost/test/detail/suppress_warnings.hpp> 58 59//____________________________________________________________________________// 60 61# ifdef BOOST_NO_STDC_NAMESPACE 62namespace std { using ::getenv; using ::strncmp; using ::strcmp; } 63# endif 64 65namespace boost { 66 67namespace unit_test { 68 69// ************************************************************************** // 70// ************** input operations for unit_test's enums ************** // 71// ************************************************************************** // 72 73std::istream& 74operator>>( std::istream& in, unit_test::log_level& ll ) 75{ 76 static fixed_mapping<const_string,unit_test::log_level,case_ins_less<char const> > log_level_name( 77 "all" , log_successful_tests, 78 "success" , log_successful_tests, 79 "test_suite" , log_test_units, 80 "unit_scope" , log_test_units, 81 "message" , log_messages, 82 "warning" , log_warnings, 83 "error" , log_all_errors, 84 "cpp_exception" , log_cpp_exception_errors, 85 "system_error" , log_system_errors, 86 "fatal_error" , log_fatal_errors, 87 "nothing" , log_nothing, 88 89 invalid_log_level 90 ); 91 92 std::string val; 93 in >> val; 94 95 ll = log_level_name[val]; 96 BOOST_TEST_SETUP_ASSERT( ll != unit_test::invalid_log_level, "invalid log level " + val ); 97 98 return in; 99} 100 101//____________________________________________________________________________// 102 103std::istream& 104operator>>( std::istream& in, unit_test::report_level& rl ) 105{ 106 fixed_mapping<const_string,unit_test::report_level,case_ins_less<char const> > report_level_name ( 107 "confirm", CONFIRMATION_REPORT, 108 "short", SHORT_REPORT, 109 "detailed", DETAILED_REPORT, 110 "no", NO_REPORT, 111 112 INV_REPORT_LEVEL 113 ); 114 115 std::string val; 116 in >> val; 117 118 rl = report_level_name[val]; 119 BOOST_TEST_SETUP_ASSERT( rl != INV_REPORT_LEVEL, "invalid report level " + val ); 120 121 return in; 122} 123 124//____________________________________________________________________________// 125 126std::istream& 127operator>>( std::istream& in, unit_test::output_format& of ) 128{ 129 fixed_mapping<const_string,unit_test::output_format,case_ins_less<char const> > output_format_name ( 130 "HRF", unit_test::CLF, 131 "CLF", unit_test::CLF, 132 "XML", unit_test::XML, 133 134 unit_test::INV_OF 135 ); 136 137 std::string val; 138 in >> val; 139 140 of = output_format_name[val]; 141 BOOST_TEST_SETUP_ASSERT( of != unit_test::INV_OF, "invalid output format " + val ); 142 143 return in; 144} 145 146//____________________________________________________________________________// 147 148// ************************************************************************** // 149// ************** runtime_config ************** // 150// ************************************************************************** // 151 152namespace runtime_config { 153 154namespace { 155 156// framework parameters and corresponding command-line arguments 157std::string AUTO_START_DBG = "auto_start_dbg"; 158std::string BREAK_EXEC_PATH = "break_exec_path"; 159std::string BUILD_INFO = "build_info"; 160std::string CATCH_SYS_ERRORS = "catch_system_errors"; 161std::string DETECT_FP_EXCEPT = "detect_fp_exceptions"; 162std::string DETECT_MEM_LEAKS = "detect_memory_leaks"; 163std::string LOG_FORMAT = "log_format"; 164std::string LOG_LEVEL = "log_level"; 165std::string LOG_SINK = "log_sink"; 166std::string OUTPUT_FORMAT = "output_format"; 167std::string RANDOM_SEED = "random"; 168std::string REPORT_FORMAT = "report_format"; 169std::string REPORT_LEVEL = "report_level"; 170std::string REPORT_SINK = "report_sink"; 171std::string RESULT_CODE = "result_code"; 172std::string TESTS_TO_RUN = "run_test"; 173std::string SAVE_TEST_PATTERN = "save_pattern"; 174std::string SHOW_PROGRESS = "show_progress"; 175std::string USE_ALT_STACK = "use_alt_stack"; 176 177fixed_mapping<const_string,const_string> parameter_2_env_var( 178 AUTO_START_DBG , "BOOST_TEST_AUTO_START_DBG", 179 BREAK_EXEC_PATH , "BOOST_TEST_BREAK_EXEC_PATH", 180 BUILD_INFO , "BOOST_TEST_BUILD_INFO", 181 CATCH_SYS_ERRORS , "BOOST_TEST_CATCH_SYSTEM_ERRORS", 182 DETECT_FP_EXCEPT , "BOOST_TEST_DETECT_FP_EXCEPTIONS", 183 DETECT_MEM_LEAKS , "BOOST_TEST_DETECT_MEMORY_LEAK", 184 LOG_FORMAT , "BOOST_TEST_LOG_FORMAT", 185 LOG_LEVEL , "BOOST_TEST_LOG_LEVEL", 186 LOG_SINK , "BOOST_TEST_LOG_SINK", 187 OUTPUT_FORMAT , "BOOST_TEST_OUTPUT_FORMAT", 188 RANDOM_SEED , "BOOST_TEST_RANDOM", 189 REPORT_FORMAT , "BOOST_TEST_REPORT_FORMAT", 190 REPORT_LEVEL , "BOOST_TEST_REPORT_LEVEL", 191 REPORT_SINK , "BOOST_TEST_REPORT_SINK", 192 RESULT_CODE , "BOOST_TEST_RESULT_CODE", 193 TESTS_TO_RUN , "BOOST_TESTS_TO_RUN", 194 SAVE_TEST_PATTERN , "BOOST_TEST_SAVE_PATTERN", 195 SHOW_PROGRESS , "BOOST_TEST_SHOW_PROGRESS", 196 USE_ALT_STACK , "BOOST_TEST_USE_ALT_STACK", 197 198 "" 199); 200 201//____________________________________________________________________________// 202 203// storage for the CLAs 204cla::parser s_cla_parser; 205std::string s_empty; 206 207output_format s_report_format; 208output_format s_log_format; 209 210//____________________________________________________________________________// 211 212template<typename T> 213T 214retrieve_parameter( const_string parameter_name, cla::parser const& s_cla_parser, T const& default_value = T(), T const& optional_value = T() ) 215{ 216 rt::const_argument_ptr arg = s_cla_parser[parameter_name]; 217 if( arg ) { 218 if( rtti::type_id<T>() == rtti::type_id<bool>() || 219 !static_cast<cla::parameter const&>( arg->p_formal_parameter.get() ).p_optional_value ) 220 return s_cla_parser.get<T>( parameter_name ); 221 222 optional<T> val = s_cla_parser.get<optional<T> >( parameter_name ); 223 if( val ) 224 return *val; 225 else 226 return optional_value; 227 } 228 229 boost::optional<T> v; 230 231#ifndef UNDER_CE 232 env::get( parameter_2_env_var[parameter_name], v ); 233#endif 234 235 if( v ) 236 return *v; 237 else 238 return default_value; 239} 240 241//____________________________________________________________________________// 242 243} // local namespace 244 245void 246init( int& argc, char** argv ) 247{ 248 using namespace cla; 249 250 try { 251 s_cla_parser - cla::ignore_mismatch 252 << cla::dual_name_parameter<bool>( AUTO_START_DBG + "|d" ) 253 - (cla::prefix = "--|-",cla::separator = "=| ",cla::guess_name,cla::optional, 254 cla::description = "Automatically starts debugger if system level error (signal) occurs") 255 << cla::named_parameter<std::string>( BREAK_EXEC_PATH ) 256 - (cla::prefix = "--",cla::separator = "=",cla::guess_name,cla::optional, 257 cla::description = "For the exception safety testing allows to break at specific execution path") 258 << cla::dual_name_parameter<bool>( BUILD_INFO + "|i" ) 259 - (cla::prefix = "--|-",cla::separator = "=| ",cla::guess_name,cla::optional, 260 cla::description = "Shows library build information" ) 261 << cla::dual_name_parameter<bool>( CATCH_SYS_ERRORS + "|s" ) 262 - (cla::prefix = "--|-",cla::separator = "=| ",cla::guess_name,cla::optional, 263 cla::description = "Allows to switch between catching and ignoring system errors (signals)") 264 << cla::named_parameter<bool>( DETECT_FP_EXCEPT ) 265 - (cla::prefix = "--",cla::separator = "=",cla::guess_name,cla::optional, 266 cla::description = "Allows to switch between catching and ignoring floating point exceptions") 267 << cla::named_parameter<long>( DETECT_MEM_LEAKS ) 268 - (cla::prefix = "--",cla::separator = "=",cla::guess_name,cla::optional, 269 cla::description = "Allows to switch between catching and ignoring memory leaks") 270 << cla::dual_name_parameter<unit_test::output_format>( LOG_FORMAT + "|f" ) 271 - (cla::prefix = "--|-",cla::separator = "=| ",cla::guess_name,cla::optional, 272 cla::description = "Specifies log format") 273 << cla::dual_name_parameter<unit_test::log_level>( LOG_LEVEL + "|l" ) 274 - (cla::prefix = "--|-",cla::separator = "=| ",cla::guess_name,cla::optional, 275 cla::description = "Specifies log level") 276 << cla::dual_name_parameter<std::string>( LOG_SINK + "|k" ) 277 - (cla::prefix = "--|-",cla::separator = "=| ",cla::guess_name,cla::optional, 278 cla::description = "Specifies log sink:stdout(default),stderr or file name") 279 << cla::dual_name_parameter<unit_test::output_format>( OUTPUT_FORMAT + "|o" ) 280 - (cla::prefix = "--|-",cla::separator = "=| ",cla::guess_name,cla::optional, 281 cla::description = "Specifies output format (both log and report)") 282 << cla::dual_name_parameter<int>( RANDOM_SEED + "|a" ) 283 - (cla::prefix = "--|-",cla::separator = "=| ",cla::guess_name,cla::optional,cla::optional_value, 284 cla::description = "Allows to switch between sequential and random order of test units execution.\n" 285 "Optionally allows to specify concrete seed for random number generator") 286 << cla::dual_name_parameter<unit_test::output_format>( REPORT_FORMAT + "|m" ) 287 - (cla::prefix = "--|-",cla::separator = "=| ",cla::guess_name,cla::optional, 288 cla::description = "Specifies report format") 289 << cla::dual_name_parameter<unit_test::report_level>(REPORT_LEVEL + "|r") 290 - (cla::prefix = "--|-",cla::separator = "=| ",cla::guess_name,cla::optional, 291 cla::description = "Specifies report level") 292 << cla::dual_name_parameter<std::string>( REPORT_SINK + "|e" ) 293 - (cla::prefix = "--|-",cla::separator = "=| ",cla::guess_name,cla::optional, 294 cla::description = "Specifies report sink:stderr(default),stdout or file name") 295 << cla::dual_name_parameter<bool>( RESULT_CODE + "|c" ) 296 - (cla::prefix = "--|-",cla::separator = "=| ",cla::guess_name,cla::optional, 297 cla::description = "Allows to disable test modules's result code generation") 298 << cla::dual_name_parameter<std::string>( TESTS_TO_RUN + "|t" ) 299 - (cla::prefix = "--|-",cla::separator = "=| ",cla::guess_name,cla::optional, 300 cla::description = "Allows to filter which test units to run") 301 << cla::named_parameter<bool>( SAVE_TEST_PATTERN ) 302 - (cla::prefix = "--",cla::separator = "=",cla::guess_name,cla::optional, 303 cla::description = "Allows to switch between saving and matching against test pattern file") 304 << cla::dual_name_parameter<bool>( SHOW_PROGRESS + "|p" ) 305 - (cla::prefix = "--|-",cla::separator = "=| ",cla::guess_name,cla::optional, 306 cla::description = "Turns on progress display") 307 << cla::named_parameter<bool>( USE_ALT_STACK ) 308 - (cla::prefix = "--",cla::separator = "=",cla::guess_name,cla::optional, 309 cla::description = "Turns on/off usage of an alternative stack for signal handling") 310 311 << cla::dual_name_parameter<bool>( "help|?" ) 312 - (cla::prefix = "--|-",cla::separator = "=",cla::guess_name,cla::optional, 313 cla::description = "this help message") 314 ; 315 316 s_cla_parser.parse( argc, argv ); 317 318 if( s_cla_parser["help"] ) { 319 s_cla_parser.help( std::cout ); 320 throw framework::nothing_to_test(); 321 } 322 323 s_report_format = retrieve_parameter( REPORT_FORMAT, s_cla_parser, unit_test::CLF ); 324 s_log_format = retrieve_parameter( LOG_FORMAT, s_cla_parser, unit_test::CLF ); 325 326 unit_test::output_format of = retrieve_parameter( OUTPUT_FORMAT, s_cla_parser, unit_test::INV_OF ); 327 328 if( of != unit_test::INV_OF ) 329 s_report_format = s_log_format = of; 330 } 331 catch( rt::logic_error const& ex ) { 332 std::ostringstream err; 333 334 err << "Fail to process runtime parameters: " << ex.msg() << std::endl; 335 s_cla_parser.usage( err ); 336 337 throw framework::setup_error( err.str() ); 338 } 339} 340 341//____________________________________________________________________________// 342 343unit_test::log_level 344log_level() 345{ 346 return retrieve_parameter( LOG_LEVEL, s_cla_parser, unit_test::log_all_errors ); 347} 348 349//____________________________________________________________________________// 350 351bool 352no_result_code() 353{ 354 return !retrieve_parameter( RESULT_CODE, s_cla_parser, true ); 355} 356 357//____________________________________________________________________________// 358 359unit_test::report_level 360report_level() 361{ 362 return retrieve_parameter( REPORT_LEVEL, s_cla_parser, unit_test::CONFIRMATION_REPORT ); 363} 364 365//____________________________________________________________________________// 366 367const_string 368test_to_run() 369{ 370 static std::string s_test_to_run = retrieve_parameter( TESTS_TO_RUN, s_cla_parser, s_empty ); 371 372 return s_test_to_run; 373} 374 375//____________________________________________________________________________// 376 377const_string 378break_exec_path() 379{ 380 static std::string s_break_exec_path = retrieve_parameter( BREAK_EXEC_PATH, s_cla_parser, s_empty ); 381 382 return s_break_exec_path; 383} 384 385//____________________________________________________________________________// 386 387bool 388save_pattern() 389{ 390 return retrieve_parameter( SAVE_TEST_PATTERN, s_cla_parser, false ); 391} 392 393//____________________________________________________________________________// 394 395bool 396show_progress() 397{ 398 return retrieve_parameter( SHOW_PROGRESS, s_cla_parser, false ); 399} 400 401//____________________________________________________________________________// 402 403bool 404show_build_info() 405{ 406 return retrieve_parameter( BUILD_INFO, s_cla_parser, false ); 407} 408 409//____________________________________________________________________________// 410 411bool 412catch_sys_errors() 413{ 414 return retrieve_parameter( CATCH_SYS_ERRORS, s_cla_parser, 415#ifdef BOOST_TEST_DEFAULTS_TO_CORE_DUMP 416 false 417#else 418 true 419#endif 420 ); 421} 422 423//____________________________________________________________________________// 424 425bool 426auto_start_dbg() 427{ 428 // !! set debugger as an option 429 return retrieve_parameter( AUTO_START_DBG, s_cla_parser, false ); 430; 431} 432 433//____________________________________________________________________________// 434 435bool 436use_alt_stack() 437{ 438 return retrieve_parameter( USE_ALT_STACK, s_cla_parser, true ); 439} 440 441//____________________________________________________________________________// 442 443bool 444detect_fp_exceptions() 445{ 446 return retrieve_parameter( DETECT_FP_EXCEPT, s_cla_parser, false ); 447} 448 449//____________________________________________________________________________// 450 451output_format 452report_format() 453{ 454 return s_report_format; 455} 456 457//____________________________________________________________________________// 458 459output_format 460log_format() 461{ 462 return s_log_format; 463} 464 465//____________________________________________________________________________// 466 467std::ostream* 468report_sink() 469{ 470 std::string sink_name = retrieve_parameter( REPORT_SINK, s_cla_parser, s_empty ); 471 472 if( sink_name.empty() || sink_name == "stderr" ) 473 return &std::cerr; 474 475 if( sink_name == "stdout" ) 476 return &std::cout; 477 478 static std::ofstream log_file( sink_name.c_str() ); 479 return &log_file; 480} 481 482//____________________________________________________________________________// 483 484std::ostream* 485log_sink() 486{ 487 std::string sink_name = retrieve_parameter( LOG_SINK, s_cla_parser, s_empty ); 488 489 if( sink_name.empty() || sink_name == "stdout" ) 490 return &std::cout; 491 492 if( sink_name == "stderr" ) 493 return &std::cerr; 494 495 static std::ofstream report_file( sink_name.c_str() ); 496 return &report_file; 497} 498 499//____________________________________________________________________________// 500 501long 502detect_memory_leaks() 503{ 504 return retrieve_parameter( DETECT_MEM_LEAKS, s_cla_parser, static_cast<long>(1) ); 505} 506 507//____________________________________________________________________________// 508 509int 510random_seed() 511{ 512 return retrieve_parameter( RANDOM_SEED, s_cla_parser, 0, 1 ); 513} 514 515//____________________________________________________________________________// 516 517} // namespace runtime_config 518 519} // namespace unit_test 520 521} // namespace boost 522 523//____________________________________________________________________________// 524 525#include <boost/test/detail/enable_warnings.hpp> 526 527#endif // BOOST_TEST_UNIT_TEST_PARAMETERS_IPP_012205GER 528