diff --git a/build/Jamfile.v2 b/build/Jamfile.v2 index c33ab1d6..c36c1aa9 100644 --- a/build/Jamfile.v2 +++ b/build/Jamfile.v2 @@ -14,10 +14,9 @@ project boost/test msvc:-wd4673 #gcc:-std=gnu++0x clang:-Wno-c99-extensions + clang:-Wno-variadic-macros all # on - gcc:-std=c++11 - clang:-std=c++11 # adding a dependency on boost/timer as the header are needed, and the junction needs # to be there in order to build the library. diff --git a/doc/adv_scenarios/test_module_runner_overview.qbk b/doc/adv_scenarios/test_module_runner_overview.qbk index e6948337..ebcc40ce 100644 --- a/doc/adv_scenarios/test_module_runner_overview.qbk +++ b/doc/adv_scenarios/test_module_runner_overview.qbk @@ -33,7 +33,7 @@ The test runner may return one of the following values: [[Value][Meaning]] [[`boost::exit_success`][ * No errors occurred during testing, or -* the success result was forced with command-line argument `--[link boost_test.utf_reference.rt_param_reference.result_code `result_code`]=no`.]] +* the success result was forced with command-line argument `--__param_result_code__=no`.]] [[`boost::exit_test_failure`][ * Non-fatal errors detected and no uncaught exceptions were thrown during testing, or * the initialization of the __UTF__ failed. ]] diff --git a/doc/closing_chapters/change_log.qbk b/doc/closing_chapters/change_log.qbk index 54c665d3..d8149d63 100644 --- a/doc/closing_chapters/change_log.qbk +++ b/doc/closing_chapters/change_log.qbk @@ -18,8 +18,8 @@ * support for declaring [link boost_test.tests_organization.tests_dependencies dependencies] over test cases * attributes for [link boost_test.tests_organization.enabling enabling or disabling] test execution based on static, compile-time or runtime rules * extended [link boost_test.runtime_config.test_unit_filtering unit test filtering] from the command line (negation, labels, ...) -* color output with [link boost_test.utf_reference.rt_param_reference.color_output `color_output`] -* test bed listing with [link boost_test.utf_reference.rt_param_reference.list_content `list_content`] +* color output with __param_color_output__ +* test bed listing with __param_list_content__ * rewritten documentation using quickbook [/* now having a more accurate timing (see [ticket 7397]) for the tests. Old format is still available through the command line option __param_deprecated_timer_format__ diff --git a/doc/examples/example51.run.cpp b/doc/examples/example51.run.cpp index 1984ff96..dad6a79a 100644 --- a/doc/examples/example51.run.cpp +++ b/doc/examples/example51.run.cpp @@ -13,7 +13,7 @@ using namespace boost::unit_test; BOOST_AUTO_TEST_CASE( test_case0 ) { - if( runtime_config::get( runtime_config::LOG_LEVEL ) < log_warnings ) + if( runtime_config::log_level() < log_warnings ) unit_test_log.set_threshold_level( log_warnings ); BOOST_WARN( sizeof(int) > 4 ); diff --git a/doc/prod_use/program_execution_monitor.qbk b/doc/prod_use/program_execution_monitor.qbk index 1af61077..404d3fc9 100644 --- a/doc/prod_use/program_execution_monitor.qbk +++ b/doc/prod_use/program_execution_monitor.qbk @@ -100,8 +100,7 @@ environment variables. ] -[note `BOOST_TEST_CATCH_SYSTEM_ERRORS` is similar to the __UTF__'s - [link boost_test.utf_reference.rt_param_reference.catch_system `catch_system_error`] command line parameter.] +[note `BOOST_TEST_CATCH_SYSTEM_ERRORS` is similar to the __UTF__'s __param_catch_system__ command line parameter.] [endsect] [/ configuration] diff --git a/doc/runtime_configuration/runtime_config_reference.qbk b/doc/runtime_configuration/runtime_config_reference.qbk index 6a10f820..d456bd74 100644 --- a/doc/runtime_configuration/runtime_config_reference.qbk +++ b/doc/runtime_configuration/runtime_config_reference.qbk @@ -8,620 +8,236 @@ [section:rt_param_reference Runtime parameters reference] -Following sections provide detailed specification for all __UTF__ runtime parameters. Each parameter specification includes: +Each parameter specification includes: -* The full parameter name. -* Description of parameter semantic and default value. -* Acceptable argument values. The default value for the parameter is bold in the acceptable values list. -* Command line syntax. The format of all command line arguments is: []. For example: --param=. - [] around separator and value indicate that argument value is optional. For example: -q[ ]. -* Corresponding environment variable name. +# the full parameter name +# corresponding environment variable name +# command line argument name +# acceptable values and +# a long description -[note All command line argument formats support parameter name guessing. What this means is that is if command like -format is like this: -[pre --long_parameter_name=] -you can in fact use any unambiguous prefix of the parameter name to specify the argument. For example: -[pre --long_param=123] -or -[pre --long_p=123.] -If parameter name prefix you chose is ambiguous the framework lets you know which parameters match specified -prefix. For example, try -[pre --log=all] -] +The default value for the parameter is bold in the +acceptable values list. All values are case sensitive and are required to exactly match the parameter specification. -[h4 Parameter value formats] -The __UTF__ runtime parameters take value of the following types: string, boolean, enumeration, -unsigned, long. Formats required for values of these types are following: - -[h5 String, unsigned, long][#regular_param_value] - -Values of these types are expected in the same format they are represented in C++. - -[h5 Boolean][#boolean_param_value] - -Values of these types are options with yes/no or true/false meaning. True values are represented -by case insensitive strings: "Y", "YES", "TRUE", "1". False values are represented by case -insensitive strings: "N", "NO", "FALSE", "0". - -[h5 Enumeration][#enum_param_value] - -Values of a enumeration type are expected as case sensitive strings representing -enumeration value names. Each parameter with a enumeration value lists all valid names in a -parameter`s description. [/ ###############################################################################################] -[section:auto_dbg `auto_start_dbg`] +[section:show_progress `show_progress`] -Option ['auto_start_dbg] specifies whether Boost.Test should attempt to attach a debugger when a 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 a different debugger. -For more details on how to configure a debugger see the [headerref boost/test/debug.hpp Boost.Test debug API], -specifically the function [funcref boost::debug::set_debugger]. +Makes the framework to print progress information. More details [link boost_test.test_output.test_output_progress here]. [h4 Acceptable values] -[link boolean_param_value Boolean] with default value [*no]. - -[h4 Command line syntax] - -* --auto_debug[=] -* -d [] +* [*no] (default) +* yes [h4 Environment variable] -BOOST_TEST_AUTO_START_DBG + BOOST_TEST_SHOW_PROGRESS -[endsect] [/auto_start_dbg] +[endsect] [/ ###############################################################################################] [section:build_info `build_info`] -Option ['build_info] instructs the __UTF__ to display the build information before testing begins. -This information includes: +Print build information that include: * platform * compiler -* STL implementation in use +* STL implementation in use and * boost version [h4 Acceptable values] -[link boolean_param_value Boolean] with default value [*no]. - -[h4 Command line syntax] - -* --build_info[=] -* -i [] +* [*no] (default) +* yes [h4 Environment variable] -BOOST_TEST_BUILD_INFO + BOOST_TEST_BUILD_INFO [endsect] [/ build_info] [/ ###############################################################################################] -[section:catch_system `catch_system_errors`] -If option ['catch_system_errors] has value "no" the __UTF__ does not attempt to catch asynchronous system failures -(signals on *NIX platforms or structured exceptions on Windows). This can be used for test programs executed -within an IDE or to get a coredump for a stack analysis. See -[link ref_usage_recommendations usage recommendations] pages for more details. +[section:auto_dbg `auto_start_dbg`] + +Automatically attach debugger in case of system failure. + +Specifies whether Boost.Test should try to attach a debugger in case if fatal system error occurs. If value is ['yes] +the default debugger configured for the platform is going to be attempted. Alternatively the debugger identified +by the argument value of the parameter is used. For more details on advanced debugger support in Boost.Test check +the [headerref boost/test/debug.hpp section dedicated to Boost.Test debug API], in particular the function [funcref boost::debug::set_debugger]. [h4 Acceptable values] -[link boolean_param_value Boolean] with default value [*no]. - -[note The __UTF__ can be built with flag BOOST_TEST_DEFAULTS_TO_CORE_DUMP in which case default changes to [*yes]] - -[h4 Command line syntax] - -* --catch_system_errors[=] -* -s [] +* [*no] +* yes +* ['debugger identifier] [h4 Environment variable] -BOOST_TEST_CATCH_SYSTEM_ERRORS + BOOST_TEST_AUTO_START_DBG + + +[warning There is a link to the Boost.Test debug API, never heard about] +[endsect] [/auto_start_dbg] + + + +[/ ###############################################################################################] +[section:catch_system `catch_system_errors`] + +Value "no" prohibits the framework from catching asynchronous system events. This could be used for test programs +executed within GUI or to get a coredump for stack analysis. See [link ref_usage_recommendations usage recommendations] pages for more details. + +[h4 Acceptable values] + +* [*yes] (default) +* no + +[h4 Environment variable] + + BOOST_TEST_CATCH_SYSTEM_ERRORS [endsect] [/catch_system_errors] [/ ###############################################################################################] -[section:color_output `color_output`] +[section:break_exec_path `break_exec_path`] -The __UTF__ is able to produce color output on systems which support it. To enable this behavior, set this option to -`yes`. By default the framework does not produce color output. +this runtime parameter is used by exception safety tester. By default exception safety tester only reports index of +execution path and test case name where failure occurred. Using this parameter you can make the tester to break the +execution right before entering this path. [h4 Acceptable values] -[link boolean_param_value Boolean] with default value [*no]. - -[h4 Command line syntax] - -* --color_output[=] -* -x [] +* string consisting of space separate test_name:execution_path_number pairs [h4 Environment variable] -BOOST_TEST_COLOR_OUTPUT + BOOST_TEST_BREAK_EXEC_PATH + +[endsect] [/break_exec_path] + +[/ ###############################################################################################] +[section:color_output `color_output`] + +The __UTF__ is able to produce color output on systems which supports it. To enable this behavior set the parameter to +`yes`. By default the output produces in not colored. + + +[h4 Acceptable values] + +* [*no] (default) +* yes + + +[h4 Environment variable] + + BOOST_TEST_COLOR_OUTPUT [endsect] [/color_output] -[/ ###############################################################################################] -[section:detect_fp_exceptions `detect_fp_exceptions`] - -Option ['build_info] enables/disables hardware traps for the floating point exceptions (if supported on your platform). - -[h4 Acceptable values] - -[link boolean_param_value Boolean] with default value [*no]. - -[h4 Command line syntax] - -* --detect_fp_exceptions[=] - -[h4 Environment variable] - -BOOST_TEST_DETECT_FP_EXCEPTIONS - -[endsect] [/detect_fp_exceptions] - -[/ ###############################################################################################] -[section:detect_memory_leaks `detect_memory_leaks`] - -Parameter ['detect_memory_leaks] enables/disables memory leaks detection (if present in your build configuration). -This parameter has an optional long integer value. The default value is 1, which enables 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 -framework to setup runtime breakpoint at Nth heap allocation. If value is omitted the default value is assumed. - -[note The only platform which supports memory leak detection is Microsoft Visual Studio family of compilers in debug builds.] - -[h4 Acceptable values] - -* 0 -* [*1] (default) -* [link regular_param_value long integer value] > 1 - -[h4 Command line syntax] - -* --detect_memory_leaks[=] - -[h4 Environment variable] - -BOOST_TEST_DETECT_MEMORY_LEAK - -[endsect] [/detect_memory_leaks] - -[/ ###############################################################################################] -[section:help `help`] - -Parameter ['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 or ambiguous error is reported. If argument value is absent, a summary of all framework's -parameter is displayed. - -[h4 Acceptable values] - -An optional parameter name [link regular_param_value string]. - -[h4 Command line syntax] - -* --help[=] - -[endsect] [/help] - -[/ ###############################################################################################] -[section:list_content `list_content`] - -Parameter ['list_content] instructs the __UTF__ to list the content of the test module instead of executing test cases. -Parameter accepts optional string value indicating the format of the output. Currently the framework supports two formats: -human readable format (HRF) and dot graph format (DOT). If a value is omitted HRF value is assumed. - -In human readable format information about the test suites and test cases is presented in a tree like form with -each test unit name on a separate line with horizontal indentation in relation to the parent test suite. In addition test -units which are enabled by default have an '*' next to the test unit name. For example, the following output: - - testsuite1* - testcase1* - testcase2 - testsuite2* - testcase3* - -represents test module consisting of two test suites: testsuite1 and testsuite2, and three test cases: testcase1, -testcase2, and testcase3. The first two test cases belong to the first test suite and last one belongs to the second. Out of -three test cases only two are enabled by default: testcase1 and testcase3. testcase2 is not enabled by default, but can -be enabled by using the parameter __param_run_test__. - -DOT output generates a graph representing a test module tree in a [@http://www.graphviz.org/doc/info/lang.html dot format]. -This output includes much more information about the test tree including labels, timeouts, expected failures, and dependencies. - -[h4 Acceptable values] - -[link enum_param_value Enumeration] names: - -* [*HRF] (default) -* DOT - -[h4 Command line syntax] - -* --list_content[=] - -[h4 Environment variable] - -BOOST_TEST_LIST_CONTENT - -[endsect] [/list_content] - -[/ ###############################################################################################] -[section:list_labels `list_labels`] - -Option ['list_labels] instructs the __UTF__ to list all the the labels defined in the test module instead -of executing test cases. - -[h4 Acceptable values] - -[link boolean_param_value Boolean] with default value [*no]. - -[h4 Command line syntax] - -* --list_labels[=] - -[h4 Environment variable] - -BOOST_TEST_LIST_LABELS - -[endsect] [/list_labels] - [/ ###############################################################################################] [section:log_format `log_format`] -Parameter ['log_format] allows to set the __UTF__ log format to one of the formats supplied by the framework. -To specify custom log format use the [link ref_log_formatter_api custom log formatting API]. - -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 the testing log. This format -is similar to a compiler error format. Alternatively you can specify XML as a log format. This format -is easier to process by testing automation tools. +Allows selecting the __UTF__ log format from the list of formats supplied by the framework. To specify custom log +format use the [link ref_log_formatter_api custom log formatting API]. [h4 Acceptable values] -[link enum_param_value Enumeration] names: - * [*HRF] (default) * XML -[h4 Command line syntax] - -* --log_format= -* -f - -[h4 Environment variable] - -BOOST_TEST_LOG_FORMAT - -[endsect] [/log_format] - -[/ ###############################################################################################] -[section:log_level `log_level`] - -Parameter ['log_level] allows to set the __UTF__ [link ref_log_level_explanations log level]. Log level defines -the verbosity of the testing log produced by a testing module. The verbosity ranges from a complete log, when all -assertions (both successful and failing) are reported and all notifications about test units start and finish -are included, to an empty log, when nothing is reported to a testing log stream. - -Log level is set to one of the predefined levels which are organized hierarchically, where each level includes -all the messages on that level as well as all the messages from levels below. Levels are identified by string -names, which are listed next. - -[h4 Acceptable values] - -Following is the list of [link enum_param_value enumeration] log_level names ordered from higher to lower level. -Thus each level includes messages on that level as well as all the messages on levels defined below. - -[table - [ - [Value] - [Included messages] - ] - [ - [all] - [All log messages including the passed assertions notification] - ] - [ - [success] - [The same as all] - ] - [ - [test_suite] - [Test units start/finish notifications] - ] - [ - [message] - [User generated messages (using BOOST_MESSAGE tool)] - ] - [ - [warning] - [Messages describing failed assertion on WARN level (BOOST_WARN_... tools)] - ] - [ - [[*error] (default)] - [Messages describing failed assertion on CHECK level (BOOST_WARN_... tools)] - ] - [ - [cpp_exception] - [Messages reporting uncaught C++ exception] - ] - [ - [system_error] - [Messages reporting system originated non-fatal errors. For example, timeout or floating point exception.] - ] - [ - [fatal_error] - [Messages reporting user or system originated fatal errors. For example, memory access violation. Also - all the messages describing failed assertion on REQUIRE level (BOOST_REQUIRE_... tools)] - ] - [ - [nothing] - [No messages are reported.] - ] -] - -[h4 Command line syntax] - -* --log_level= -* -l - -[h4 Environment variable] - -BOOST_TEST_LOG_LEVEL - -[endsect] [/log_level] - -[/ ###############################################################################################] -[section:log_sink `log_sink`] - -Parameter ['log_sink] allows to set the log sink - location where framework writes the testing log to, -thus it allows to easily redirect the testing log to file or standard streams. By default testing log -is directed to the standard output stream. - -[h4 Acceptable values] - -Case sensitive [link regular_param_value string]: - -[table - [ - [Value] - [Meaning] - ] - [ - [[*`stdout`] (default)] - [Testing log is redirected into standard output stream] - ] - [ - [stderr] - [Testing log is redirected into standard error stream] - ] - [ - [File name] - [Testing log is redirected into this file] - ] -] - -[h4 Command line syntax] - -* --log_sink= -* -k - -[h4 Environment variable] - -BOOST_TEST_LOG_SINK - -[endsect] [/log_sink] - -[/ ###############################################################################################] -[section:output_format `output_format`] - -Parameter ['output_format] combines an effect of -[link boost_test.utf_reference.rt_param_reference.report_format `report_format`] and -[link boost_test.utf_reference.rt_param_reference.log_format `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 have -a default value. The only acceptable values are string names of output formats: HRF - human readable -format and XML - XML formats for automation tools processing. - -[h4 Acceptable values] - -[link enum_param_value Enumeration] name: - -* HRF -* XML - ['HRF] stands for human readable format, while ['XML] is dedicated to automated output processing -[h4 Command line syntax] - -* --output_format= -* -o - [h4 Environment variable] -BOOST_TEST_OUTPUT_FORMAT + BOOST_TEST_LOG_FORMAT + +[endsect] [/log_format] -[endsect] [/output_format] [/ ###############################################################################################] -[section:random `random`] +[section:log_level `log_level`] -Parameter ['random] instructs the __UTF__ 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 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. - -[h4 Acceptable values] +Allows setting the __UTF__ [link ref_log_level_explanations log level] in a range from a +complete log, when all successful tests are confirmed and all test suite messages are included, to an empty +log when nothing is logged a test output stream. -* [*0] (default) -* 1 -* [link regular_param_value integer] value > 1 - -[h4 Command line syntax] - -* --random= - -[h4 Environment variable] - -BOOST_TEST_RANDOM - -[endsect] [/random] - -[/ ###############################################################################################] -[section:report_format `report_format`] - -Parameter ['report_format] allows to set the __UTF__ report format to one of the formats supplied -by the framework. To specify a custom report format use unit_test_report API. - -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 specify -XML as report format. This format is easier to process by testing automation tools. - -[/TODO: unit_test_report API] - -[h4 Acceptable values] - -[link enum_param_value Enumeration] names: - -* [*HRF] (default) -* XML - -[h4 Command line syntax] - -* --report_format= -* -m - -[h4 Environment variable] - -BOOST_TEST_REPORT_FORMAT - -[endsect] [/report_format] - -[/ ###############################################################################################] -[section:report_level `report_level`] - -Parameter ['report_level] allows to set the verbosity level of the testing result report generated by -the __UTF__. Use value "no" to eliminate the results report completely. See the -[link ref_report_formats report formats] section for description of report formats on different levels. +[note Log levels are accumulating, in other words each log level includes also all the information reported by less restrictive ones.] + [h4 Acceptable values] -[link enum_param_value Enumeration] report_level names: +[table Log levels + [ + [value] + [feature] + ] + [ + [all] + [report all log messages including the passed test notification] + ] + [ + [success] + [the same as all] + ] + [ + [test_suite] + [Shows test suite messages] + ] + [ + [message] + [Shows user messages] + ] + [ + [warning] + [Reports warnings issued by user] + ] + [ + [[*error] (default)] + [Reports all error conditions] + ] + [ + [cpp_exception] + [Reports uncaught C++ exception] + ] + [ + [system_error] + [Reports system originated non-fatal errors. For example, timeout or floating point exception.] + ] + [ + [fatal_error] + [Reports only user or system originated fatal errors. For example, memory access violation.] + ] + [ + [nothing] + [Does not report any information.] + ] -* [*confirm] (default) -* no -* short -* detailed +] -[h4 Command line syntax] - -* --report_level= -* -r [h4 Environment variable] -BOOST_TEST_REPORT_LEVEL + BOOST_TEST_LOG_LEVEL -[endsect] [/report_level] - -[/ ###############################################################################################] -[section:report_memory_leaks_to `report_memory_leaks_to`] - -Parameter ['report_memory_leaks_to] allows to specify a file where to report memory leaks to. The -parameter does not have default value. If it is not specified, memory leaks (if any) are reported -to the standard error stream. - -[h4 Acceptable values] - -Arbitrary file name [link regular_param_value string]. - -[h4 Command line syntax] - -* --report_memory_leaks_to= - -[h4 Environment variable] - -BOOST_TEST_REPORT_MEMORY_LEAKS_TO - -[endsect] [/report_sink] - -[/ ###############################################################################################] -[section:report_sink `report_sink`] - -Parameter ['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 standard error stream. - -[h4 Acceptable values] - -Case sensitive [link regular_param_value string]: - -* [*`stderr`] (default) -* `stdout` -* arbitrary file name - -[h4 Command line syntax] - -* --report_synk= -* -e - -[h4 Environment variable] - -BOOST_TEST_REPORT_SINK - -[endsect] [/report_sink] - -[/ ###############################################################################################] -[section:result_code `result_code`] - -The "no" argument value for the option [`result_code] instructs the __UTF__ to always return zero -result code. This could be used for test programs executed within IDE. By default this parameter has -value "yes". See the [link ref_usage_recommendations usage recommendations] section for more details. - -[h4 Acceptable values] - -[link boolean_param_value Boolean] with default value [*yes]. - -[h4 Command line syntax] - -* --result_code[=] -* -c [] - -[h4 Environment variable] - -BOOST_TEST_RESULT_CODE - -[endsect] [/result_code] +[endsect] [/log_level] [/ ###############################################################################################] [section:run_test `run_test`] -Parameter ['run_test] allows to filter which test units to execute during testing. The __UTF__ 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 -enabling/disabling test units at compile time. These settings identify the default set of test units -to run. Parameter ['run_test] is used to change this default. This parameter is repeatable, so you can -specify more than one filter if necessary. - -More details about practical application of this parameter resides in [link boost_test.runtime_config.test_unit_filtering test unit -filtering] section. +Specifies the tests to run. It can be specified more than once. [h4 Acceptable values] -[link regular_param_value String] value representing single filter. The following grammar productions -describe the syntax of filters: +The following grammar productions describe the syntax of allowed values: ``` -filter ::= relative_spec? test_set +value ::= relative_spec? test_set relative_spec ::= '+' | '!' test_set ::= label | path label ::= '@' identifier @@ -633,134 +249,259 @@ pattern ::= '*'? identifier '*'? Regarding the meaning of these values [link ref_command_line_control see here]. -[h4 Command line syntax] - -* --run_test= -* -t - [h4 Environment variable] -BOOST_TESTS_TO_RUN + BOOST_TESTS_TO_RUN [endsect] [/run_test] +[/ ###############################################################################################] +[section:output_format `output_format`] + +Combines an effect of __param_report_format__ and __param_log_format__ parameters. Has higher priority than either one of them if specified. + +[h4 Acceptable values] + +* [*HRF] (default) +* XML + +['HRF] stands for human readable format, while ['XML] is dedicated to automated output processing + +[h4 Environment variable] + + BOOST_TEST_OUTPUT_FORMAT + +[endsect] [/output_format] + +[/ ###############################################################################################] +[section:report_format `report_format`] + +Allows selecting the __UTF__ report format from the list of formats supplied by the framework. To specify a custom report format use unit_test_report API. + +[warning Provide something concrete to the user] + +[h4 Acceptable values] + +* [*HRF] (default) +* XML + +['HRF] stands for human readable format, while ['XML] is dedicated to automated output processing + +[h4 Environment variable] + + BOOST_TEST_REPORT_FORMAT + +[endsect] [/report_format] + +[/ ###############################################################################################] +[section:result_code `result_code`] + +Value "no" enforces the framework to always return zero result code. This could be used for test programs +executed within GUI. See the [link ref_usage_recommendations usage recommendations] section for more details. + +[h4 Acceptable values] + +* [*yes] (default) +* no + +[h4 Environment variable] + + BOOST_TEST_RESULT_CODE + +[endsect] [/result_code] + +[/ ###############################################################################################] +[section:report_level `report_level`] + +Allows setting the level of details carried by the testing results report generated by the framework. Use value +"no" to eliminate the results report completely. See the +[link ref_tests_report test report] section for description of different report formats. + +[h4 Acceptable values] + +* [*confirm] (default) +* no +* short +* detailed + +[h4 Environment variable] + + BOOST_TEST_REPORT_LEVEL + +[endsect] [/report_level] + +[/ ###############################################################################################] +[section:random `random`] + +Runs the tests in random order. + +Positive value makes the framework to run the test cases in random order. Also if this value is greater than 1, +it is used as a random seed. In other case random seed is generated based on current time. + +[caution If computed from time, the seed is not outputted to the report] + +[h4 Acceptable values] + +* [*0] (default) +* 1 +* integer value > 1 + +[h4 Environment variable] + + BOOST_TEST_RANDOM + +[endsect] [/random] + +[/ ###############################################################################################] +[section:detect_memory_leaks `detect_memory_leaks`] + +Detect memory leaks. + +Positive value tells the framework to detect the memory leaks (if any). In addition any value greater than 1 +is treated as leak allocation number and setups runtime breakpoint. In other words setting this parameter to +the positive value N greater than 1 causes the framework to set a breakpoint at Nth memory allocation (don't +do that from the command line - only when you are under debugger). + +[note If your test program produces memory +leaks notifications, they are combined with allocation number values you could use to set a breakpoint.] + +[caution Currently only applies to MS family of compilers in debug builds.] + +[h4 Acceptable values] + +* 0 +* [*1] (default) +* integer value > 1 + +[h4 Environment variable] + + BOOST_TEST_DETECT_MEMORY_LEAK + +[endsect] [/detect_memory_leaks] + +[/ ###############################################################################################] +[section:use_alt_stack `use_alt_stack`] + +Uses an alternative stack. + +Specifies whether or not the execution monitor should employ an alternative stack for signals +processing, on platforms where they are supported. + +[warning indicate which platforms are supported] +[warning add a link to the execution monitor] + +[h4 Acceptable values] + +* [*yes] (default) +* no + +[h4 Environment variable] + + BOOST_TEST_USE_ALT_STACK + +[endsect] [/use_alt_stack] + +[/ ###############################################################################################] +[section:detect_fp_exceptions `detect_fp_exceptions`] + +Traps or not floating point exceptions. + +Enables/disable hardware traps for the floating point exception (if supported). + +[h4 Acceptable values] + +* [*no] (default) +* yes + +[h4 Environment variable] + + BOOST_TEST_DETECT_FP_EXCEPTIONS + +[endsect] [/detect_fp_exceptions] + +[/ ###############################################################################################] +[section:log_sink `log_sink`] + +Sets the logging sink to the one specified. + +This parameter allows to easily redirect the test logs. The parameter value is + +* either the string containing either a file name, in which case the __UTF__ will redirect log into this file +* or `stdout` (the default), in which case log is redirected into standard output stream +* or `stderr` , in which case log is redirected into standard error stream. + +[h4 Acceptable values] + +* [*`stdout`] (default) +* `stderr` +* arbitrary file name + +[h4 Environment variable] + + BOOST_TEST_LOG_SINK + +[endsect] [/log_sink] + +[/ ###############################################################################################] +[section:report_sink `report_sink`] + +Sets the report sink to the one specified. + +This parameter allows to easily redirect the test result report. See __param_log_sink__ for more details. + +[h4 Acceptable values] + +* [*`stderr`] (default) +* `stdout` +* arbitrary file name + +[h4 Environment variable] + + BOOST_TEST_REPORT_SINK + +[endsect] [/report_sink] + [/ ###############################################################################################] [section:save_pattern `save_pattern`] -Option ['save_pattern] facilitates switching mode of operation for testing output streams. See __output_test_stream_tool__ -section for details on these tests. - +Provides parameters for testing output streams. See __output_test_stream_tool__ section for details on these tests. + This parameter serves no particular purpose within the framework itself. It can be used by test modules relying -on [classref boost::test_tools::output_test_stream] to implement testing logic. It has two modes of operation: +on [classref boost::test_tools::output_test_stream] to implement testing logic. `output_test_stream` has two modes of operation: -* save the pattern file (true). -* and match against a previously stored pattern file (false). - -Default mode is 'match' (false). +* save the pattern file +* and match against a previously stored pattern file. You can use this parameter to switch between these modes, by passing the parameter value to the `output_test_stream` constructor. -The value of the command line parameter is available using call like this: +The value of the command line parameter is available from the code like this: + `` bool is_save_pattern_flag_set = boost::unit_test::runtime_config::save_pattern(); `` [h4 Acceptable values] -[link boolean_param_value Boolean] with default value [*no]. +* [*no] (default) +* yes -[h4 Command line syntax] - -* --save_pattern[=] +Equivalent to ['yes] when called without any argument. [h4 Environment variable] -BOOST_TEST_SAVE_PATTERN + BOOST_TEST_SAVE_PATTERN [endsect] [/save_pattern] [/ ###############################################################################################] -[section:show_progress `show_progress`] +[section:list_content `list_content`] -Option ['show_progress] instructs the __UTF__ to display test progress information. By default the -parameter test progress is not shown. More details [link boost_test.test_output.test_output_progress here]. - -[h4 Acceptable values] - -[link boolean_param_value Boolean] with default value [*no]. - -[h4 Command line syntax] - -* --show_progress[=] -* -p [] +Lists the content of the tests that would be run. If set on the command line, no test will be run and the content +of the test bed will be printed, one test per line. [h4 Environment variable] - -BOOST_TEST_SHOW_PROGRESS + + BOOST_TEST_LIST_CONTENT [endsect] -[/ ###############################################################################################] -[section:use_alt_stack `use_alt_stack`] - -Option ['use_alt_stack] instructs the __UTF__ to use alternative stack for signals processing, on -platforms where they are supported. More information about this feature is available -[@http://www.gnu.org/software/libc/manual/html_node/Signal-Stack.html here]. The feature is enabled -by default, but can be disabled using this parameter. - -[/ TODO indicate which platforms are supported] -[/ TODO add a link to the execution monitor] - -[h4 Acceptable values] - -[link boolean_param_value Boolean] with default value [*yes]. - -[h4 Command line syntax] - -* --use_alt_stack[=] - -[h4 Environment variable] - -BOOST_TEST_USE_ALT_STACK - -[endsect] [/use_alt_stack] - -[/ ###############################################################################################] -[section:usage `usage`] - -If specified option ['usage] instructs the __UTF__ to displays short usage message about the -framework's parameters. - -[h4 Command line syntax] - -* -? [] - -[note The parameter name is not part of command line format, only short '-?'.] - -[h4 Acceptable values] - -[link boolean_param_value Boolean] with default value [*no]. - -[endsect] [/usage] - -[/ ###############################################################################################] -[section:wait_for_debugger `wait_for_debugger`] - -Option ['wait_for_debugger] instructs the __UTF__ to pause before starting test units execution, -so that you can attach a debugger to running test module. By default this parameters turned off. - -[h4 Acceptable values] - -[link boolean_param_value Boolean] with default value [*no]. - -[h4 Command line syntax] - -* --wait_for_debugger[=] -* -w [] - -[h4 Environment variable] - -BOOST_TEST_USE_ALT_STACK - -[endsect] [/use_alt_stack] - [endsect] [/ runtime parameters reference] diff --git a/doc/runtime_configuration/runtime_config_summary.qbk b/doc/runtime_configuration/runtime_config_summary.qbk index 58f537ec..ee48ebae 100644 --- a/doc/runtime_configuration/runtime_config_summary.qbk +++ b/doc/runtime_configuration/runtime_config_summary.qbk @@ -5,163 +5,152 @@ / file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) /] + [section:summary Summary of run-time parameters] [table [ [Command] [Short description] + ] + + [/ ###############################################################################################] + [ + [__param_auto_start_dbg__] + [Automatically attach debugger in case of system failure.] ] + + + [/ ###############################################################################################] + [ + [__param_show_progress__] + [Makes the framework to print progress information. More details [link boost_test.test_output.test_output_progress here].] + ] + [/ ###############################################################################################] [ - [[link boost_test.utf_reference.rt_param_reference.auto_dbg `auto_start_dbg`]] - [Instructs the framework to automatically attach debugger in case of system failure.] + [__param_build_info__] + [Print build information.] ] + + + [/ ###############################################################################################] + [ + [__param_catch_system__] + [Catch system errors.] + ] + + [/ ###############################################################################################] + [ + [__param_break_exec_path__] + [Break execution path] + ] + [/ ###############################################################################################] [ - [[link boost_test.utf_reference.rt_param_reference.build_info `build_info`]] - [Instructs the framework to display library build information.] - ] + [__param_color_output__] + [Produce color output] + ] [/ ###############################################################################################] [ - [[link boost_test.utf_reference.rt_param_reference.catch_system `catch_system_error`]] - [Instructs the framework to catch system errors.] - ] - - [/ ###############################################################################################] - [ - [[link boost_test.utf_reference.rt_param_reference.color_output `color_output`]] - [Instructs the framework to produce color output] - ] - - [/ ###############################################################################################] - [ - [[link boost_test.utf_reference.rt_param_reference.detect_fp_exceptions `detect_fp_exceptions`]] - [Instructs the framework to trap floating point exceptions (on supported platforms).] - ] - - [/ ###############################################################################################] - [ - [[link boost_test.utf_reference.rt_param_reference.detect_memory_leaks `detect_memory_leaks`]] - [Instructs the framework to detect memory leaks (on supported platforms).] - ] - - [/ ###############################################################################################] - [ - [[link boost_test.utf_reference.rt_param_reference.help `help`]] - [Provides help on the __UTF__ parameters.] - ] - - [/ ###############################################################################################] - [ - [[link boost_test.utf_reference.rt_param_reference.list_content `list_content`]] - [Lists the tests that will be run.] - ] - - [/ ###############################################################################################] - [ - [[link boost_test.utf_reference.rt_param_reference.list_labels `list_labels`]] - [Lists the labels defined in the test module.] - ] - - [/ ###############################################################################################] - [ - [[link boost_test.utf_reference.rt_param_reference.log_format `log_format`]] + [__param_log_format__] [Specifies the log format] ] [/ ###############################################################################################] [ - [[link boost_test.utf_reference.rt_param_reference.log_level `log_level`]] - [Specifies the framework's logging level] + [__param_log_level__] + [Specifies the logging level of the __UTF__] ] - + + [/ ###############################################################################################] [ - [[link boost_test.utf_reference.rt_param_reference.log_sink `log_sink`]] - [Specifies where to write testing log to.] + [__param_run_test__] + [Specifies which test units to run.] ] - + + [/ ###############################################################################################] [ - [[link boost_test.utf_reference.rt_param_reference.output_format `output_format`]] + [__param_output_format__] [Specifies the log format and the report format.] - ] - + ] + [/ ###############################################################################################] [ - [[link boost_test.utf_reference.rt_param_reference.random `random`]] - [Instructs the framework to run the tests in random order] - ] - - [/ ###############################################################################################] - [ - [[link boost_test.utf_reference.rt_param_reference.report_format `report_format`]] + [__param_report_format__] [Specifies the report format.] ] [/ ###############################################################################################] [ - [[link boost_test.utf_reference.rt_param_reference.report_level `report_level`]] - [Specifies the level of details carried by the framework's testing result report.] + [__param_result_code__] + [Make the framework return a result code indicating an error in the tests.] ] - + [/ ###############################################################################################] [ - [[link boost_test.utf_reference.rt_param_reference.report_memory_leaks_to `report_memory_leaks_to`]] - [Specifies file name where memory leaks report should be re-directed to.] + [__param_report_level__] + [The level of details carried by the __UTF__ report.] ] - + [/ ###############################################################################################] [ - [[link boost_test.utf_reference.rt_param_reference.report_sink `report_sink`]] - [Specifies where to write the testing result report to.] + [__param_random__] + [Runs the tests in random order] ] - + [/ ###############################################################################################] [ - [[link boost_test.utf_reference.rt_param_reference.result_code `result_code`]] - [Instructs the framework to return or ignore a result code indicating an error in the tests.] + [__param_detect_memory_leaks__] + [Detects memory leaks.] ] - + + [/ ###############################################################################################] [ - [__param_run_test__] - [Allows to filter which test units to execute at runtime.] + [__param_use_alt_stack__] + [Uses an alternative stack for running tests (on supported platforms).] ] - + + [/ ###############################################################################################] [ - [[link boost_test.utf_reference.rt_param_reference.save_pattern `save_pattern`]] - [Facilitates mode switching for testing output streams.] + [__param_detect_fp_exceptions__] + [Traps floating point exceptions (on supported platforms).] ] - + + [/ ###############################################################################################] [ - [[link boost_test.utf_reference.rt_param_reference.show_progress `show_progress`]] - [Instructs the framework to print progress information. More details [link boost_test.test_output.test_output_progress here].] + [__param_log_sink__] + [Specifies the sink stream for logging.] ] - + + [/ ###############################################################################################] [ - [[link boost_test.utf_reference.rt_param_reference.use_alt_stack `use_alt_stack`]] - [Instructs the framework to use an alternative stack for signal processing (on supported platforms).] + [__param_report_sink__] + [Specifies the sink stream for tests reports.] ] - + [/ ###############################################################################################] [ - [[link boost_test.utf_reference.rt_param_reference.usage `usage`]] - [Displays short usage message.] + [__param_save_pattern__] + [Provides parameters for testing output streams.] ] - + + [/ ###############################################################################################] [ - [[link boost_test.utf_reference.rt_param_reference.wait_for_debugger `wait_for_debugger`]] - [Instructs the framework to pause test module before testing is started to allow debugger to attach.] + [__param_list_content__] + [List the tests that will be run.] ] ] + [endsect] \ No newline at end of file diff --git a/doc/runtime_configuration/test_unit_filtering.qbk b/doc/runtime_configuration/test_unit_filtering.qbk index e60794cd..3d6a5395 100644 --- a/doc/runtime_configuration/test_unit_filtering.qbk +++ b/doc/runtime_configuration/test_unit_filtering.qbk @@ -20,11 +20,7 @@ Each test unit (either test case or test suite) has an associated ['default run Initially, the master test suite has default run status set to ['true]. All other test units have default run status set to ['inherit]. This implies that, unless any additional configuration is applied, all tests are designated to be run. -You can set a different default run status in any test unit by using [link boost_test.tests_organization.decorators decorators]: -__decorator_disabled__, __decorator_enabled__ and __decorator_enable_if__. The default run status is set once, upon testing program -initialization, and cannot be changed. The disabled tests are not executed by default, but are still present in the test tree, -and are listed along with other tests when you use command-line argument -[link boost_test.utf_reference.rt_param_reference.list_content `list_content`]. +You can set a different default run status in any test unit by using [link boost_test.tests_organization.decorators decorators]: __decorator_disabled__, __decorator_enabled__ and __decorator_enable_if__. The default run status is set once, upon testing program initialization, and cannot be changed. The disabled tests are not executed by default, but are still present in the test tree, and are listed along with other tests when you use command-line argument __param_list_content__. [bt_example decorator_20..default run status..run-fail] @@ -37,8 +33,7 @@ Additionally, it is possible to statically associate a test unit with a conditio [#ref_command_line_control][h3 Command-line control] -Static configuration of the test-case filtering is used by default, unless command-line filtering is applied. With command-line argument -__param_run_test__ it is possible to alter the static pre-set in a number of ways: +Static configuration of the test-case filtering is used by default, unless command-line filtering is applied. With command-line argument __param_run_test__ it is possible to alter the static pre-set in a number of ways: # Ignore the static configuration and manually specify test cases to be run. # Augment the statically defined set by enabling the disabled test cases. @@ -46,12 +41,7 @@ __param_run_test__ it is possible to alter the static pre-set in a number of way [#ref_command_line_control_absolute][h4 Absolute specification] -Term 'absolute' in this context means that the default run status of the test units, which has been statically set up, -is completely ignored and the tests to be run are specified manually from scratch. First, in order to learn what test -units are registered in the test tree the user needs to use command-line argument -[link boost_test.utf_reference.rt_param_reference.list_content `list_content`]. -Next, in order to specify a set of test cases, the user needs to use command-line argument -__param_run_test__ with absolute value: +Term 'absolute' in this context means that the default run status of the test units, which has been statically set up, is completely ignored and the tests to be run are specified manually from scratch. First, in order to learn what test units are registered in the test tree the user needs to use command-line argument __param_list_content__. Next, in order to specify a set of test cases, the user needs to use command-line argument __param_run_test__ with absolute value: ``` > test_program --__param_run_test__= diff --git a/doc/test.qbk b/doc/test.qbk index b55c3bbf..0bd5cecd 100644 --- a/doc/test.qbk +++ b/doc/test.qbk @@ -116,12 +116,37 @@ [def __BOOST_FIXTURE_TEST_SUITE__ [link boost_test.utf_reference.test_org_reference.test_org_boost_test_suite_fixture `BOOST_FIXTURE_TEST_SUITE`]] [def __BOOST_GLOBAL_FIXTURE__ [link boost_test.utf_reference.test_org_reference.test_org_boost_global_fixture `BOOST_GLOBAL_FIXTURE`]] + + + + [/ log] [def __BOOST_TEST_LOG_LEVEL__ [link boost_test.utf_reference.rt_param_reference.log_level `BOOST_TEST_LOG_LEVEL`]] [/ this is an environment variable] + [/ runtime/cla parameters] +[def __param_show_progress__ [link boost_test.utf_reference.rt_param_reference.show_progress `show_progress`]] +[def __param_log_level__ [link boost_test.utf_reference.rt_param_reference.log_level `log_level`]] +[def __param_output_format__ [link boost_test.utf_reference.rt_param_reference.output_format `output_format`]] +[def __param_log_format__ [link boost_test.utf_reference.rt_param_reference.log_format `log_format`]] +[def __param_run_test__ [link boost_test.utf_reference.rt_param_reference.run_test `run_test`]] +[def __param_report_level__ [link boost_test.utf_reference.rt_param_reference.report_level `report_level`]] +[def __param_report_format__ [link boost_test.utf_reference.rt_param_reference.report_format `report_format`]] +[def __param_catch_system__ [link boost_test.utf_reference.rt_param_reference.catch_system `catch_system_error`]] +[def __param_result_code__ [link boost_test.utf_reference.rt_param_reference.result_code `result_code`]] +[def __param_build_info__ [link boost_test.utf_reference.rt_param_reference.build_info `build_info`]] +[def __param_auto_start_dbg__ [link boost_test.utf_reference.rt_param_reference.auto_dbg `auto_start_dbg`]] +[def __param_break_exec_path__ [link boost_test.utf_reference.rt_param_reference.break_exec_path `break_exec_path`]] +[def __param_color_output__ [link boost_test.utf_reference.rt_param_reference.color_output `color_output`]] +[def __param_random__ [link boost_test.utf_reference.rt_param_reference.random `random`]] +[def __param_detect_memory_leaks__ [link boost_test.utf_reference.rt_param_reference.detect_memory_leaks `detect_memory_leaks`]] +[def __param_use_alt_stack__ [link boost_test.utf_reference.rt_param_reference.use_alt_stack `use_alt_stack`]] +[def __param_detect_fp_exceptions__ [link boost_test.utf_reference.rt_param_reference.detect_fp_exceptions `detect_fp_exceptions`]] +[def __param_log_sink__ [link boost_test.utf_reference.rt_param_reference.log_sink `log_sink`]] +[def __param_report_sink__ [link boost_test.utf_reference.rt_param_reference.report_sink `report_sink`]] +[def __param_save_pattern__ [link boost_test.utf_reference.rt_param_reference.save_pattern `save_pattern`]] +[def __param_list_content__ [link boost_test.utf_reference.rt_param_reference.list_content `list_content`]] [def __default_run_status__ [link ref_default_run_status ['default run status]]] -[def __param_run_test__ [link boost_test.utf_reference.rt_param_reference.run_test `run_test`]] [/ decorators] [def __decorator_label__ [link boost_test.utf_reference.test_org_reference.decorator_label `label`]] diff --git a/doc/test_organization/managing_tests_dependencies.qbk b/doc/test_organization/managing_tests_dependencies.qbk index 88004718..c86b9756 100644 --- a/doc/test_organization/managing_tests_dependencies.qbk +++ b/doc/test_organization/managing_tests_dependencies.qbk @@ -18,7 +18,7 @@ executed in one go, even if the test suite namespace is opened multiple times. Even though the order is not guaranteed, it may be accidentally preserved across the different runs. In order to make sure the test cases do not depend on one another, whoever runs the test module may provide a command-line argument -[link boost_test.utf_reference.rt_param_reference.random `random`] to make sure the test units are shuffled within the suites. +__param_random__ to make sure the test units are shuffled within the suites. [h3 Declaring a test case dependency] diff --git a/doc/test_organization/semantic.qbk b/doc/test_organization/semantic.qbk index 87c12124..e2823716 100644 --- a/doc/test_organization/semantic.qbk +++ b/doc/test_organization/semantic.qbk @@ -16,10 +16,9 @@ on the test unit /name/, or instead of looking at the code. The __UTF__ provides the decorator __decorator_description__ for that purpose. Decorator `description` attaches an arbitrary string to the test unit. All strings attached to test units can be -displayed when running a test program with parameter [link boost_test.utf_reference.rt_param_reference.list_content `list_content`]. -This can be used for conveying information from the person who composes the test tree to the person who will be -running the test program. Applying more than one decorator `description` to the same test unit means that the two -(or more) strings will be concatenated. +displayed when running a test program with parameter __param_list_content__. This can be used for conveying information +from the person who composes the test tree to the person who will be running the test program. Applying more than one +decorator `description` to the same test unit means that the two (or more) strings will be concatenated. [bt_example decorator_09..decorator description..run] diff --git a/doc/test_output/compilation_options.qbk b/doc/test_output/compilation_options.qbk index 2c26574c..44637665 100644 --- a/doc/test_output/compilation_options.qbk +++ b/doc/test_output/compilation_options.qbk @@ -35,6 +35,9 @@ cases. There are no limitations on number of output stream resets either. [endsect] [/section:log_ct_output_stream_redirection] + + + [#ref_log_level_explanations][section:log_ct_log_level Log level configuration] If you need to enforce specific log level from within your test module use the following interface: @@ -43,8 +46,7 @@ If you need to enforce specific log level from within your test module use the f `` In regular circumstances you shouldn't use this interface, since you not only override default log level, but also -the one supplied at test execution time. Prefer to use runtime parameter -[link boost_test.utf_reference.rt_param_reference.log_level `log_level`] for log level selection. +the one supplied at test execution time. Prefer to use runtime parameters __param_log_level__ for log level selection. [bt_example example51..Compile-time log level configuration..run] diff --git a/doc/test_output/log_format.qbk b/doc/test_output/log_format.qbk index 721bc598..ed3d77a8 100644 --- a/doc/test_output/log_format.qbk +++ b/doc/test_output/log_format.qbk @@ -5,7 +5,6 @@ / file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) /] -[section Log formats] [section:log_human_readable_format Human readable log format] The human readable log format is designed to closely match an errors description produced by the Microsoft family @@ -16,7 +15,7 @@ events occurring in test module. This is a default format generated by test modu Here the list of events along with corresponding message and the condition that has to be satisfied for it to appear in the output. -[table +[table:human_readable_log_format_table [ [Event] [Condition] @@ -84,7 +83,7 @@ Boost : $BOOST_VERSION]] ] [``]] ] -Advanced [link boost_test.testing_tools testing tools] may produce more detailed error messages. +Advanced [link boost_test.testing_tools testing tools] may produce more complicated error messages. [endsect] [/ human readable report] @@ -94,8 +93,6 @@ Advanced [link boost_test.testing_tools testing tools] may produce more detailed This log format is designed for automated test results processing. The test log output XML schema depends on the active log level threshold. -[/TODO: Fix this section] - -[endsect] +[warning There is a TO FIX in the doc, what for ?] [endsect] [/section:log_xml_format ] diff --git a/doc/test_output/logging_floating_point.qbk b/doc/test_output/logging_floating_point.qbk index 5bc857e4..627a553d 100644 --- a/doc/test_output/logging_floating_point.qbk +++ b/doc/test_output/logging_floating_point.qbk @@ -11,7 +11,7 @@ It may appear that floating-point numbers are displayed by the __UTF__ with an e However the number of digits shown is chosen to avoid apparently nonsensical displays like `[1.00000 != 1.00000]` when comparing exactly unity against a value which is increased by just one least significant binary digit using the default precision for float of just 6 decimal digits, given by - `std::numeric_limits::digits10`. The function used for the number of decimal +`std::numeric_limits::digits10`. The function used for the number of decimal digits displayed is that proposed for a future C++ Standard, [@http://www2.open-std.org/JTC1/SC22/WG21/docs/papers/2005/n1822.pdf A Proposal to add a max significant decimal digits value], to be called `std::numeric_limits::max_digits10();`. diff --git a/doc/test_output/progress_display.qbk b/doc/test_output/progress_display.qbk index 00fd7155..120bb653 100644 --- a/doc/test_output/progress_display.qbk +++ b/doc/test_output/progress_display.qbk @@ -16,18 +16,20 @@ on [footnote The __UTF__ interfaces allow implementing an advanced GUI based test runner with arbitrary progress display controls]. -The progress display output is enabled using the __UTF__ parameter -[link boost_test.utf_reference.rt_param_reference.show_progress `show_progress`]. +The progress display output is enabled using the __UTF__ parameter __param_show_progress__. + The __UTF__ has no ability to estimate how long the test case execution is going to take and the manual test progress update is not supported at this point. The __UTF__ tracks the progress on test case level. If you want to see more frequent progress update, you need to split the test into multiple test cases. + In default configuration both test log and test progress outputs are directed into standard output stream. Any test log messages are going to interfere with test progress display. To prevent this you can either set log level to lower level or redirect either test log or test progress output into different stream during test module initialization. Use following interface to redirect test progress output: + `` boost::unit_test::progress_monitor.set_stream( std::ostream& ) `` diff --git a/doc/test_output/report_format.qbk b/doc/test_output/report_format.qbk deleted file mode 100644 index e9f70823..00000000 --- a/doc/test_output/report_format.qbk +++ /dev/null @@ -1,81 +0,0 @@ -[/ - / Copyright (c) 2003 Boost.Test team - / - / 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) - /] - -[section Report formats][#ref_report_formats] - -[section:report_human_readable_format Human readable report format] - -The human readable report format is designed to produce the most human friendly description of the -results of a test module testing. This is a default format generated by test modules. - -Depending on the framework's report level the output looks like this: - -[table - [ [Level] - [Output] - ] - - [ [no report] - [On this level the framework does not produce result report at all. It make sense - to use this level for test modules running unattended (as part of some automated regression - testing system, for example) - ] - ] - - [ [Confirmation] - [ - [variablelist - [[Passing test] [\*** No errors detected]] - [[Skipped test] [\*** The test suite was skipped; see standard output for details]] - [[Aborted test] [\*** The test suite was aborted; see standard output for details]] - [[Failed test without failed assertions] [\*** Errors were detected in the test suite ; see standard output for details]] - [[Failed test] [\*** N failures are detected in test suite ]] - [[Failed test with some failures expected] [\*** N failures are detected (M failures are expected) in test suite ]] - ] - ] - ] - [ [Detailed] - [On this level we report result for each test units hierarchically (each test unit is reported as part of parent test unit - report. Test cases are reported like this: - [pre - Test case/suite has passed/was skipped/was aborted/has failed/ with: - N assertions out of M passed - N assertions out of M failed - N warnings out of M failed - X failures expected - ] - Only relevant lines will appear. If test case does not have failing assertions corresponding line in the report is not shown. - - Test suite in addition to above lines also report these: - [pre - N test cases out of M passed - N test cases out of M passed with warnings - N test cases out of M failed - N test cases out of M skipped - N test cases out of M aborted - ] - And similarly to above lines only relevant ones will appear in output. - ] - ] - [ [Short] - [Short report format is similar to detailed, but only reports information for master test suite] - ] -] - -[endsect] [/ human readable report] - -[/ -------------------------------------------------------------------------------------------------- ] -[section:report_xml_format XML based report output format] - -This report format is designed for automated test results processing. The result report output XML schema -depends on the report level. - -[/TODO: Fix this section] - -[endsect] - -[endsect] [/section:log_xml_format ] diff --git a/doc/test_output/test_output.qbk b/doc/test_output/test_output.qbk index 9dbf6ed9..379f9bdc 100644 --- a/doc/test_output/test_output.qbk +++ b/doc/test_output/test_output.qbk @@ -129,19 +129,25 @@ macros for this purpose: * __BOOST_TEST_CHECKPOINT__ to specify a ['named] checkpoint and * __BOOST_TEST_PASSPOINT__ to specify an ['unnamed] checkpoint. + + [endsect] [/ test log output] + + [/ -------------------------------------------------------------------------------------------------- ] [section:log_runtime_config Verbosity of the logs] -The active log level threshold can be configured at runtime using the parameter -[link boost_test.utf_reference.rt_param_reference.log_level `log_level`]. -The test log output format can be selected using either parameter -[link boost_test.utf_reference.rt_param_reference.log_format `log_format`] or the parameter -[link boost_test.utf_reference.rt_param_reference.output_format `output_format`]. +The active log level threshold can be configured at runtime using the parameter __param_log_level__. +The test log output format can be selected using either parameter __param_log_format__ or the +parameter __param_output_format__. [endsect] [/section:log_runtime_config] + + + + [/ -------------------------------------------------------------------------------------------------- ] [section:testing_tool_output_disable Disabling automatic printing for specific types] @@ -163,6 +169,10 @@ includes statement failing to compile: [endsect] [/section:testing_tool_output_disable] + + + + [/ -------------------------------------------------------------------------------------------------- ] [section:test_output_macro_message Custom messages] The macro __BOOST_TEST_MESSAGE__ is intended to be used for the purpose of injecting an additional message into the @@ -183,16 +193,22 @@ manner similar to standard `std::iostream` operation. [endsect] [/section:test_output_macro_message] + [/ -------------------------------------------------------------------------------------------------- ] [include checkpoints.qbk] [include contexts.qbk] [include logging_floating_point.qbk] [include log_format.qbk] -[include report_format.qbk] [include compilation_options.qbk] + +[#ref_tests_report][section Test reports] +[warning Section empty] +[endsect] + [include progress_display.qbk] [include testout_summary.qbk] [endsect] [/test_output] + diff --git a/doc/testing_tools/testing_output_streams.qbk b/doc/testing_tools/testing_output_streams.qbk index f03c58c3..6e34273d 100644 --- a/doc/testing_tools/testing_output_streams.qbk +++ b/doc/testing_tools/testing_output_streams.qbk @@ -36,8 +36,8 @@ of sheer volume. A possible way to address that issue is to split the test in tw # second to save this output to ensure that future checks produce the same output The class `output_test_stream` allows both the matching of the output content versus a /pattern file/ and generation -of this pattern file. The command line parameter [link boost_test.utf_reference.rt_param_reference.save_pattern `save_pattern`] -may be used to either generate a new pattern file, or to check against an existing pattern. +of this pattern file. The command line parameter __param_save_pattern__ may be used to either generate +a new pattern file, or to check against an existing pattern. [h3:usages Usage] There are two ways to employ the class `output_test_stream`: diff --git a/doc/usage_recommendations.qbk b/doc/usage_recommendations.qbk index 75b69b8f..3a59d615 100644 --- a/doc/usage_recommendations.qbk +++ b/doc/usage_recommendations.qbk @@ -72,10 +72,10 @@ project property page: [$images/post_build_event.jpg] Full command you need in "Command Line" field is: - -[pre -"$(TargetDir)\$(TargetName).exe" --[link boost_test.utf_reference.rt_param_reference.result_code `result_code`]=no --[link boost_test.utf_reference.rt_param_reference.report_level `report_level`]=no -] + +`` +"$(TargetDir)\$(TargetName).exe" --__param_result_code__=no --__param_report_level__=no +`` Note that both report level and result code are suppressed. This way the only output you may see from this command are possible runtime errors. But the best part is that you could jump through these errors using usual @@ -88,13 +88,13 @@ keyboard shortcuts/mouse clicks you use for compilation error analysis: If you got "memory access violation" message (or any other message indication fatal or system error) when you run you test, to get more information of error location add - -[pre ---[link boost_test.utf_reference.rt_param_reference.catch_system catch_system_error]=no -] +`` +--__param_catch_system__=no +`` to the test run command line: [$images/run_args.jpg] + Now run the test again under debugger and it will break at the point of failure. @@ -106,10 +106,9 @@ Now run the test again under debugger and it will break at the point of failure. line argument] If you got "memory access violation" message (or any other message indication fatal or system error) when you run you test, to get more information about the error location add - -[pre ---[link boost_test.utf_reference.rt_param_reference.catch_system catch_system_error]=no -] +`` +--__param_catch_system__=no +`` to the test run command line. Now run the test again and it will create a coredump you could analyze using you preferable debugger. Or run it under debugger in a first place and it will break at the point of failure. @@ -117,32 +116,31 @@ debugger. Or run it under debugger in a first place and it will break at the poi [h4 How to use test module build with Boost.Test framework under management of automated regression test facilities?] My first recommendation is to make sure that the test framework catches all fatal errors by adding argument - -[pre ---[link boost_test.utf_reference.rt_param_reference.catch_system catch_system_error]=yes -] +`` +--__param_catch_system__=yes +`` to all test modules invocations. Otherwise test program may produce unwanted dialogs (depends on compiler and OS) that will halt you regression tests run. The second recommendation is to suppress result report output by adding -[pre +`` --__param_report_level__=no -] +`` argument and test log output by adding -[pre ---[link boost_test.utf_reference.rt_param_reference.log_level log_level]=nothing -] +`` +--__param_log_level__=nothing +`` argument, so that test module won't produce undesirable output no one is going to look at anyway. We recommend relying only on result code that will be consistent for all test programs. An alternative to my second recommendation is direct both log and report to separate file you could analyze later on. Moreover you can make Boost.Test to produce them in XML format using -[pre ---[link boost_test.utf_reference.rt_param_reference.output_format output_format]=XML -] +`` +--__param_output_format__=XML +`` and use some automated tool that will format this information as you like. [endsect][/command line] diff --git a/example/cla/Jamfile.v2 b/example/cla/Jamfile.v2 new file mode 100644 index 00000000..671fa7e4 --- /dev/null +++ b/example/cla/Jamfile.v2 @@ -0,0 +1,57 @@ +# (C) Copyright Gennadiy Rozental 2001-2005. +# (C) Copyright Juergen Hunold 2006. +# Use, modification, and distribution are subject to 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. + +# bring in the rules for testing +import testing ; + +# Project +project libs/test/example/cla ; + +# DEPENDS all : test ; + +rule boost-runtime-param-example ( example-name ) +{ + return [ compile $(example-name).cpp + : + : $(example-name) + ] ; +} + +# : on + +test-suite boost_test_cla_examples +: + [ boost-runtime-param-example assign_to ] + [ boost-runtime-param-example basic_float ] + [ boost-runtime-param-example basic_int ] + [ boost-runtime-param-example basic_list ] + [ boost-runtime-param-example basic_string ] + [ boost-runtime-param-example basic_udt ] + [ boost-runtime-param-example char_parameter ] + [ boost-runtime-param-example custom_handler ] + [ boost-runtime-param-example custom_interpreter ] + [ boost-runtime-param-example custom_parameter ] + [ boost-runtime-param-example default_value ] + [ boost-runtime-param-example dual_name ] + [ boost-runtime-param-example global ] + [ boost-runtime-param-example guess_name ] + [ boost-runtime-param-example help ] + [ boost-runtime-param-example ignore_mismatch ] + [ boost-runtime-param-example input_separator ] + [ boost-runtime-param-example multiplicable ] + [ boost-runtime-param-example name ] + [ boost-runtime-param-example optional ] + [ boost-runtime-param-example optional_value ] + [ boost-runtime-param-example positional ] + [ boost-runtime-param-example prefix ] + [ boost-runtime-param-example reference ] + [ boost-runtime-param-example remainder ] + [ boost-runtime-param-example separator ] + [ boost-runtime-param-example usage ] + [ boost-runtime-param-example wide_string ] +; diff --git a/example/cla/assign_to.cpp b/example/cla/assign_to.cpp new file mode 100644 index 00000000..fe7d144f --- /dev/null +++ b/example/cla/assign_to.cpp @@ -0,0 +1,41 @@ +// (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) + +// See http://www.boost.org/libs/test for the library home page. + +// Boost.Runtime.Param +#include +#include + +namespace rt = boost::runtime; +namespace cla = boost::runtime::cla; + +// STL +#include + +int main() { + char* argv[] = { "basic", "-abcd", "25" }; + int argc = sizeof(argv)/sizeof(char*); + + try { + cla::parser P; + + int i = 0; + + P << cla::named_parameter( "abcd" ) - (cla::assign_to = i); + + P.parse( argc, argv ); + + std::cout << "abcd = " << i << std::endl; + } + catch( rt::logic_error const& ex ) { + std::cout << "Logic error: " << ex.msg() << std::endl; + return -1; + } + + return 0; +} + +// EOF diff --git a/example/cla/basic_float.cpp b/example/cla/basic_float.cpp new file mode 100644 index 00000000..5210b6a2 --- /dev/null +++ b/example/cla/basic_float.cpp @@ -0,0 +1,40 @@ +// (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) + +// See http://www.boost.org/libs/test for the library home page. + +// Boost.Runtime.Param +#include +#include + +namespace rt = boost::runtime; +namespace cla = boost::runtime::cla; + +// STL +#include + +int main() { + char* argv[] = { "basic", "-abcd", "25.45" }; + int argc = sizeof(argv)/sizeof(char*); + + try { + cla::parser P; + + P << cla::named_parameter( "abcd" ); + + P.parse( argc, argv ); + + std::cout << "abcd = " << P.get( "abcd" ) << std::endl; + } + catch( rt::logic_error const& ex ) { + std::cout << "Logic error: " << ex.msg() << std::endl; + return -1; + } + + return 0; +} + +// EOF + diff --git a/example/cla/basic_int.cpp b/example/cla/basic_int.cpp new file mode 100644 index 00000000..fc904c9b --- /dev/null +++ b/example/cla/basic_int.cpp @@ -0,0 +1,39 @@ +// (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) + +// See http://www.boost.org/libs/test for the library home page. + +// Boost.Runtime.Param +#include +#include + +namespace rt = boost::runtime; +namespace cla = boost::runtime::cla; + +// STL +#include + +int main() { + char* argv[] = { "basic", "-abcd", "25" }; + int argc = sizeof(argv)/sizeof(char*); + + try { + cla::parser P; + + P << cla::named_parameter( "abcd" ); + + P.parse( argc, argv ); + + std::cout << "abcd = " << P.get( "abcd" ) << std::endl; + } + catch( rt::logic_error const& ex ) { + std::cout << "Logic error: " << ex.msg() << std::endl; + return -1; + } + + return 0; +} + +// EOF diff --git a/example/cla/basic_list.cpp b/example/cla/basic_list.cpp new file mode 100644 index 00000000..adb9e1ee --- /dev/null +++ b/example/cla/basic_list.cpp @@ -0,0 +1,44 @@ +// (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) + +// See http://www.boost.org/libs/test for the library home page. + +// Boost.Runtime.Param +#include +#include + +namespace rt = boost::runtime; +namespace cla = boost::runtime::cla; + +// STL +#include +#include + +int main() { + char* argv[] = { "basic", "-abcd", "25,12,45,67,1" }; + int argc = sizeof(argv)/sizeof(char*); + + try { + cla::parser P; + + P << cla::named_parameter >( "abcd" ); + + P.parse( argc, argv ); + + std::list arg_values = P.get >( "abcd" ); + + std::cout << "abcd = "; + std::copy( arg_values.begin(), arg_values.end(), std::ostream_iterator( std::cout, " " ) ); + std::cout << std::endl; + } + catch( rt::logic_error const& ex ) { + std::cout << "Logic error: " << ex.msg() << std::endl; + return -1; + } + + return 0; +} + +// EOF diff --git a/example/cla/basic_string.cpp b/example/cla/basic_string.cpp new file mode 100644 index 00000000..433b5fb8 --- /dev/null +++ b/example/cla/basic_string.cpp @@ -0,0 +1,39 @@ +// (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) + +// See http://www.boost.org/libs/test for the library home page. + +// Boost.Runtime.Param +#include +#include + +namespace rt = boost::runtime; +namespace cla = boost::runtime::cla; + +// STL +#include + +int main() { + char* argv[] = { "basic", "-abcd", "25" }; + int argc = sizeof(argv)/sizeof(char*); + + try { + cla::parser P; + + P << cla::named_parameter( "abcd" ); + + P.parse( argc, argv ); + + std::cout << "abcd = " << P.get( "abcd" ) << std::endl; + } + catch( rt::logic_error const& ex ) { + std::cout << "Logic error: " << ex.msg() << std::endl; + return -1; + } + + return 0; +} + +// EOF diff --git a/example/cla/basic_udt.cpp b/example/cla/basic_udt.cpp new file mode 100644 index 00000000..0d5ea58e --- /dev/null +++ b/example/cla/basic_udt.cpp @@ -0,0 +1,72 @@ +// (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) + +// See http://www.boost.org/libs/test for the library home page. + +// Boost.Runtime.Param +#include +#include + +namespace rt = boost::runtime; +namespace cla = boost::runtime::cla; + +// STL +#include + +// Library code +struct FullName +{ + std::string first_name; + std::string last_name; +}; + +std::istream& +operator>>( std::istream& istr, FullName& f ) +{ + std::string token; + istr >> token; + + std::size_t pos = token.find( ',' ); + if( pos != std::string::npos ) { + f.first_name.assign( token.begin(), token.begin()+pos ); + f.last_name.assign( token.begin()+pos+1, token.end() ); + } + else { + f.first_name = token; + } + + return istr; +} + +std::ostream& +operator<<( std::ostream& ostr, FullName const& f ) +{ + return ostr << f.first_name << ':' << f.last_name; +} + +// End of library code + +int main() { + char* argv[] = { "basic", "-abcd", "John,Doe" }; + int argc = sizeof(argv)/sizeof(char*); + + try { + cla::parser P; + + P << cla::named_parameter( "abcd" ); + + P.parse( argc, argv ); + + std::cout << "abcd = " << P.get( "abcd" ) << std::endl; + } + catch( rt::logic_error const& ex ) { + std::cout << "Logic error: " << ex.msg() << std::endl; + return -1; + } + + return 0; +} + +// EOF diff --git a/example/cla/char_parameter.cpp b/example/cla/char_parameter.cpp new file mode 100644 index 00000000..d6d64aed --- /dev/null +++ b/example/cla/char_parameter.cpp @@ -0,0 +1,41 @@ +// (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) + +// See http://www.boost.org/libs/test for the library home page. + +// Boost.Runtime.Param +#include +#include + +namespace rt = boost::runtime; +namespace cla = boost::runtime::cla; + +// STL +#include + +int main() { + char* argv[] = { "basic", "-k", "14", "-l", "debug" }; + int argc = sizeof(argv)/sizeof(char*); + + try { + cla::parser P; + + P << cla::char_parameter( 'k' ) + << cla::char_parameter( 'l' ); + + P.parse( argc, argv ); + + std::cout << "k = " << P.get( "k" ) << std::endl; + std::cout << "l = " << P.get( "l" ) << std::endl; + } + catch( rt::logic_error const& ex ) { + std::cout << "Logic error: " << ex.msg() << std::endl; + return -1; + } + + return 0; +} + +// EOF diff --git a/example/cla/custom_handler.cpp b/example/cla/custom_handler.cpp new file mode 100644 index 00000000..a2b12014 --- /dev/null +++ b/example/cla/custom_handler.cpp @@ -0,0 +1,45 @@ +// (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) + +// See http://www.boost.org/libs/test for the library home page. + +// Boost.Runtime.Param +#include +#include + +namespace rt = boost::runtime; +namespace cla = boost::runtime::cla; + +// STL +#include + +void validate_abcd( cla::parameter const&, int& value ) +{ + if( value < 0 ) + value += 40; +} + +int main() { + char* argv[] = { "basic", "-abcd", "-25" }; + int argc = sizeof(argv)/sizeof(char*); + + try { + cla::parser P; + + P << cla::named_parameter( "abcd" ) - (cla::handler = &validate_abcd); + + P.parse( argc, argv ); + + std::cout << "abcd = " << P.get( "abcd" ) << std::endl; + } + catch( rt::logic_error const& ex ) { + std::cout << "Logic error: " << ex.msg() << std::endl; + return -1; + } + + return 0; +} + +// EOF diff --git a/example/cla/custom_interpreter.cpp b/example/cla/custom_interpreter.cpp new file mode 100644 index 00000000..e6385d0f --- /dev/null +++ b/example/cla/custom_interpreter.cpp @@ -0,0 +1,54 @@ +// (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) + +// See http://www.boost.org/libs/test for the library home page. + +// Boost.Runtime.Param +#include +#include + +namespace rt = boost::runtime; +namespace cla = boost::runtime::cla; + +// STL +#include + +void +named_integer( rt::cla::argv_traverser& source, boost::optional& value ) +{ + if( source.token() == "one" ) { + value = 1; + source.next_token(); + } + else if( source.token() == "two" ) { + value = 2; + source.next_token(); + } + else + value = 0; +} + +int main() { + char* argv[] = { "basic", "-abcd", "one" }; + int argc = sizeof(argv)/sizeof(char*); + + try { + cla::parser P; + + P << cla::named_parameter( "abcd" ) - (cla::interpreter = &named_integer); + + P.parse( argc, argv ); + + std::cout << "abcd = " << P.get( "abcd" ) << std::endl; + } + catch( rt::logic_error const& ex ) { + std::cout << "Logic error: " << ex.msg() << std::endl; + return -1; + } + + return 0; +} + +// EOF diff --git a/example/cla/custom_parameter.cpp b/example/cla/custom_parameter.cpp new file mode 100644 index 00000000..6259bd24 --- /dev/null +++ b/example/cla/custom_parameter.cpp @@ -0,0 +1,290 @@ +// (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) + +// See http://www.boost.org/libs/test for the library home page. + +// Boost.Runtime.Param +#include +#include + +namespace rt = boost::runtime; +namespace cla = boost::runtime::cla; + +// STL +#include +#include + +//_____________________________________________________________________// + +struct Point : std::pair { + bool parse( rt::cstring& in ) { + in.trim_left(); + + if( first_char( in ) != '(' ) + return false; + + in.trim_left( 1 ); + rt::cstring::size_type pos = in.find( ")" ); + + if( pos == rt::cstring::npos ) + return false; + + rt::cstring ss( in.begin(), pos ); + pos = ss.find( "," ); + + if( pos == rt::cstring::npos ) + return false; + + rt::cstring f( ss.begin(), pos ); + rt::cstring s( ss.begin()+pos+1, ss.end() ); + + f.trim(); + s.trim(); + + try { + first = boost::lexical_cast( f ); + second = boost::lexical_cast( s ); + } + catch( boost::bad_lexical_cast const& ) { + return false; + } + + in.trim_left( ss.end()+1 ); + return true; + } +}; + +std::ostream& operator<<( std::ostream& ostr, Point const& p ) +{ + ostr << '(' << p.first << ',' << p.second << ')'; + + return ostr; +} + +struct Segment : std::pair { + bool parse( rt::cstring& in ) { + in.trim_left(); + + if( first_char( in ) != '[' ) + return false; + + in.trim_left( 1 ); + + if( !first.parse( in ) ) + return false; + + in.trim_left(); + + if( first_char( in ) != ',' ) + return false; + + in.trim_left( 1 ); + + if( !second.parse( in ) ) + return false; + + in.trim_left(); + + if( first_char( in ) != ']' ) + return false; + + in.trim_left( 1 ); + + return true; + } +}; + +std::ostream& operator<<( std::ostream& ostr, Segment const& p ) +{ + ostr << '[' << p.first << ',' << p.second << ']'; + + return ostr; +} + +struct Circle : std::pair { + bool parse( rt::cstring& in ) { + in.trim_left(); + + if( first_char( in ) != '[' ) + return false; + + in.trim_left( 1 ); + + if( !first.parse( in ) ) + return false; + + in.trim_left(); + + if( first_char( in ) != ',' ) + return false; + + in.trim_left( 1 ); + + rt::cstring::size_type pos = in.find( "]" ); + + if( pos == rt::cstring::npos ) + return false; + + rt::cstring ss( in.begin(), pos ); + ss.trim(); + + try { + second = boost::lexical_cast( ss ); + } + catch( boost::bad_lexical_cast const& ) { + return false; + } + + in.trim_left( pos+1 ); + + return true; + } +}; + +std::ostream& operator<<( std::ostream& ostr, Circle const& p ) +{ + ostr << '[' << p.first << ',' << p.second << ']'; + + return ostr; +} + +//_____________________________________________________________________// + +template +class ShapeIdPolicy : public cla::identification_policy { + rt::cstring m_name; + rt::cstring m_usage_str; +public: + explicit ShapeIdPolicy( rt::cstring name ) + : cla::identification_policy( boost::rtti::type_id >() ) + , m_name( name ) {} + + virtual bool responds_to( rt::cstring name ) const { return m_name == name; } + virtual bool conflict_with( cla::identification_policy const& ) const { return false; } + virtual rt::cstring id_2_report() const { return m_name; } + virtual void usage_info( rt::format_stream& fs ) const { fs << m_name; } + + virtual bool matching( cla::parameter const& p, cla::argv_traverser& tr, bool primary ) const + { + T s; + + rt::cstring in = tr.input(); + return s.parse( in ); + } +}; + +//_____________________________________________________________________// + +template +class ShapeArgumentFactory : public cla::argument_factory { + rt::cstring m_usage_str; +public: + explicit ShapeArgumentFactory( rt::cstring usage ) : m_usage_str( usage ) {} + + // Argument factory interface + virtual rt::argument_ptr produce_using( cla::parameter& p, cla::argv_traverser& tr ) + { + T s; + + rt::cstring in = tr.input(); + s.parse( in ); + tr.trim( in.begin() - tr.input().begin() ); + + if( !p.actual_argument() ) { + rt::argument_ptr res; + + rt::typed_argument >* new_arg = new rt::typed_argument >( p ); + + new_arg->p_value.value.push_back( s ); + res.reset( new_arg ); + + return res; + } + else { + std::list& arg_values = rt::arg_value >( *p.actual_argument() ); + arg_values.push_back( s ); + + return p.actual_argument(); + } + } + virtual rt::argument_ptr produce_using( cla::parameter& p, cla::parser const& ) { return rt::argument_ptr(); } + virtual void argument_usage_info( rt::format_stream& fs ) { fs << m_usage_str; } +}; + +//_____________________________________________________________________// + +struct SegmentParam : cla::parameter { + SegmentParam() + : cla::parameter( m_id_policy, m_arg_factory ) + , m_id_policy( "segment" ) + , m_arg_factory( ":((P1x,P1y), (P2x,P2y)) ... ((P1x,P1y), (P2x,P2y))" ) + {} + + ShapeIdPolicy m_id_policy; + ShapeArgumentFactory m_arg_factory; +}; + +inline boost::shared_ptr +segment_param() { return boost::shared_ptr( new SegmentParam ); } + +//_____________________________________________________________________// + +struct CircleParam : cla::parameter { + CircleParam() + : cla::parameter( m_id_policy, m_arg_factory ) + , m_id_policy( "circle" ) + , m_arg_factory( ":((P1x,P1y), R) ... ((P1x,P1y), R)" ) + {} + + ShapeIdPolicy m_id_policy; + ShapeArgumentFactory m_arg_factory; +}; + +inline boost::shared_ptr +circle_param() { return boost::shared_ptr( new CircleParam ); } + +//_____________________________________________________________________// + +int main() { + char* argv[] = { "basic", "[(1,", "1)", ",", "(7,", "-1", ")]", "[(", "1,1)", ",7", "]", "[(3,", "1", ")", ",", "2]", + "[", "(2,7", "),", "(5", ",1", ")]" }; + int argc = sizeof(argv)/sizeof(char*); + + try { + cla::parser P; + + P << circle_param() - cla::optional + << segment_param() - cla::optional; + + P.parse( argc, argv ); + + boost::optional > segments; + boost::optional > circles; + + P.get( "segment", segments ); + + if( segments ) { + std::cout << "segments : "; + std::copy( segments->begin(), segments->end(), std::ostream_iterator( std::cout, "; " ) ); + std::cout << std::endl; + } + + P.get( "circle", circles ); + + if( circles ) { + std::cout << "circles : "; + std::copy( circles->begin(), circles->end(), std::ostream_iterator( std::cout, "; " ) ); + std::cout << std::endl; + } + } + catch( rt::logic_error const& ex ) { + std::cout << "Logic error: " << ex.msg() << std::endl; + return -1; + } + + return 0; +} + +// EOF diff --git a/example/cla/default_value.cpp b/example/cla/default_value.cpp new file mode 100644 index 00000000..1e88110d --- /dev/null +++ b/example/cla/default_value.cpp @@ -0,0 +1,39 @@ +// (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) + +// See http://www.boost.org/libs/test for the library home page. + +// Boost.Runtime.Param +#include +#include + +namespace rt = boost::runtime; +namespace cla = boost::runtime::cla; + +// STL +#include + +int main() { + char* argv[] = { "basic" }; + int argc = sizeof(argv)/sizeof(char*); + + try { + cla::parser P; + + P << cla::named_parameter( "abcd" ) - ( cla::default_value = 10 ); + + P.parse( argc, argv ); + + std::cout << "abcd = " << P.get( "abcd" ) << std::endl; + } + catch( rt::logic_error const& ex ) { + std::cout << "Logic error: " << ex.msg() << std::endl; + return -1; + } + + return 0; +} + +// EOF diff --git a/example/cla/dual_name.cpp b/example/cla/dual_name.cpp new file mode 100644 index 00000000..13ed2447 --- /dev/null +++ b/example/cla/dual_name.cpp @@ -0,0 +1,42 @@ +// (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) + +// See http://www.boost.org/libs/test for the library home page. + +// Boost.Runtime.Param +#include +#include + +namespace rt = boost::runtime; +namespace cla = boost::runtime::cla; + +// STL +#include + +int main() { + char* argv[] = { "basic", "/abcd", "25", "-k=1" }; + int argc = sizeof(argv)/sizeof(char*); + + try { + cla::parser P; + + P << cla::dual_name_parameter( "abcd|a" ) - (cla::prefix = "/|-") + << cla::dual_name_parameter() - (cla::name = "klmn|k", cla::separator = "|="); + + P.parse( argc, argv ); + + std::cout << "abcd = " << P.get( "abcd" ) << std::endl; + + std::cout << "klmn = " << P.get( "k" ) << std::endl; + } + catch( rt::logic_error const& ex ) { + std::cout << "Logic error: " << ex.msg() << std::endl; + return -1; + } + + return 0; +} + +// EOF diff --git a/example/cla/global.cpp b/example/cla/global.cpp new file mode 100644 index 00000000..06c97468 --- /dev/null +++ b/example/cla/global.cpp @@ -0,0 +1,46 @@ +// (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) + +// See http://www.boost.org/libs/test for the library home page. + +// Boost.Runtime.Param +#include +#include +#include + +namespace rt = boost::runtime; +namespace cla = boost::runtime::cla; + +// STL +#include + +int main() { + char* argv[] = { "basic", "--abcd=25", "1.23", "--klmn", "wert" }; + int argc = sizeof(argv)/sizeof(char*); + + try { + cla::parser P; + float f; + + P - (cla::prefix = "--", cla::guess_name) + << cla::named_parameter( "abcd" ) - (cla::separator = "=") + << cla::named_parameter( "klmn" ) + << cla::positional_parameter() - (cla::assign_to = f); + + P.parse( argc, argv ); + + std::cout << "abcd = " << P.get( "abcd" ) << std::endl; + std::cout << "klmn = " << P.get( "klmn" ) << std::endl; + std::cout << "f = " << f << std::endl; + } + catch( rt::logic_error const& ex ) { + std::cout << "Logic error: " << ex.msg() << std::endl; + return -1; + } + + return 0; +} + +// EOF diff --git a/example/cla/guess_name.cpp b/example/cla/guess_name.cpp new file mode 100644 index 00000000..1304a838 --- /dev/null +++ b/example/cla/guess_name.cpp @@ -0,0 +1,39 @@ +// (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) + +// See http://www.boost.org/libs/test for the library home page. + +// Boost.Runtime.Param +#include +#include + +namespace rt = boost::runtime; +namespace cla = boost::runtime::cla; + +// STL +#include + +int main() { + char* argv[] = { "basic", "-a", "25" }; + int argc = sizeof(argv)/sizeof(char*); + + try { + cla::parser P; + + P << cla::named_parameter( "abcd" ) - cla::guess_name; + + P.parse( argc, argv ); + + std::cout << "abcd = " << P.get( "ab" ) << std::endl; + } + catch( rt::logic_error const& ex ) { + std::cout << "Logic error: " << ex.msg() << std::endl; + return -1; + } + + return 0; +} + +// EOF diff --git a/example/cla/help.cpp b/example/cla/help.cpp new file mode 100644 index 00000000..2e358e50 --- /dev/null +++ b/example/cla/help.cpp @@ -0,0 +1,43 @@ +// (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) + +// See http://www.boost.org/libs/test for the library home page. + +// Boost.Runtime.Param +#include +#include +#include + +namespace rt = boost::runtime; +namespace cla = boost::runtime::cla; + +// STL +#include + +int main() { + char* argv[] = { "/usr/local/bin/basic1", }; + int argc = sizeof(argv)/sizeof(char*); + + cla::parser P; + + try { + P - (cla::prefix = "--", cla::separator = "=") + << cla::dual_name_parameter( "quiet|q" ) - (cla::description = "verbosity level") + << cla::named_parameter( "hostname" ) - (cla::guess_name, cla::description = "ABC server host name") + << cla::named_parameter( "port" ) - (cla::guess_name, cla::description = "ABC server port") + << cla::dual_name_parameter( "help|?" ) - (cla::description = "this help message"); + + P.parse( argc, argv ); + } + catch( rt::logic_error const& ex ) { + std::cout << "Logic error: " << ex.msg() << std::endl; + P.help( std::cout ); + return -1; + } + + return 0; +} + +// EOF diff --git a/example/cla/ignore_mismatch.cpp b/example/cla/ignore_mismatch.cpp new file mode 100644 index 00000000..1c497d07 --- /dev/null +++ b/example/cla/ignore_mismatch.cpp @@ -0,0 +1,40 @@ +// (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) + +// See http://www.boost.org/libs/test for the library home page. + +// Boost.Runtime.Param +#include +#include + +namespace rt = boost::runtime; +namespace cla = boost::runtime::cla; + +// STL +#include + +int main() { + char* argv[] = { "basic", "-abc", "25", "-abcd", "12" }; + int argc = sizeof(argv)/sizeof(char*); + + try { + cla::parser P; + + P - cla::ignore_mismatch + << cla::named_parameter( "abcd" ); + + P.parse( argc, argv ); + + std::cout << "abcd = " << P.get( "abcd" ) << std::endl; + } + catch( rt::logic_error const& ex ) { + std::cout << "Logic error: " << ex.msg() << std::endl; + return -1; + } + + return 0; +} + +// EOF diff --git a/example/cla/input_separator.cpp b/example/cla/input_separator.cpp new file mode 100644 index 00000000..180833d2 --- /dev/null +++ b/example/cla/input_separator.cpp @@ -0,0 +1,62 @@ +// (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) + +// See http://www.boost.org/libs/test for the library home page. + +// Boost.Runtime.Param +#include +#include + +namespace rt = boost::runtime; +namespace cla = boost::runtime::cla; + +// STL +#include + +struct FullName +{ + std::string first_name; + std::string last_name; +}; + +std::istream& +operator>>( std::istream& istr, FullName& f ) +{ + return istr >> f.first_name >> std::ws >> f.last_name; +} + +std::ostream& +operator<<( std::ostream& ostr, FullName const& f ) +{ + return ostr << f.first_name << ' ' << f.last_name; +} + +int main() { + char* argv[] = { "basic", "name=John Doe:name=Joan Doe:name=Your Name" }; + int argc = sizeof(argv)/sizeof(char*); + + try { + cla::parser P; + + P - ( cla::input_separator = ':' ) + << cla::named_parameter( "name" ) - ( cla::multiplicable, cla::separator = "=", cla::prefix = "" ); + + P.parse( argc, argv ); + + std::list arg_values = P.get >( "name" ); + + std::cout << "names: "; + std::copy( arg_values.begin(), arg_values.end(), std::ostream_iterator( std::cout, ", " ) ); + std::cout << std::endl; + } + catch( rt::logic_error const& ex ) { + std::cout << "Logic error: " << ex.msg() << std::endl; + return -1; + } + + return 0; +} + +// EOF diff --git a/example/cla/multiplicable.cpp b/example/cla/multiplicable.cpp new file mode 100644 index 00000000..d328cf46 --- /dev/null +++ b/example/cla/multiplicable.cpp @@ -0,0 +1,44 @@ +// (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) + +// See http://www.boost.org/libs/test for the library home page. + +// Boost.Runtime.Param +#include +#include + +namespace rt = boost::runtime; +namespace cla = boost::runtime::cla; + +// STL +#include +#include + +int main() { + char* argv[] = { "basic", "-abcd", "25", "-abcd", "20", "-abcd", "15", "-abcd", "10", "-abcd", "5" }; + int argc = sizeof(argv)/sizeof(char*); + + try { + cla::parser P; + + P << cla::named_parameter( "abcd" ) - cla::multiplicable; + + P.parse( argc, argv ); + + std::list arg_values = P.get< std::list >( "abcd" ); + + std::cout << "abcd = "; + std::copy( arg_values.begin(), arg_values.end(), std::ostream_iterator( std::cout, " " ) ); + std::cout << std::endl; + } + catch( rt::logic_error const& ex ) { + std::cout << "Logic error: " << ex.msg() << std::endl; + return -1; + } + + return 0; +} + +// EOF diff --git a/example/cla/name.cpp b/example/cla/name.cpp new file mode 100644 index 00000000..401cbf97 --- /dev/null +++ b/example/cla/name.cpp @@ -0,0 +1,39 @@ +// (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) + +// See http://www.boost.org/libs/test for the library home page. + +// Boost.Runtime.Param +#include +#include + +namespace rt = boost::runtime; +namespace cla = boost::runtime::cla; + +// STL +#include + +int main() { + char* argv[] = { "basic", "-abcd", "-0.12" }; + int argc = sizeof(argv)/sizeof(char*); + + try { + cla::parser P; + + P << cla::named_parameter() - (cla::name = "abcd"); + + P.parse( argc, argv ); + + std::cout << "abcd = " << P.get( "abcd" ) << std::endl; + } + catch( rt::logic_error const& ex ) { + std::cout << "Logic error: " << ex.msg() << std::endl; + return -1; + } + + return 0; +} + +// EOF diff --git a/example/cla/optional.cpp b/example/cla/optional.cpp new file mode 100644 index 00000000..04a8a313 --- /dev/null +++ b/example/cla/optional.cpp @@ -0,0 +1,66 @@ +// (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) + +// See http://www.boost.org/libs/test for the library home page. + +// Boost.Runtime.Param +#include +#include + +namespace rt = boost::runtime; +namespace cla = boost::runtime::cla; + +// STL +#include + +int main() { + char* argv[] = { "basic", "-abc", "25" }; + int argc = 1; + + cla::parser P; + + try { + P << cla::named_parameter( "abcd" ) - cla::optional; + + P.parse( argc, argv ); + + if( P["abcd"] ) + std::cout << "abcd = " << P.get( "abcd" ) << std::endl; + else + std::cout << "not present" << std::endl; + + std::string s = P.get( "abcd" ); + + } + catch( rt::logic_error const& ex ) { + std::cout << "Logic error: " << ex.msg() << std::endl; + return -1; + } + + /////////////////////////////////////////////////////////// + + try { + cla::parser P1; + + P1 << cla::named_parameter( "abc" ) - cla::optional; + + argc = sizeof(argv)/sizeof(char*); + + P1.parse( argc, argv ); + + if( P1["abc"] ) + std::cout << "abc = " << P1.get( "abc" ) << std::endl; + else + std::cout << "not present" << std::endl; + } + catch( rt::logic_error const& ex ) { + std::cout << "Logic error: " << ex.msg() << std::endl; + return -1; + } + + return 0; +} + +// EOF diff --git a/example/cla/optional_value.cpp b/example/cla/optional_value.cpp new file mode 100644 index 00000000..0e910bb7 --- /dev/null +++ b/example/cla/optional_value.cpp @@ -0,0 +1,107 @@ +// (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) + +// See http://www.boost.org/libs/test for the library home page. + +// Boost.Runtime.Param +#include +#include + +namespace rt = boost::runtime; +namespace cla = boost::runtime::cla; + +// STL +#include +#include + +namespace boost { + +template +inline std::ostream& +operator<<( std::ostream& ostr, boost::optional const& v ) +{ + if( v ) + ostr << *v; + + return ostr; +} + +} + +int main() { + { + char* argv[] = { "basic", "-abcd", "-klmn", "10" }; + int argc = sizeof(argv)/sizeof(char*); + + try { + cla::parser P; + + P << cla::named_parameter( "abcd" ) - cla::optional_value + << cla::named_parameter( "klmn" ); + + P.parse( argc, argv ); + + boost::optional v = P.get >( "abcd" ); + + std::cout << "abcd " << ( v ? "present" : "not present" ) << std::endl; + std::cout << "klmn = " << P.get( "klmn" ) << std::endl; + } + catch( rt::logic_error const& ex ) { + std::cout << "Logic error: " << ex.msg() << std::endl; + return -1; + } + } + { + char* argv[] = { "basic", "-abcd", "25", "-klmn", "10" }; + int argc = sizeof(argv)/sizeof(char*); + + try { + cla::parser P; + + P << cla::named_parameter( "abcd" ) - cla::optional_value + << cla::named_parameter( "klmn" ); + + P.parse( argc, argv ); + + boost::optional v = P.get >( "abcd" ); + + if( v ) + std::cout << "*******\n""abcd = " << *v << std::endl; + + std::cout << "klmn = " << P.get( "klmn" ) << std::endl; + } + catch( rt::logic_error const& ex ) { + std::cout << "Logic error: " << ex.msg() << std::endl; + return -1; + } + } + { + char* argv[] = { "basic", "-abcd", "25", "-abcd", "-abcd", "10" }; + int argc = sizeof(argv)/sizeof(char*); + + try { + cla::parser P; + + P << cla::named_parameter( "abcd" ) - (cla::optional_value, cla::multiplicable); + + P.parse( argc, argv ); + + typedef std::list > value_type; + value_type v = P.get( "abcd" ); + + std::cout << "*******\n""abcd = "; + std::copy( v.begin(), v.end(), std::ostream_iterator >( std::cout, ", " ) ); + std::cout << std::endl; + } + catch( rt::logic_error const& ex ) { + std::cout << "Logic error: " << ex.msg() << std::endl; + return -1; + } + } + + return 0; +} + +// EOF diff --git a/example/cla/positional.cpp b/example/cla/positional.cpp new file mode 100644 index 00000000..cff85d5a --- /dev/null +++ b/example/cla/positional.cpp @@ -0,0 +1,46 @@ +// (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) + +// See http://www.boost.org/libs/test for the library home page. + +// Boost.Runtime.Param +#include +#include + +namespace rt = boost::runtime; +namespace cla = boost::runtime::cla; + +// STL +#include + +int main() { + char* argv[] = { "basic", "--klmn-- 14" }; + int argc = sizeof(argv)/sizeof(char*); + + try { + cla::parser P; + int i; + + P << cla::positional_parameter( "abcd" ) + << cla::positional_parameter() - (cla::assign_to = i) + << cla::positional_parameter( "klmn" ) - (cla::default_value = std::string("file")) + << cla::positional_parameter( "oprt" ) - cla::optional; + + P.parse( argc, argv ); + + std::cout << "abcd = " << P.get( "abcd" ) << std::endl; + std::cout << "i = " << i << std::endl; + std::cout << "klmn = " << P.get( "klmn" ) << std::endl; + std::cout << "oprt " << (P["oprt"] ? "present" : "not present" ) << std::endl; + } + catch( rt::logic_error const& ex ) { + std::cout << "Logic error: " << ex.msg() << std::endl; + return -1; + } + + return 0; +} + +// EOF diff --git a/example/cla/prefix.cpp b/example/cla/prefix.cpp new file mode 100644 index 00000000..6bc1b26b --- /dev/null +++ b/example/cla/prefix.cpp @@ -0,0 +1,41 @@ +// (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) + +// See http://www.boost.org/libs/test for the library home page. + +// Boost.Runtime.Param +#include +#include + +namespace rt = boost::runtime; +namespace cla = boost::runtime::cla; + +// STL +#include + +int main() { + char* argv[] = { "basic", "/abcd", "25", "-klmn", "abs" }; + int argc = sizeof(argv)/sizeof(char*); + + try { + cla::parser P; + + P << cla::named_parameter( "abcd" ) - ( cla::prefix = "/" ) + << cla::named_parameter( "klmn" ); + + P.parse( argc, argv ); + + std::cout << "abcd = " << P.get( "abcd" ) << std::endl; + std::cout << "klnm = " << P.get( "klmn" ) << std::endl; + } + catch( rt::logic_error const& ex ) { + std::cout << "Logic error: " << ex.msg() << std::endl; + return -1; + } + + return 0; +} + +// EOF diff --git a/example/cla/reference.cpp b/example/cla/reference.cpp new file mode 100644 index 00000000..00f8482c --- /dev/null +++ b/example/cla/reference.cpp @@ -0,0 +1,40 @@ +// (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) + +// See http://www.boost.org/libs/test for the library home page. + +// Boost.Runtime.Param +#include +#include + +namespace rt = boost::runtime; +namespace cla = boost::runtime::cla; + +// STL +#include + +int main() { + char* argv[] = { "basic", "-qwe", "25" }; + int argc = sizeof(argv)/sizeof(char*); + + try { + cla::parser P; + + P << cla::named_parameter( "abcd" ) - (cla::default_refer_to = "qwe") + << cla::named_parameter( "qwe" ); + + P.parse( argc, argv ); + + std::cout << "abcd = " << P.get( "abcd" ) << std::endl; + } + catch( rt::logic_error const& ex ) { + std::cout << "Logic error: " << ex.msg() << std::endl; + return -1; + } + + return 0; +} + +// EOF diff --git a/example/cla/remainder.cpp b/example/cla/remainder.cpp new file mode 100644 index 00000000..695ad776 --- /dev/null +++ b/example/cla/remainder.cpp @@ -0,0 +1,46 @@ +// (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) + +// See http://www.boost.org/libs/test for the library home page. + +// Boost.Runtime.Param +#include +#include + +namespace rt = boost::runtime; +namespace cla = boost::runtime::cla; + +// STL +#include + +int main() { + char* argv[] = { "basic", "-abd", "as", "-cd", "aswdf", "--da", "25", "-ffd", "(fgh,", "asd)" }; + int argc = sizeof(argv)/sizeof(char*); + + try { + cla::parser P; + + P - cla::ignore_mismatch + << cla::named_parameter( "da" ) - ( cla::prefix = "--" ) + << cla::named_parameter( "abd" ); + + P.parse( argc, argv ); + + std::cout << "da = " << P.get( "da" ) << std::endl; + std::cout << "abd = " << P.get( "abd" ) << std::endl; + + std::cout << "argc = " << argc << std::endl; + for( int i = 0; i +#include + +namespace rt = boost::runtime; +namespace cla = boost::runtime::cla; + +// STL +#include + +int main() { + char* argv[] = { "basic", "-abcd=25" }; + int argc = sizeof(argv)/sizeof(char*); + + try { + cla::parser P; + + P << cla::named_parameter( "abcd" ) - ( cla::separator = "=" ); + + P.parse( argc, argv ); + + std::cout << "abcd = " << P.get( "abcd" ) << std::endl; + } + catch( rt::logic_error const& ex ) { + std::cout << "Logic error: " << ex.msg() << std::endl; + return -1; + } + + return 0; +} + +// EOF diff --git a/example/cla/usage.cpp b/example/cla/usage.cpp new file mode 100644 index 00000000..a8bcc094 --- /dev/null +++ b/example/cla/usage.cpp @@ -0,0 +1,45 @@ +// (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) + +// See http://www.boost.org/libs/test for the library home page. + +// Boost.Runtime.Param +#include +#include +#include + +namespace rt = boost::runtime; +namespace cla = boost::runtime::cla; + +// STL +#include + +int main() { + char* argv[] = { "..\\..\\src\\basic1" }; + int argc = sizeof(argv)/sizeof(char*); + + cla::parser P; + + try { + P << cla::named_parameter( "ab" ) + << cla::named_parameter( "cd" ) - (cla::prefix = "--",cla::separator = "=", cla::optional) + << cla::dual_name_parameter( "klnm|k" ) + << cla::named_parameter( "op" ) - cla::multiplicable + << cla::named_parameter >( "rs" ) + << cla::named_parameter( "tu" ) + << cla::named_parameter( "yu" ) - cla::optional_value; + + P.parse( argc, argv ); + } + catch( rt::logic_error const& ex ) { + std::cout << "Logic error: " << ex.msg() << std::endl; + P.usage( std::cout ); + return -1; + } + + return 0; +} + +// EOF diff --git a/example/cla/validation/Jamfile b/example/cla/validation/Jamfile new file mode 100755 index 00000000..40e4355f --- /dev/null +++ b/example/cla/validation/Jamfile @@ -0,0 +1,31 @@ +# (C) Copyright Gennadiy Rozental 2001-2006. +# Use, modification, and distribution are subject to 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. + +subproject libs/test/example/cla/validation ; + +DEPENDS test : all ; + +rule boost-runtime-param-example ( example-name ) +{ + exe $(example-name) : $(example-name).cpp + : $(BOOST_ROOT) + on + <*>-w-8080 ; +} + +boost-runtime-param-example access_unknown ; +boost-runtime-param-example ambiguous_access ; +boost-runtime-param-example ambiguous_input ; +boost-runtime-param-example definition_conflict ; +boost-runtime-param-example invalid_short_name ; +boost-runtime-param-example multiple_generators ; +boost-runtime-param-example multiple_value_handlers ; +boost-runtime-param-example opt_with_default_value ; +boost-runtime-param-example optional_plus_multiplicable ; +boost-runtime-param-example required_missing ; +boost-runtime-param-example unexpected_input ; +boost-runtime-param-example unexpected_repetition ; diff --git a/example/cla/validation/access_unknown.cpp b/example/cla/validation/access_unknown.cpp new file mode 100644 index 00000000..20e4e327 --- /dev/null +++ b/example/cla/validation/access_unknown.cpp @@ -0,0 +1,37 @@ +// (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) + +// See http://www.boost.org/libs/test for the library home page. + +// Boost.Runtime.Param +#include +#include + +namespace rt = boost::runtime; +namespace cla = boost::runtime::cla; + +// STL +#include + +int main() { + char* argv[] = { "basic", "-abcd", "25" }; + int argc = sizeof(argv)/sizeof(char*); + + try { + cla::parser P; + + P << cla::named_parameter( "abcd" ); + + P.parse( argc, argv ); + + P["ab"]; + } + catch( rt::logic_error const& ex ) { + std::cout << "Logic error: " << ex.msg() << std::endl; + return -1; + } + + return 0; +} diff --git a/example/cla/validation/ambiguous_access.cpp b/example/cla/validation/ambiguous_access.cpp new file mode 100644 index 00000000..1cadd563 --- /dev/null +++ b/example/cla/validation/ambiguous_access.cpp @@ -0,0 +1,39 @@ +// (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) + +// See http://www.boost.org/libs/test for the library home page. + +// Boost.Runtime.Param +#include +#include + +namespace rt = boost::runtime; +namespace cla = boost::runtime::cla; + +// STL +#include + +int main() { + char* argv[] = { "basic", "-abc", "25" }; + int argc = sizeof(argv)/sizeof(char*); + + + try { + cla::parser P; + + P << cla::named_parameter( "abfv" ) - (cla::guess_name, cla::optional) + << cla::named_parameter( "abcd" ) - cla::guess_name; + + P.parse( argc, argv ); + + P["ab"]; + } + catch( rt::logic_error const& ex ) { + std::cout << "Logic error: " << ex.msg() << std::endl; + return -1; + } + + return 0; +} diff --git a/example/cla/validation/ambiguous_input.cpp b/example/cla/validation/ambiguous_input.cpp new file mode 100644 index 00000000..d901e49a --- /dev/null +++ b/example/cla/validation/ambiguous_input.cpp @@ -0,0 +1,36 @@ +// (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) + +// See http://www.boost.org/libs/test for the library home page. + +// Boost.Runtime.Param +#include +#include + +namespace rt = boost::runtime; +namespace cla = boost::runtime::cla; + +// STL +#include + +int main() { + char* argv[] = { "basic", "-ab", "25" }; + int argc = sizeof(argv)/sizeof(char*); + + try { + cla::parser P; + + P << cla::named_parameter( "abfv" ) - cla::guess_name + << cla::named_parameter( "abcd" ) - cla::guess_name; + + P.parse( argc, argv ); + } + catch( rt::logic_error const& ex ) { + std::cout << "Logic error: " << ex.msg() << std::endl; + return -1; + } + + return 0; +} diff --git a/example/cla/validation/definition_conflict.cpp b/example/cla/validation/definition_conflict.cpp new file mode 100644 index 00000000..ea143efc --- /dev/null +++ b/example/cla/validation/definition_conflict.cpp @@ -0,0 +1,71 @@ +// (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) + +// See http://www.boost.org/libs/test for the library home page. + +// Boost.Runtime.Param +#include +#include +#include + +namespace rt = boost::runtime; +namespace cla = boost::runtime::cla; + +// STL +#include + +int main() { + char* argv[] = { "basic", "-abcd", "25" }; + int argc = sizeof(argv)/sizeof(char*); + + + try { + cla::parser P; + + P << cla::named_parameter( "abcd" ) + << cla::named_parameter( "abcd" ); + + P.parse( argc, argv ); + } + catch( rt::logic_error const& ex ) { + std::cout << "Logic error: " << ex.msg() << std::endl; + } + + try { + cla::parser P; + + P << cla::named_parameter( "abcd" ) - cla::guess_name + << cla::named_parameter( "ab" ); + + P.parse( argc, argv ); + } + catch( rt::logic_error const& ex ) { + std::cout << "Logic error: " << ex.msg() << std::endl; + } + try { + cla::parser P; + + P << cla::named_parameter( "abcd" ) - cla::guess_name + << cla::named_parameter( "abdf" ) - cla::guess_name; + + P.parse( argc, argv ); + } + catch( rt::logic_error const& ex ) { + std::cout << "Logic error: " << ex.msg() << std::endl; + } + try { + cla::parser P; + + P << cla::named_parameter( "abcd" ) - cla::guess_name + << cla::char_parameter( 'a' ); + + P.parse( argc, argv ); + } + catch( rt::logic_error const& ex ) { + std::cout << "Logic error: " << ex.msg() << std::endl; + } + + return 0; +} diff --git a/example/cla/validation/invalid_short_name.cpp b/example/cla/validation/invalid_short_name.cpp new file mode 100644 index 00000000..79828548 --- /dev/null +++ b/example/cla/validation/invalid_short_name.cpp @@ -0,0 +1,33 @@ +// (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) + +// See http://www.boost.org/libs/test for the library home page. + +// Boost.Runtime.Param +#include +#include + +namespace rt = boost::runtime; +namespace cla = boost::runtime::cla; + +// STL +#include + +int main() { + char* argv[] = { "basic", "--klmn", "25" }; + int argc = sizeof(argv)/sizeof(char*); + + try { + cla::parser P; + + P << cla::dual_name_parameter() - (cla::name = "klmn|kl"); + } + catch( rt::logic_error const& ex ) { + std::cout << "Logic error: " << ex.msg() << std::endl; + return -1; + } + + return 0; +} diff --git a/example/cla/validation/multiple_generators.cpp b/example/cla/validation/multiple_generators.cpp new file mode 100644 index 00000000..3b53e366 --- /dev/null +++ b/example/cla/validation/multiple_generators.cpp @@ -0,0 +1,35 @@ +// (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) + +// See http://www.boost.org/libs/test for the library home page. + +// Boost.Runtime.Param +#include +#include + +namespace rt = boost::runtime; +namespace cla = boost::runtime::cla; + +// STL +#include + +int main() { + char* argv[] = { "basic", "-abcd", "25" }; + int argc = sizeof(argv)/sizeof(char*); + + cla::parser P; + + P << cla::named_parameter( "abcd" ) - ( cla::default_value = 1, cla::default_value = 2 ); + + try { + P.parse( argc, argv ); + } + catch( rt::logic_error const& ex ) { + std::cout << "Logic error: " << ex.msg() << std::endl; + return -1; + } + + return 0; +} diff --git a/example/cla/validation/multiple_value_handlers.cpp b/example/cla/validation/multiple_value_handlers.cpp new file mode 100644 index 00000000..3e24dcab --- /dev/null +++ b/example/cla/validation/multiple_value_handlers.cpp @@ -0,0 +1,36 @@ +// (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) + +// See http://www.boost.org/libs/test for the library home page. + +// Boost.Runtime.Param +#include +#include + +namespace rt = boost::runtime; +namespace cla = boost::runtime::cla; + +// STL +#include + +int main() { + char* argv[] = { "basic", "-abcd", "25" }; + int argc = sizeof(argv)/sizeof(char*); + + try { + cla::parser P; + + int i, j; + + P << cla::named_parameter( "abcd" ) - (cla::assign_to = i,cla::assign_to = j) ; + // !! does not work + } + catch( rt::logic_error const& ex ) { + std::cout << "Logic error: " << ex.msg() << std::endl; + return -1; + } + + return 0; +} diff --git a/example/cla/validation/opt_with_default_value.cpp b/example/cla/validation/opt_with_default_value.cpp new file mode 100644 index 00000000..1b597218 --- /dev/null +++ b/example/cla/validation/opt_with_default_value.cpp @@ -0,0 +1,35 @@ +// (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) + +// See http://www.boost.org/libs/test for the library home page. + +// Boost.Runtime.Param +#include +#include + +namespace rt = boost::runtime; +namespace cla = boost::runtime::cla; + +// STL +#include + +int main() { + char* argv[] = { "basic", "-abcd", "25" }; + int argc = sizeof(argv)/sizeof(char*); + + try { + cla::parser P; + + P << cla::named_parameter( "abcd" ) - ( cla::optional, cla::default_value = 5 ); + + P.parse( argc, argv ); + } + catch( rt::logic_error const& ex ) { + std::cout << "Logic error: " << ex.msg() << std::endl; + return -1; + } + + return 0; +} diff --git a/example/cla/validation/optional_plus_multiplicable.cpp b/example/cla/validation/optional_plus_multiplicable.cpp new file mode 100644 index 00000000..40ab88ca --- /dev/null +++ b/example/cla/validation/optional_plus_multiplicable.cpp @@ -0,0 +1,80 @@ +// (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) + +// See http://www.boost.org/libs/test for the library home page. + +// Boost.Runtime.Param +#include +#include + +namespace rt = boost::runtime; +namespace cla = boost::runtime::cla; + +// STL +#include + +int main() { + { + char* argv[] = { "basic" }; + int argc = sizeof(argv)/sizeof(char*); + + try { + cla::parser P; + P << cla::named_parameter( "abcd" ) - (cla::optional, cla::multiplicable); + P.parse( argc, argv ); + + std::cout << "abcd = " << (P["abcd"] ? "present" : "not present" ); + std::cout << std::endl; + } + catch( rt::logic_error const& ex ) { + std::cout << "Logic error: " << ex.msg() << std::endl; + return -1; + } + } + + { + char* argv[] = { "basic", "-abcd", "25" }; + int argc = sizeof(argv)/sizeof(char*); + + try { + cla::parser P; + P << cla::named_parameter( "abcd" ) - (cla::optional, cla::multiplicable); + P.parse( argc, argv ); + + std::list arg_values = P.get >( "abcd" ); + + std::cout << "abcd = "; + std::copy( arg_values.begin(), arg_values.end(), std::ostream_iterator( std::cout, " " ) ); + std::cout << std::endl; + } + catch( rt::logic_error const& ex ) { + std::cout << "Logic error: " << ex.msg() << std::endl; + return -1; + } + } + + { + char* argv[] = { "basic", "-abcd", "25", "-abcd", "50" }; + int argc = sizeof(argv)/sizeof(char*); + + try { + cla::parser P; + P << cla::named_parameter( "abcd" ) - (cla::optional, cla::multiplicable); + P.parse( argc, argv ); + + std::list arg_values = P.get >( "abcd" ); + + std::cout << "abcd = "; + std::copy( arg_values.begin(), arg_values.end(), std::ostream_iterator( std::cout, " " ) ); + std::cout << std::endl; + } + catch( rt::logic_error const& ex ) { + std::cout << "Logic error: " << ex.msg() << std::endl; + return -1; + } + } + + return 0; +} diff --git a/example/cla/validation/required_missing.cpp b/example/cla/validation/required_missing.cpp new file mode 100644 index 00000000..bafd190a --- /dev/null +++ b/example/cla/validation/required_missing.cpp @@ -0,0 +1,35 @@ +// (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) + +// See http://www.boost.org/libs/test for the library home page. + +// Boost.Runtime.Param +#include +#include + +namespace rt = boost::runtime; +namespace cla = boost::runtime::cla; + +// STL +#include + +int main() { + char* argv[] = { "basic" }; + int argc = sizeof(argv)/sizeof(char*); + + try { + cla::parser P; + + P << cla::named_parameter( "abcd" ); + + P.parse( argc, argv ); + } + catch( rt::logic_error const& ex ) { + std::cout << "Logic error: " << ex.msg() << std::endl; + return -1; + } + + return 0; +} diff --git a/example/cla/validation/unexpected_input.cpp b/example/cla/validation/unexpected_input.cpp new file mode 100644 index 00000000..1d540e60 --- /dev/null +++ b/example/cla/validation/unexpected_input.cpp @@ -0,0 +1,35 @@ +// (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) + +// See http://www.boost.org/libs/test for the library home page. + +// Boost.Runtime.Param +#include +#include + +namespace rt = boost::runtime; +namespace cla = boost::runtime::cla; + +// STL +#include + +int main() { + char* argv[] = { "basic", "-ab", "25" }; + int argc = sizeof(argv)/sizeof(char*); + + try { + cla::parser P; + + P << cla::named_parameter( "abcd" ); + + P.parse( argc, argv ); + } + catch( rt::logic_error const& ex ) { + std::cout << "Logic error: " << ex.msg() << std::endl; + return -1; + } + + return 0; +} diff --git a/example/cla/validation/unexpected_repetition.cpp b/example/cla/validation/unexpected_repetition.cpp new file mode 100644 index 00000000..69beef4a --- /dev/null +++ b/example/cla/validation/unexpected_repetition.cpp @@ -0,0 +1,35 @@ +// (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) + +// See http://www.boost.org/libs/test for the library home page. + +// Boost.Runtime.Param +#include +#include + +namespace rt = boost::runtime; +namespace cla = boost::runtime::cla; + +// STL +#include + +int main() { + char* argv[] = { "basic", "-abcd", "25", "-abcd", "26" }; + int argc = sizeof(argv)/sizeof(char*); + + try { + cla::parser P; + + P << cla::named_parameter( "abcd" ); + + P.parse( argc, argv ); + } + catch( rt::logic_error const& ex ) { + std::cout << "Logic error: " << ex.msg() << std::endl; + return -1; + } + + return 0; +} diff --git a/example/cla/wide_string.cpp b/example/cla/wide_string.cpp new file mode 100644 index 00000000..50e836f0 --- /dev/null +++ b/example/cla/wide_string.cpp @@ -0,0 +1,40 @@ +// (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) + +// See http://www.boost.org/libs/test for the library home page. + +// Boost.Runtime.Param +#define BOOST_RT_PARAM_WIDE_STRING +#include +#include + +namespace rt = boost::wide_runtime; +namespace cla = boost::wide_runtime::cla; + +// STL +#include + +int main() { + wchar_t* argv[] = { L"basic", L"-àáâã", L"25" }; + int argc = sizeof(argv)/sizeof(char*); + + try { + cla::parser P; + + P << cla::named_parameter( L"àáâã" ); + + P.parse( argc, argv ); + + std::wcout << L"àáâã = " << P.get( L"àáâã" ) << std::endl; + } + catch( rt::logic_error const& ex ) { + std::wcout << L"Logic Error: " << ex.msg() << std::endl; + return -1; + } + + return 0; +} + +// EOF diff --git a/example/env/Jamfile b/example/env/Jamfile new file mode 100755 index 00000000..d7ae6ccb --- /dev/null +++ b/example/env/Jamfile @@ -0,0 +1,31 @@ +# (C) Copyright Gennadiy Rozental 2001-2006. +# Use, modification, and distribution are subject to 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. + +subproject libs/test/example/env ; + +# bring in the rules for testing +import testing ; + +# Make tests run by default. +DEPENDS all : test ; + +rule boost-runtime-param-example ( example-name ) +{ + return [ compile $(example-name).cpp + : on <*>-w-8080 + : $(example-name) + ] ; +} + +test-suite "cla_examples" + [ boost-runtime-param-example custom_interpreter_env ] + [ boost-runtime-param-example env_var_default_value ] + [ boost-runtime-param-example environment_ex ] + [ boost-runtime-param-example global_id ] + [ boost-runtime-param-example modifier_combination ] + [ boost-runtime-param-example variable_ex ] +; diff --git a/example/env/custom_interpreter_env.cpp b/example/env/custom_interpreter_env.cpp new file mode 100644 index 00000000..34c20647 --- /dev/null +++ b/example/env/custom_interpreter_env.cpp @@ -0,0 +1,42 @@ +// (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) + +// See http://www.boost.org/libs/test for the library home page. + +// Boost.Runtime.Param +#include +#include + +namespace rt = boost::runtime; +namespace env = boost::runtime::env; + +// STL +#include + +void +named_integer( rt::cstring source, boost::optional& value ) +{ + if( source == "one" ) + value = 1; + else if( source == "two" ) + value = 2; + else + value = 0; +} + +env::variable NUMBER1( "NUMBER1", env::interpreter = &named_integer ); + +int main() { + + std::cout << NUMBER1 << std::endl; + + std::cout << env::var( "NUMBER2", ( env::interpreter = &named_integer, env::default_value = 10 )) + << std::endl; + + return 0; +} + +// EOF + diff --git a/example/env/env_var_default_value.cpp b/example/env/env_var_default_value.cpp new file mode 100644 index 00000000..89d4aed5 --- /dev/null +++ b/example/env/env_var_default_value.cpp @@ -0,0 +1,27 @@ +// (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) + +// See http://www.boost.org/libs/test for the library home page. + +// Boost.Runtime.Param +#include +#include + +namespace rt = boost::runtime; +namespace env = boost::runtime::env; + +// STL +#include + +int main() { + env::variable TEMP( "abc", env::default_value = 5 ); + + std::cout << TEMP << std::endl; + + return 0; +} + +// EOF + diff --git a/example/env/environment_ex.cpp b/example/env/environment_ex.cpp new file mode 100644 index 00000000..0ce7ad4e --- /dev/null +++ b/example/env/environment_ex.cpp @@ -0,0 +1,32 @@ +// (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) + +// See http://www.boost.org/libs/test for the library home page. + +// Boost.Runtime.Param +#include +#include + +namespace rt = boost::runtime; +namespace env = boost::runtime::env; + +// STL +#include + +int main() { + std::cout << env::get("NUMBER_OF_PROCESSORS") << '\n' << env::get("TEMP") << std::endl; + + boost::optional n; + + env::get( "NUMBER_OF_PROCESSORS", n ); + + if( n ) + std::cout << n << std::endl; + + return 0; +} + +// EOF + diff --git a/example/env/global_id.cpp b/example/env/global_id.cpp new file mode 100644 index 00000000..716594fe --- /dev/null +++ b/example/env/global_id.cpp @@ -0,0 +1,25 @@ +// (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) + +// See http://www.boost.org/libs/test for the library home page. + +// Boost.Runtime.Param +#include +#include + +namespace rt = boost::runtime; +namespace env = boost::runtime::env; + +// STL +#include + +int main() { + env::variable<> TEMP( "TEMP", env::global_id = "temp_dir_location" ); + + return 0; +} + +// EOF + diff --git a/example/env/modifier_combination.cpp b/example/env/modifier_combination.cpp new file mode 100644 index 00000000..47f89d91 --- /dev/null +++ b/example/env/modifier_combination.cpp @@ -0,0 +1,27 @@ +// (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) + +// See http://www.boost.org/libs/test for the library home page. + +// Boost.Runtime.Param +#include +#include + +namespace rt = boost::runtime; +namespace env = boost::runtime::env; + +// STL +#include + +int main() { + env::variable TEMP( "abc", (env::global_id = "temp_dir_location", env::default_value = 5) ); + + std::cout << TEMP << std::endl; + + return 0; +} + +// EOF + diff --git a/example/env/validation/Jamfile b/example/env/validation/Jamfile new file mode 100755 index 00000000..36c72182 --- /dev/null +++ b/example/env/validation/Jamfile @@ -0,0 +1,20 @@ +# (C) Copyright Gennadiy Rozental 2001-2006. +# Use, modification, and distribution are subject to 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. + +subproject libs/test/example/env/validation ; + +DEPENDS test : all ; + +rule boost-runtime-param-example ( example-name ) +{ + exe $(example-name) : $(example-name).cpp + : $(BOOST_ROOT) + on + <*>-w-8080 ; +} + +boost-runtime-param-example need_typed_access ; diff --git a/example/env/validation/need_typed_access.cpp b/example/env/validation/need_typed_access.cpp new file mode 100644 index 00000000..4e674b65 --- /dev/null +++ b/example/env/validation/need_typed_access.cpp @@ -0,0 +1,41 @@ +// (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) + +// See http://www.boost.org/libs/test for the library home page. + +// Boost.Runtime.Param +#include +#include + +namespace rt = boost::runtime; +namespace env = boost::runtime::env; + +// STL +#include + +// Boost.Runtime.Param +#include +namespace rt = boost::runtime; +namespace env = boost::runtime::environment; + +// Boost.Test +#include + +// STL +#include + +int main() { + try { + std::cout << env::var("ABC").value(); + } + catch ( rt::logic_error const& ex ) { + std::cout << ex.msg(); + } + + return 0; +} + +// EOF + diff --git a/example/env/variable_ex.cpp b/example/env/variable_ex.cpp new file mode 100644 index 00000000..a3a2c669 --- /dev/null +++ b/example/env/variable_ex.cpp @@ -0,0 +1,67 @@ +// (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) + +// See http://www.boost.org/libs/test for the library home page. + +// Boost.Runtime.Param +#include +#include + +namespace rt = boost::runtime; +namespace env = boost::runtime::env; + +// STL +#include + +env::variable<> TEMP( "TEMP" ); + +env::variable ProcNumber( "NUMBER_OF_PROCESSORS" ); + +env::variable abc( "abccccc" ); + +void print_int( env::variable_base const& var ) { + std::cout << var.name() << (var.has_value() ? " is present: " : " is not present: " ) << var.value() << std::endl; +} + +int main() { + std::cout << TEMP << '\n' << ProcNumber << std::endl; + + rt::cstring val = TEMP.value(); + std::cout << " val=" << val << std::endl; + + int n = ProcNumber.value(); + + std::cout << " n=" << n << std::endl; + + boost::optional opt_n; + ProcNumber.value( opt_n ); + + std::cout << " n=" << opt_n << std::endl; + + print_int( ProcNumber ); + + if( ProcNumber == 1 ) + std::cout << "ProcNumber = 1\n"; + + if( 2 != ProcNumber ) + std::cout << "ProcNumber != 2\n"; + + if( abc != 1 ) + std::cout << "abc != 1\n"; + + abc = 1; + + if( abc == 1 ) + std::cout << "abc == 1\n"; + + TEMP = "../tmp"; + + std::cout << TEMP << std::endl; + + return 0; +} + +// EOF + diff --git a/example/unit_test_example_01.cpp b/example/unit_test_example_01.cpp index 4bfcae17..3c8e7b09 100644 --- a/example/unit_test_example_01.cpp +++ b/example/unit_test_example_01.cpp @@ -9,7 +9,8 @@ // each test module could contain no more then one 'main' file with init function defined // alternatively you could define init function yourself -#define BOOST_TEST_MAIN +//#define BOOST_TEST_MAIN +#define BOOST_TEST_NO_MAIN #include namespace bt = boost::unit_test; diff --git a/include/boost/test/data/config.hpp b/include/boost/test/data/config.hpp index efff9b7f..bedfae5d 100644 --- a/include/boost/test/data/config.hpp +++ b/include/boost/test/data/config.hpp @@ -41,7 +41,8 @@ //____________________________________________________________________________// -#define BOOST_TEST_DS_ERROR( msg ) BOOST_TEST_I_THROW( std::logic_error( msg ) ) -#define BOOST_TEST_DS_ASSERT( cond, msg ) BOOST_TEST_I_ASSRT( cond, std::logic_error( msg ) ) +#define BOOST_TEST_DS_ERROR( msg ) BOOST_TEST_IMPL_THROW( std::logic_error( msg ) ) +#define BOOST_TEST_DS_ASSERT( cond, msg ) if( cond ) {} else BOOST_TEST_DS_ERROR( msg ) #endif // BOOST_TEST_DATA_CONFIG_HPP_112611GER + diff --git a/include/boost/test/data/monomorphic/generators/xrange.hpp b/include/boost/test/data/monomorphic/generators/xrange.hpp index b9464b99..55a51110 100644 --- a/include/boost/test/data/monomorphic/generators/xrange.hpp +++ b/include/boost/test/data/monomorphic/generators/xrange.hpp @@ -179,8 +179,7 @@ xrange( SampleType const& end_val ) /// @overload boost::unit_test::data::xrange() template -inline typename enable_if_c::value, - monomorphic::generated_by > >::type +inline typename enable_if_c::value,monomorphic::generated_by > >::type xrange( SampleType const& end_val, Params const& params ) { return monomorphic::ds_detail::make_xrange:: diff --git a/include/boost/test/detail/global_typedef.hpp b/include/boost/test/detail/global_typedef.hpp index c09ddf93..0c71479a 100644 --- a/include/boost/test/detail/global_typedef.hpp +++ b/include/boost/test/detail/global_typedef.hpp @@ -19,11 +19,11 @@ #define BOOST_TEST_STRINGIZE( s ) BOOST_TEST_L( BOOST_STRINGIZE( s ) ) #define BOOST_TEST_EMPTY_STRING BOOST_TEST_L( "" ) -#define BOOST_TEST_SCOPE_SETCOLOR( is_color_output, os, attr, color ) \ - scope_setcolor const& sc = is_color_output \ - ? scope_setcolor( os, attr, color ) \ - : scope_setcolor(); \ - ut_detail::ignore_unused_variable_warning( sc ) \ +#define BOOST_TEST_SCOPE_SETCOLOR( os, attr, color ) \ + scope_setcolor const& sc = runtime_config::color_output() \ + ? scope_setcolor( os, attr, color ) \ + : scope_setcolor(); \ + ut_detail::ignore_unused_variable_warning( sc ) \ /**/ #include diff --git a/include/boost/test/detail/throw_exception.hpp b/include/boost/test/detail/throw_exception.hpp index d3d2e97d..ff347dfe 100644 --- a/include/boost/test/detail/throw_exception.hpp +++ b/include/boost/test/detail/throw_exception.hpp @@ -35,11 +35,11 @@ template BOOST_NORETURN inline void throw_exception(E const& e) { abort(); } -#define BOOST_TEST_I_TRY -#define BOOST_TEST_I_CATCH( T, var ) for(T const& var = *(T*)0; false;) -#define BOOST_TEST_I_CATCH0( T ) if(0) -#define BOOST_TEST_I_CATCHALL() if(0) -#define BOOST_TEST_I_RETHROW +#define BOOST_TEST_IMPL_TRY +#define BOOST_TEST_IMPL_CATCH( T, var ) for(T const& var = *(T*)0; false;) +#define BOOST_TEST_IMPL_CATCH0( T ) if(0) +#define BOOST_TEST_IMPL_CATCHALL() if(0) +#define BOOST_TEST_IMPL_RETHROW #else @@ -47,19 +47,16 @@ template BOOST_NORETURN inline void throw_exception(E const& e) { throw e; } -#define BOOST_TEST_I_TRY try -#define BOOST_TEST_I_CATCH( T, var ) catch( T const& var ) -#define BOOST_TEST_I_CATCH0( T ) catch( T const& ) -#define BOOST_TEST_I_CATCHALL() catch(...) -#define BOOST_TEST_I_RETHROW throw +#define BOOST_TEST_IMPL_TRY try +#define BOOST_TEST_IMPL_CATCH( T, var ) catch( T const& var ) +#define BOOST_TEST_IMPL_CATCH0( T ) catch( T const& ) +#define BOOST_TEST_IMPL_CATCHALL() catch(...) +#define BOOST_TEST_IMPL_RETHROW throw #endif //____________________________________________________________________________// -#define BOOST_TEST_I_THROW( E ) unit_test::ut_detail::throw_exception( E ) -#define BOOST_TEST_I_THROW( E ) unit_test::ut_detail::throw_exception( E ) -#define BOOST_TEST_I_ASSRT( cond, ex ) if( cond ) {} else BOOST_TEST_I_THROW( ex ) - +#define BOOST_TEST_IMPL_THROW( E ) unit_test::ut_detail::throw_exception( E ) } // namespace ut_detail } // namespace unit_test diff --git a/include/boost/test/execution_monitor.hpp b/include/boost/test/execution_monitor.hpp index 2985a6d9..b01137da 100644 --- a/include/boost/test/execution_monitor.hpp +++ b/include/boost/test/execution_monitor.hpp @@ -415,10 +415,10 @@ public: // translator holder interface virtual int operator()( boost::function const& F ) { - BOOST_TEST_I_TRY { + BOOST_TEST_IMPL_TRY { return m_next ? (*m_next)( F ) : F(); } - BOOST_TEST_I_CATCH( ExceptionType, e ) { + BOOST_TEST_IMPL_CATCH( ExceptionType, e ) { m_translator( e ); return boost::exit_exception_failure; } @@ -461,11 +461,13 @@ public: // Constructor explicit system_error( char const* exp ); - long const p_errno; - char const* const p_failed_exp; + unit_test::readonly_property p_errno; + unit_test::readonly_property p_failed_exp; }; -#define BOOST_TEST_SYS_ASSERT( cond ) BOOST_TEST_I_ASSRT( cond, ::boost::system_error( BOOST_STRINGIZE( exp ) ) ) +#define BOOST_TEST_SYS_ASSERT( exp ) \ + if( (exp) ) ; \ + else BOOST_TEST_IMPL_THROW( ::boost::system_error( BOOST_STRINGIZE( exp ) ) ) // ************************************************************************** // // **************Floating point exception management interface ************** // diff --git a/include/boost/test/framework.hpp b/include/boost/test/framework.hpp index 7bfead03..9679f4fc 100644 --- a/include/boost/test/framework.hpp +++ b/include/boost/test/framework.hpp @@ -254,7 +254,9 @@ struct BOOST_TEST_DECL setup_error : public std::runtime_error { setup_error( const_string m ) : std::runtime_error( std::string( m.begin(), m.size() ) ) {} }; -#define BOOST_TEST_SETUP_ASSERT( cond, msg ) BOOST_TEST_I_ASSRT( cond, unit_test::framework::setup_error( msg ) ) +#define BOOST_TEST_SETUP_ASSERT( cond, msg ) \ + if( cond ) {} \ + else BOOST_TEST_IMPL_THROW( unit_test::framework::setup_error( msg ) ) //____________________________________________________________________________// @@ -269,3 +271,4 @@ struct nothing_to_test {}; // not really an error #include #endif // BOOST_TEST_FRAMEWORK_HPP_020805GER + diff --git a/include/boost/test/impl/compiler_log_formatter.ipp b/include/boost/test/impl/compiler_log_formatter.ipp index b251bb74..c1ed944a 100644 --- a/include/boost/test/impl/compiler_log_formatter.ipp +++ b/include/boost/test/impl/compiler_log_formatter.ipp @@ -16,18 +16,14 @@ #define BOOST_TEST_COMPILER_LOG_FORMATTER_IPP_020105GER // Boost.Test -#include - #include #include -#include - #include - #include #include #include - +#include +#include // Boost #include @@ -62,8 +58,6 @@ test_phase_identifier() void compiler_log_formatter::log_start( std::ostream& output, counter_t test_cases_amount ) { - m_color_output = runtime_config::get( runtime_config::COLOR_OUTPUT ); - if( test_cases_amount > 0 ) output << "Running " << test_cases_amount << " test " << (test_cases_amount > 1 ? "cases" : "case") << "...\n"; @@ -95,7 +89,7 @@ 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( m_color_output, output, term_attr::BRIGHT, term_color::BLUE ); + BOOST_TEST_SCOPE_SETCOLOR( output, term_attr::BRIGHT, term_color::BLUE ); print_prefix( output, tu.p_file_name, tu.p_line_num ); @@ -107,7 +101,7 @@ 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( m_color_output, output, term_attr::BRIGHT, term_color::BLUE ); + BOOST_TEST_SCOPE_SETCOLOR( output, term_attr::BRIGHT, term_color::BLUE ); print_prefix( output, tu.p_file_name, tu.p_line_num ); @@ -129,7 +123,7 @@ 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, const_string reason ) { - BOOST_TEST_SCOPE_SETCOLOR( m_color_output, output, term_attr::BRIGHT, term_color::YELLOW ); + BOOST_TEST_SCOPE_SETCOLOR( output, term_attr::BRIGHT, term_color::YELLOW ); print_prefix( output, tu.p_file_name, tu.p_line_num ); @@ -146,7 +140,7 @@ compiler_log_formatter::log_exception_start( std::ostream& output, log_checkpoin print_prefix( output, loc.m_file_name, loc.m_line_num ); { - BOOST_TEST_SCOPE_SETCOLOR( m_color_output, output, term_attr::BLINK, term_color::RED ); + BOOST_TEST_SCOPE_SETCOLOR( output, term_attr::BLINK, term_color::RED ); output << "fatal error: in \"" << (loc.m_function.is_empty() ? test_phase_identifier() : loc.m_function ) << "\": " << ex.what(); @@ -156,7 +150,7 @@ compiler_log_formatter::log_exception_start( std::ostream& output, log_checkpoin output << '\n'; print_prefix( output, checkpoint_data.m_file_name, checkpoint_data.m_line_num ); - BOOST_TEST_SCOPE_SETCOLOR( m_color_output, output, term_attr::BRIGHT, term_color::CYAN ); + BOOST_TEST_SCOPE_SETCOLOR( output, term_attr::BRIGHT, term_color::CYAN ); output << "last checkpoint"; if( !checkpoint_data.m_message.empty() ) @@ -180,29 +174,29 @@ 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( m_color_output ) + if( runtime_config::color_output() ) output << setcolor( term_attr::BRIGHT, term_color::GREEN ); output << "info: "; break; case BOOST_UTL_ET_MESSAGE: - if( m_color_output ) + 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 ); - if( m_color_output ) + 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 ); - if( m_color_output ) + 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 ); - if( m_color_output ) + if( runtime_config::color_output() ) output << setcolor( term_attr::BLINK, term_color::RED ); output << "fatal error: in \"" << test_phase_identifier() << "\": "; break; @@ -230,7 +224,7 @@ compiler_log_formatter::log_entry_value( std::ostream& output, lazy_ostream cons void compiler_log_formatter::log_entry_finish( std::ostream& output ) { - if( m_color_output ) + if( runtime_config::color_output() ) output << setcolor(); output << std::endl; @@ -242,7 +236,8 @@ compiler_log_formatter::log_entry_finish( std::ostream& output ) void compiler_log_formatter::print_prefix( std::ostream& output, const_string file_name, std::size_t line_num ) { - if( !file_name.empty() ) { + if( !file_name.empty() ) + { #ifdef __APPLE_CC__ // Xcode-compatible logging format, idea by Richard Dingwall at // . diff --git a/include/boost/test/impl/cpp_main.ipp b/include/boost/test/impl/cpp_main.ipp index 4fbdeb1c..5cab0f42 100644 --- a/include/boost/test/impl/cpp_main.ipp +++ b/include/boost/test/impl/cpp_main.ipp @@ -68,7 +68,7 @@ prg_exec_monitor_main( int (*cpp_main)( int argc, char* argv[] ), int argc, char { int result = 0; - BOOST_TEST_I_TRY { + BOOST_TEST_IMPL_TRY { boost::unit_test::const_string p( std::getenv( "BOOST_TEST_CATCH_SYSTEM_ERRORS" ) ); ::boost::execution_monitor ex_mon; @@ -83,11 +83,11 @@ prg_exec_monitor_main( int (*cpp_main)( int argc, char* argv[] ), int argc, char result = ::boost::exit_failure; } } - BOOST_TEST_I_CATCH( ::boost::execution_exception, exex ) { + BOOST_TEST_IMPL_CATCH( ::boost::execution_exception, exex ) { std::cout << "\n**** exception(" << exex.code() << "): " << exex.what() << std::endl; result = ::boost::exit_exception_failure; } - BOOST_TEST_I_CATCH( ::boost::system_error, 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**** error(" << ex.p_errno << "): " << std::strerror( ex.p_errno ) << std::endl; diff --git a/include/boost/test/impl/execution_monitor.ipp b/include/boost/test/impl/execution_monitor.ipp index a02ee04e..3a9e7794 100644 --- a/include/boost/test/impl/execution_monitor.ipp +++ b/include/boost/test/impl/execution_monitor.ipp @@ -243,9 +243,9 @@ report_error( execution_exception::error_code ec, boost::exception const* be, ch va_end( *args ); - BOOST_TEST_I_THROW(execution_exception( ec, buf, execution_exception::location( extract( be ), - (size_t)extract( be ), - extract( be ) ) )); + BOOST_TEST_IMPL_THROW(execution_exception( ec, buf, execution_exception::location( extract( be ), + (size_t)extract( be ), + extract( be ) ) )); } //____________________________________________________________________________// @@ -869,7 +869,7 @@ execution_monitor::catch_signals( boost::function const& F ) if( !sigsetjmp( signal_handler::jump_buffer(), 1 ) ) return detail::do_invoke( m_custom_translators , F ); else - BOOST_TEST_I_THROW( local_signal_handler.sys_sig() ); + BOOST_TEST_IMPL_THROW( local_signal_handler.sys_sig() ); } //____________________________________________________________________________// @@ -1200,7 +1200,7 @@ execution_monitor::execute( boost::function const& F ) if( debug::under_debugger() ) p_catch_system_errors.value = false; - BOOST_TEST_I_TRY { + BOOST_TEST_IMPL_TRY { detail::fpe_except_guard G( p_detect_fp_exceptions ); unit_test::ut_detail::ignore_unused_variable_warning( G ); @@ -1273,7 +1273,7 @@ execution_monitor::execute( boost::function const& F ) // system errors catch( system_error const& ex ) { detail::report_error( execution_exception::cpp_exception_error, - "system_error produced by: %s: %s", ex.p_failed_exp, std::strerror( ex.p_errno ) ); } + "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(); } diff --git a/include/boost/test/impl/framework.ipp b/include/boost/test/impl/framework.ipp index acaf78e7..a69d95cd 100644 --- a/include/boost/test/impl/framework.ipp +++ b/include/boost/test/impl/framework.ipp @@ -170,7 +170,8 @@ static void invoke_init_func( init_unit_test_func init_func ) { #ifdef BOOST_TEST_ALTERNATIVE_INIT_API - BOOST_TEST_I_ASSRT( (*init_func)(), std::runtime_error( "test module initialization failed" ) ); + 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 ); @@ -389,9 +390,7 @@ parse_filters( test_unit_id master_tu_id, test_unit_id_list& tu_to_enable, test_ // 10. collect tu to enable and disable based on filters bool had_selector_filter = false; - auto const& filters = runtime_config::get>( runtime_config::RUN_FILTERS ); - - BOOST_TEST_FOREACH( const_string, filter, filters ) { + 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; @@ -434,8 +433,6 @@ public: , m_next_test_suite_id( MIN_TEST_SUITE_ID ) , m_test_in_progress( false ) , m_context_idx( 0 ) - , m_log_sink( std::cout ) - , m_report_sink( std::cerr ) { } @@ -534,7 +531,7 @@ public: test_unit_id_list tu_to_disable; // 10. If there are any filters supplied, figure out lists of test units to enable/disable - bool had_selector_filter = !runtime_config::get>( runtime_config::RUN_FILTERS ).empty() && + 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 @@ -630,7 +627,7 @@ public: if( tu.p_type == TUT_SUITE ) { test_suite const& ts = static_cast( tu ); - if( runtime_config::get( runtime_config::RANDOM_SEED ) == 0 ) { + if( runtime_config::random_seed() == 0 ) { typedef std::pair value_type; BOOST_TEST_FOREACH( value_type, chld, ts.m_ranked_children ) { @@ -771,9 +768,6 @@ public: int m_context_idx; boost::execution_monitor m_aux_em; - - runtime_config::stream_holder m_log_sink; - runtime_config::stream_holder m_report_sink; }; //____________________________________________________________________________// @@ -808,48 +802,41 @@ setup_for_execution( test_unit const& tu ) void init( init_unit_test_func init_func, int argc, char* argv[] ) { - using namespace impl; - // 10. Set up runtime parameters runtime_config::init( argc, argv ); - // 20. Set the desired log level, format and sink - unit_test_log.set_threshold_level( runtime_config::get( runtime_config::LOG_LEVEL ) ); - unit_test_log.set_format( runtime_config::get( runtime_config::LOG_FORMAT ) ); - s_frk_state().m_log_sink.setup( runtime_config::LOG_SINK ); - unit_test_log.set_stream( s_frk_state().m_log_sink.ref() ); + // 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() ); - // 30. Set the desired report level, format and sink - results_reporter::set_level( runtime_config::get( runtime_config::REPORT_LEVEL ) ); - results_reporter::set_format( runtime_config::get( runtime_config::REPORT_FORMAT ) ); - s_frk_state().m_report_sink.setup( runtime_config::REPORT_SINK ); - results_reporter::set_stream( s_frk_state().m_report_sink.ref() ); + // 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::get( runtime_config::SHOW_PROGRESS ) ) { - progress_monitor.set_stream( s_frk_state().m_log_sink.ref() ); + if( runtime_config::show_progress() ) register_observer( progress_monitor ); - } // 50. Set up memory leak detection - unsigned long detect_mem_leak = runtime_config::get( runtime_config::DETECT_MEM_LEAKS ); - if( detect_mem_leak > 0 ) { - debug::detect_memory_leaks( true, runtime_config::get( runtime_config::REPORT_MEM_LEAKS ) ); - debug::break_memory_alloc( (long)detect_mem_leak ); + if( runtime_config::detect_memory_leaks() > 0 ) { + debug::detect_memory_leaks( true, runtime_config::memory_leaks_report_file() ); + debug::break_memory_alloc( runtime_config::detect_memory_leaks() ); } // 60. Initialize master unit test suite master_test_suite().argc = argc; master_test_suite().argv = argv; + using namespace impl; + // 70. Invoke test module initialization routine - BOOST_TEST_I_TRY { + BOOST_TEST_IMPL_TRY { s_frk_state().m_aux_em.vexecute( boost::bind( &impl::invoke_init_func, init_func ) ); } - BOOST_TEST_I_CATCH( execution_exception, ex ) { + BOOST_TEST_IMPL_CATCH( execution_exception, ex ) { BOOST_TEST_SETUP_ASSERT( false, ex.what() ); } } @@ -1170,7 +1157,8 @@ get( test_unit_id id, test_unit_type t ) { test_unit* res = impl::s_frk_state().m_test_units[id]; - BOOST_TEST_I_ASSRT( (res->p_type & t) != 0, internal_error( "Invalid test unit type" ) ); + if( (res->p_type & t) == 0 ) + BOOST_TEST_IMPL_THROW( internal_error( "Invalid test unit type" ) ); return *res; } @@ -1193,7 +1181,7 @@ run( test_unit_id id, bool continue_test ) test_case_counter tcc; traverse_test_tree( id, tcc ); - BOOST_TEST_SETUP_ASSERT( tcc.p_count != 0 , runtime_config::get>( runtime_config::RUN_FILTERS ).empty() + 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" ) ); @@ -1204,24 +1192,27 @@ run( test_unit_id id, bool continue_test ) if( call_start_finish ) { BOOST_TEST_FOREACH( test_observer*, to, impl::s_frk_state().m_observers ) { - BOOST_TEST_I_TRY { + BOOST_TEST_IMPL_TRY { impl::s_frk_state().m_aux_em.vexecute( boost::bind( &test_observer::test_start, to, tcc.p_count ) ); } - BOOST_TEST_I_CATCH( execution_exception, ex ) { + BOOST_TEST_IMPL_CATCH( execution_exception, ex ) { BOOST_TEST_SETUP_ASSERT( false, ex.what() ); } } } - unsigned seed = runtime_config::get( runtime_config::RANDOM_SEED ); - switch( seed ) { + switch( runtime_config::random_seed() ) { case 0: break; - case 1: - seed = static_cast( std::time( 0 ) ); - default: + case 1: { + unsigned seed = static_cast( std::time( 0 ) ); BOOST_TEST_MESSAGE( "Test cases order is shuffled using seed: " << seed ); std::srand( seed ); + break; + } + default: + BOOST_TEST_MESSAGE( "Test cases order is shuffled using seed: " << runtime_config::random_seed() ); + std::srand( runtime_config::random_seed() ); } impl::s_frk_state().execute_test_tree( id ); diff --git a/include/boost/test/impl/plain_report_formatter.ipp b/include/boost/test/impl/plain_report_formatter.ipp index e9b1f798..f9e7db77 100644 --- a/include/boost/test/impl/plain_report_formatter.ipp +++ b/include/boost/test/impl/plain_report_formatter.ipp @@ -19,13 +19,14 @@ #include #include #include -#include #include #include #include +#include + // STL #include #include @@ -83,7 +84,6 @@ void plain_report_formatter::results_report_start( std::ostream& ostr ) { m_indent = 0; - m_color_output = runtime_config::get( runtime_config::COLOR_OUTPUT ); ostr << '\n'; } @@ -160,13 +160,13 @@ plain_report_formatter::do_confirmation_report( test_unit const& tu, std::ostrea test_results const& tr = results_collector.results( tu.p_id ); if( tr.passed() ) { - BOOST_TEST_SCOPE_SETCOLOR( m_color_output, ostr, term_attr::BRIGHT, term_color::GREEN ); + BOOST_TEST_SCOPE_SETCOLOR( ostr, term_attr::BRIGHT, term_color::GREEN ); ostr << "*** No errors detected\n"; return; } - BOOST_TEST_SCOPE_SETCOLOR( m_color_output, ostr, term_attr::BRIGHT, term_color::RED ); + BOOST_TEST_SCOPE_SETCOLOR( ostr, term_attr::BRIGHT, term_color::RED ); if( tr.p_skipped ) { ostr << "*** The test " << tu.p_type_name << ' ' << quote() << tu.full_name() << " was skipped" diff --git a/include/boost/test/impl/progress_monitor.ipp b/include/boost/test/impl/progress_monitor.ipp index 195bc701..ebdd7e93 100644 --- a/include/boost/test/impl/progress_monitor.ipp +++ b/include/boost/test/impl/progress_monitor.ipp @@ -17,8 +17,8 @@ // Boost.Test #include -#include +#include #include #include @@ -102,21 +102,15 @@ namespace { struct progress_monitor_impl { // Constructor progress_monitor_impl() - : m_stream( &std::cout ) - , m_color_output( false ) - { - } + : m_stream( runtime_config::log_sink() ) + {} - std::ostream* m_stream; - scoped_ptr m_progress_display; - bool m_color_output; + std::ostream* m_stream; + scoped_ptr m_progress_display; }; progress_monitor_impl& s_pm_impl() { static progress_monitor_impl the_inst; return the_inst; } -#define PM_SCOPED_COLOR() \ - BOOST_TEST_SCOPE_SETCOLOR( s_pm_impl().m_color_output, *s_pm_impl().m_stream, term_attr::BRIGHT, term_color::MAGENTA ) - } // local namespace //____________________________________________________________________________// @@ -124,9 +118,7 @@ progress_monitor_impl& s_pm_impl() { static progress_monitor_impl the_inst; retu void progress_monitor_t::test_start( counter_t test_cases_amount ) { - s_pm_impl().m_color_output = runtime_config::get( runtime_config::COLOR_OUTPUT ); - - PM_SCOPED_COLOR(); + 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 ) ); } @@ -136,7 +128,7 @@ progress_monitor_t::test_start( counter_t test_cases_amount ) void progress_monitor_t::test_aborted() { - PM_SCOPED_COLOR(); + 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(); } @@ -146,7 +138,7 @@ progress_monitor_t::test_aborted() void progress_monitor_t::test_unit_finish( test_unit const& tu, unsigned long ) { - PM_SCOPED_COLOR(); + 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); @@ -157,7 +149,7 @@ progress_monitor_t::test_unit_finish( test_unit const& tu, unsigned long ) void progress_monitor_t::test_unit_skipped( test_unit const& tu, const_string /*reason*/ ) { - PM_SCOPED_COLOR(); + BOOST_TEST_SCOPE_SETCOLOR( *s_pm_impl().m_stream, term_attr::BRIGHT, term_color::MAGENTA ); test_case_counter tcc; traverse_test_tree( tu, tcc ); @@ -175,8 +167,6 @@ progress_monitor_t::set_stream( std::ostream& ostr ) //____________________________________________________________________________// -#undef PM_SCOPED_COLOR - } // namespace unit_test } // namespace boost diff --git a/include/boost/test/impl/results_reporter.ipp b/include/boost/test/impl/results_reporter.ipp index fdfe4b45..885295c9 100644 --- a/include/boost/test/impl/results_reporter.ipp +++ b/include/boost/test/impl/results_reporter.ipp @@ -19,7 +19,6 @@ #include #include #include - #include #include @@ -27,6 +26,8 @@ #include #include +#include + // Boost #include #include @@ -52,8 +53,8 @@ namespace { struct results_reporter_impl : test_tree_visitor { // Constructor results_reporter_impl() - : m_stream( &std::cerr ) - , m_stream_state_saver( new io_saver_type( std::cerr ) ) + : m_output( runtime_config::report_sink() ) + , m_stream_state_saver( new io_saver_type( *m_output ) ) , m_report_level( CONFIRMATION_REPORT ) , m_formatter( new output::plain_report_formatter ) {} @@ -61,28 +62,28 @@ struct results_reporter_impl : test_tree_visitor { // test tree visitor interface implementation void visit( test_case const& tc ) { - m_formatter->test_unit_report_start( tc, *m_stream ); - m_formatter->test_unit_report_finish( tc, *m_stream ); + m_formatter->test_unit_report_start( tc, *m_output ); + m_formatter->test_unit_report_finish( tc, *m_output ); } bool test_suite_start( test_suite const& ts ) { - m_formatter->test_unit_report_start( ts, *m_stream ); + m_formatter->test_unit_report_start( ts, *m_output ); if( m_report_level == DETAILED_REPORT && !results_collector.results( ts.p_id ).p_skipped ) return true; - m_formatter->test_unit_report_finish( ts, *m_stream ); + m_formatter->test_unit_report_finish( ts, *m_output ); return false; } void test_suite_finish( test_suite const& ts ) { - m_formatter->test_unit_report_finish( ts, *m_stream ); + m_formatter->test_unit_report_finish( ts, *m_output ); } typedef scoped_ptr saver_ptr; // Data members - std::ostream* m_stream; + std::ostream* m_output; saver_ptr m_stream_state_saver; report_level m_report_level; scoped_ptr m_formatter; @@ -108,7 +109,7 @@ set_level( report_level l ) void set_stream( std::ostream& ostr ) { - s_rr_impl().m_stream = &ostr; + s_rr_impl().m_output = &ostr; s_rr_impl().m_stream_state_saver.reset( new io_saver_type( ostr ) ); } @@ -117,7 +118,7 @@ set_stream( std::ostream& ostr ) std::ostream& get_stream() { - return *s_rr_impl().m_stream; + return *s_rr_impl().m_output; } //____________________________________________________________________________// @@ -168,11 +169,11 @@ make_report( report_level l, test_unit_id id ) report_level bkup = s_rr_impl().m_report_level; s_rr_impl().m_report_level = l; - s_rr_impl().m_formatter->results_report_start( *s_rr_impl().m_stream ); + s_rr_impl().m_formatter->results_report_start( *s_rr_impl().m_output ); switch( l ) { case CONFIRMATION_REPORT: - s_rr_impl().m_formatter->do_confirmation_report( framework::get( id ), *s_rr_impl().m_stream ); + s_rr_impl().m_formatter->do_confirmation_report( framework::get( id ), *s_rr_impl().m_output ); break; case SHORT_REPORT: case DETAILED_REPORT: @@ -182,7 +183,7 @@ make_report( report_level l, test_unit_id id ) break; } - s_rr_impl().m_formatter->results_report_finish( *s_rr_impl().m_stream ); + s_rr_impl().m_formatter->results_report_finish( *s_rr_impl().m_output ); s_rr_impl().m_report_level = bkup; } diff --git a/include/boost/test/impl/test_tools.ipp b/include/boost/test/impl/test_tools.ipp index 827f96c3..03fea916 100644 --- a/include/boost/test/impl/test_tools.ipp +++ b/include/boost/test/impl/test_tools.ipp @@ -294,8 +294,9 @@ report_assertion( assertion_result const& ar, { using namespace unit_test; - BOOST_TEST_I_ASSRT( framework::current_test_case_id() != INV_TEST_UNIT_ID, - std::runtime_error( "Can't use testing tools outside of test case implementation." ) ); + if( framework::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; @@ -356,7 +357,7 @@ report_assertion( assertion_result const& ar, framework::test_unit_aborted( framework::current_test_case() ); - BOOST_TEST_I_THROW( execution_aborted() ); + BOOST_TEST_IMPL_THROW( execution_aborted() ); } return true; diff --git a/include/boost/test/impl/test_tree.ipp b/include/boost/test/impl/test_tree.ipp index 5d2d443b..712cb9ee 100644 --- a/include/boost/test/impl/test_tree.ipp +++ b/include/boost/test/impl/test_tree.ipp @@ -39,6 +39,10 @@ #include +#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 { diff --git a/include/boost/test/impl/unit_test_log.ipp b/include/boost/test/impl/unit_test_log.ipp index 811c0e38..f202f502 100644 --- a/include/boost/test/impl/unit_test_log.ipp +++ b/include/boost/test/impl/unit_test_log.ipp @@ -20,6 +20,7 @@ #include #include #include + #include #include @@ -84,8 +85,8 @@ namespace { struct unit_test_log_impl { // Constructor unit_test_log_impl() - : m_stream( &std::cout ) - , m_stream_state_saver( new io_saver_type( std::cout ) ) + : m_stream( runtime_config::log_sink() ) + , m_stream_state_saver( new io_saver_type( *m_stream ) ) , m_threshold_level( log_all_errors ) , m_log_formatter( new output::compiler_log_formatter ) { @@ -109,14 +110,11 @@ struct unit_test_log_impl { log_checkpoint_data m_checkpoint_data; // helper functions - std::ostream& stream() - { - return *m_stream; - } + std::ostream& stream() { return *m_stream; } void set_checkpoint( const_string file, std::size_t line_num, const_string msg ) { assign_op( m_checkpoint_data.m_message, msg, 0 ); - m_checkpoint_data.m_file_name = file; + m_checkpoint_data.m_file_name = file; m_checkpoint_data.m_line_num = line_num; } }; @@ -135,7 +133,7 @@ unit_test_log_t::test_start( counter_t test_cases_amount ) s_log_impl().m_log_formatter->log_start( s_log_impl().stream(), test_cases_amount ); - if( runtime_config::get( runtime_config::BUILD_INFO ) ) + if( runtime_config::show_build_info() ) s_log_impl().m_log_formatter->log_build_info( s_log_impl().stream() ); s_log_impl().m_entry_in_progress = false; diff --git a/include/boost/test/impl/unit_test_main.ipp b/include/boost/test/impl/unit_test_main.ipp index 48958e22..327e14de 100644 --- a/include/boost/test/impl/unit_test_main.ipp +++ b/include/boost/test/impl/unit_test_main.ipp @@ -185,10 +185,10 @@ unit_test_main( init_unit_test_func init_func, int argc, char* argv[] ) { int result_code = 0; - BOOST_TEST_I_TRY { + BOOST_TEST_IMPL_TRY { framework::init( init_func, argc, argv ); - if( runtime_config::get( runtime_config::WAIT_FOR_DEBUGGER ) ) { + if( runtime_config::wait_for_debugger() ) { results_reporter::get_stream() << "Press any key to continue..." << std::endl; std::getchar(); @@ -197,9 +197,8 @@ unit_test_main( init_unit_test_func init_func, int argc, char* argv[] ) framework::finalize_setup_phase(); - output_format list_cont = runtime_config::get( runtime_config::LIST_CONTENT ); - if( list_cont != unit_test::OF_INVALID ) { - if( list_cont == unit_test::OF_DOT ) { + 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 ); @@ -213,7 +212,7 @@ unit_test_main( init_unit_test_func init_func, int argc, char* argv[] ) return boost::exit_success; } - if( runtime_config::get( runtime_config::LIST_LABELS ) ) { + if( runtime_config::list_labels() ) { ut_detail::labels_collector collector; traverse_test_tree( framework::master_test_suite().p_id, collector, true ); @@ -230,24 +229,24 @@ unit_test_main( init_unit_test_func init_func, int argc, char* argv[] ) results_reporter::make_report(); - result_code = !runtime_config::get( runtime_config::RESULT_CODE ) + result_code = runtime_config::no_result_code() ? boost::exit_success : results_collector.results( framework::master_test_suite().p_id ).result_code(); } - BOOST_TEST_I_CATCH0( framework::nothing_to_test ) { + BOOST_TEST_IMPL_CATCH0( framework::nothing_to_test ) { result_code = boost::exit_success; } - BOOST_TEST_I_CATCH( framework::internal_error, ex ) { + BOOST_TEST_IMPL_CATCH( framework::internal_error, ex ) { results_reporter::get_stream() << "Boost.Test framework internal error: " << ex.what() << std::endl; result_code = boost::exit_exception_failure; } - BOOST_TEST_I_CATCH( framework::setup_error, ex ) { + BOOST_TEST_IMPL_CATCH( framework::setup_error, ex ) { results_reporter::get_stream() << "Test setup error: " << ex.what() << std::endl; result_code = boost::exit_exception_failure; } - BOOST_TEST_I_CATCHALL() { + BOOST_TEST_IMPL_CATCHALL() { results_reporter::get_stream() << "Boost.Test framework internal error: unknown reason" << std::endl; result_code = boost::exit_exception_failure; diff --git a/include/boost/test/impl/unit_test_monitor.ipp b/include/boost/test/impl/unit_test_monitor.ipp index 77bfb7cb..8c931f20 100644 --- a/include/boost/test/impl/unit_test_monitor.ipp +++ b/include/boost/test/impl/unit_test_monitor.ipp @@ -36,16 +36,16 @@ namespace unit_test { unit_test_monitor_t::error_level unit_test_monitor_t::execute_and_translate( boost::function const& func, unsigned timeout ) { - BOOST_TEST_I_TRY { - p_catch_system_errors.value = runtime_config::get( runtime_config::CATCH_SYS_ERRORS ); + BOOST_TEST_IMPL_TRY { + p_catch_system_errors.value = runtime_config::catch_sys_errors(); p_timeout.value = timeout; - p_auto_start_dbg.value = runtime_config::get( runtime_config::AUTO_START_DBG ); - p_use_alt_stack.value = runtime_config::get( runtime_config::USE_ALT_STACK ); - p_detect_fp_exceptions.value = runtime_config::get( runtime_config::DETECT_FP_EXCEPT ); + 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(); vexecute( func ); } - BOOST_TEST_I_CATCH( execution_exception, ex ) { + BOOST_TEST_IMPL_CATCH( execution_exception, ex ) { framework::exception_caught( ex ); framework::test_unit_aborted( framework::current_test_case() ); diff --git a/include/boost/test/impl/unit_test_parameters.ipp b/include/boost/test/impl/unit_test_parameters.ipp index f3d5a2e1..2ffa495e 100644 --- a/include/boost/test/impl/unit_test_parameters.ipp +++ b/include/boost/test/impl/unit_test_parameters.ipp @@ -20,32 +20,36 @@ // Boost.Test #include - #include #include #include - +#include #include #include -#include #include // Boost.Runtime.Param -#include -#include -#include +#include #include -#include + +namespace rt = boost::runtime; +namespace cla = rt::cla; + +#ifndef UNDER_CE +#include + +namespace env = rt::env; +#endif // Boost #include #include #include #include -#include // STL +#include #include #include #include @@ -61,7 +65,85 @@ namespace std { using ::getenv; using ::strncmp; using ::strcmp; } namespace boost { namespace unit_test { -namespace rt = boost::runtime; +// ************************************************************************** // +// ************** input operations for unit_test's enums ************** // +// ************************************************************************** // + +std::istream& +operator>>( std::istream& in, unit_test::log_level& ll ) +{ + static fixed_mapping > log_level_name( + "all" , log_successful_tests, + "success" , log_successful_tests, + "test_suite" , log_test_units, + "unit_scope" , log_test_units, + "message" , log_messages, + "warning" , log_warnings, + "error" , log_all_errors, + "cpp_exception" , log_cpp_exception_errors, + "system_error" , log_system_errors, + "fatal_error" , log_fatal_errors, + "nothing" , log_nothing, + + invalid_log_level + ); + + std::string val; + in >> val; + + ll = log_level_name[val]; + BOOST_TEST_SETUP_ASSERT( ll != unit_test::invalid_log_level, "invalid log level " + val ); + + return in; +} + +//____________________________________________________________________________// + +std::istream& +operator>>( std::istream& in, unit_test::report_level& rl ) +{ + fixed_mapping > report_level_name ( + "confirm", CONFIRMATION_REPORT, + "short", SHORT_REPORT, + "detailed", DETAILED_REPORT, + "no", NO_REPORT, + + INV_REPORT_LEVEL + ); + + std::string val; + in >> val; + + rl = report_level_name[val]; + BOOST_TEST_SETUP_ASSERT( rl != INV_REPORT_LEVEL, "invalid report level " + val ); + + return in; +} + +//____________________________________________________________________________// + +std::istream& +operator>>( std::istream& in, unit_test::output_format& of ) +{ + fixed_mapping > output_format_name ( + "HRF", unit_test::OF_CLF, + "CLF", unit_test::OF_CLF, + "XML", unit_test::OF_XML, + "DOT", unit_test::OF_DOT, + + unit_test::OF_INVALID + ); + + std::string val; + in >> val; + + of = output_format_name[val]; + BOOST_TEST_SETUP_ASSERT( of != unit_test::OF_INVALID, "invalid output format " + val ); + + return in; +} + +//____________________________________________________________________________// // ************************************************************************** // // ************** runtime_config ************** // @@ -69,7 +151,9 @@ namespace rt = boost::runtime; namespace runtime_config { -// UTF parameters +namespace { + +// framework parameters and corresponding command-line arguments std::string AUTO_START_DBG = "auto_start_dbg"; std::string BREAK_EXEC_PATH = "break_exec_path"; std::string BUILD_INFO = "build_info"; @@ -86,475 +170,100 @@ std::string OUTPUT_FORMAT = "output_format"; std::string RANDOM_SEED = "random"; std::string REPORT_FORMAT = "report_format"; std::string REPORT_LEVEL = "report_level"; -std::string REPORT_MEM_LEAKS = "report_memory_leaks_to"; std::string REPORT_SINK = "report_sink"; std::string RESULT_CODE = "result_code"; -std::string RUN_FILTERS = "run_test"; +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"; -std::string HELP = "help"; -std::string USAGE = "usage"; +static const_string +parameter_2_env_var( const_string param_name ) +{ + typedef std::map 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"; + } + + mtype::const_iterator it = s_mapping.find( param_name ); + + return it == s_mapping.end() ? const_string() : it->second; +} //____________________________________________________________________________// -namespace { +// storage for the CLAs +cla::parser s_cla_parser; +std::string s_empty; -void -register_parameters( rt::parameters_store& store ) +output_format s_report_format; +output_format s_log_format; + +std::list s_test_to_run; + +//____________________________________________________________________________// + +template +T +retrieve_parameter( const_string parameter_name, cla::parser const& s_cla_parser, T const& default_value = T(), T const& optional_value = T() ) { - rt::option auto_start_dbg( AUTO_START_DBG, ( - rt::description = "Automatically attaches debugger in case of system level failure (signal).", - rt::env_var = "BOOST_TEST_AUTO_START_DBG", + rt::const_argument_ptr arg = s_cla_parser[parameter_name]; + if( arg ) { + if( rtti::type_id() == rtti::type_id() || + !static_cast( arg->p_formal_parameter.get() ).p_optional_value ) + return s_cla_parser.get( parameter_name ); - rt::help = "Option " + AUTO_START_DBG + " 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 " - "different debugger. For more details on how to configure the debugger see the " - "Boost.Test debug API, specifically the function boost::debug::set_debugger." - )); + optional val = s_cla_parser.get >( parameter_name ); + if( val ) + return *val; + else + return optional_value; + } - auto_start_dbg.add_cla_id( "--", AUTO_START_DBG, "=" ); - auto_start_dbg.add_cla_id( "-", "d", " " ); - store.add( auto_start_dbg ); + boost::optional v; - /////////////////////////////////////////////// - - rt::parameter break_exec_path( BREAK_EXEC_PATH, ( - rt::description = "For the exception safety testing allows to break at specific execution path.", - rt::env_var = "BOOST_TEST_BREAK_EXEC_PATH", - rt::callback = [](rt::cstring) { - BOOST_TEST_SETUP_ASSERT( false, "parameter break_exec_path is disabled in this release" ); - } - )); - - break_exec_path.add_cla_id( "--", BREAK_EXEC_PATH, "=" ); - store.add( break_exec_path ); - - rt::option build_info( BUILD_INFO, ( - rt::description = "Displays library build information.", - rt::env_var = "BOOST_TEST_BUILD_INFO", - rt::help = "Option " + BUILD_INFO + " displays library build information, including: platform, " - "compiler, STL version and Boost version." - )); - - /////////////////////////////////////////////// - - build_info.add_cla_id( "--", BUILD_INFO, "=" ); - build_info.add_cla_id( "-", "i", " " ); - store.add( build_info ); - - - rt::option catch_sys_errors( CATCH_SYS_ERRORS, ( - rt::description = "Allows to switch between catching and ignoring system errors (signals).", - rt::env_var = "BOOST_TEST_CATCH_SYSTEM_ERRORS", - rt::default_value = -#ifdef BOOST_TEST_DEFAULTS_TO_CORE_DUMP - false, -#else - true, +#ifndef UNDER_CE + env::get( parameter_2_env_var(parameter_name), v ); #endif - rt::help = "If option " + 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 - "no." -#else - "true." -#endif - )); - catch_sys_errors.add_cla_id( "--", CATCH_SYS_ERRORS, "=", true ); - catch_sys_errors.add_cla_id( "-", "s", " " ); - store.add( catch_sys_errors ); - - /////////////////////////////////////////////// - - rt::option color_output( 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." - )); - - color_output.add_cla_id( "--", COLOR_OUTPUT, "=", true ); - color_output.add_cla_id( "-", "x", " " ); - store.add( color_output ); - - /////////////////////////////////////////////// - - rt::option detect_fp_except( DETECT_FP_EXCEPT, ( - rt::description = "Enables/disables floating point exceptions traps.", - rt::env_var = "BOOST_TEST_DETECT_FP_EXCEPTIONS", - rt::help = "Option " + DETECT_FP_EXCEPT + " enables/disables hardware traps for the floating " - "point exceptions (if supported on your platfrom)." - )); - - detect_fp_except.add_cla_id( "--", DETECT_FP_EXCEPT, "=", true ); - store.add( detect_fp_except ); - - /////////////////////////////////////////////// - - rt::parameter detect_mem_leaks( DETECT_MEM_LEAKS, ( - rt::description = "Turns on/off memory leaks detection (optionally breaking on specified alloc order number).", - rt::env_var = "BOOST_TEST_DETECT_MEMORY_LEAK", - rt::default_value = 1L, - rt::optional_value = 1L, - rt::value_hint = "", - rt::help = "Parameter " + DETECT_MEM_LEAKS + " 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 " - "framework to setup runtime breakpoint at Nth heap allocation. If value is " - "omitted the default value is assumed." - )); - - detect_mem_leaks.add_cla_id( "--", DETECT_MEM_LEAKS, "=" ); - store.add( detect_mem_leaks ); - - /////////////////////////////////////////////// - - rt::enum_parameter list_content( LIST_CONTENT, ( - rt::description = "Lists the content of test tree - names of all test suites and test cases.", - rt::env_var = "BOOST_TEST_LIST_CONTENT", - rt::default_value = OF_INVALID, - rt::optional_value = OF_CLF, - rt::enum_values::value = { - { "HRF", OF_CLF }, - { "DOT", OF_DOT } - }, - rt::help = "Parameter " + 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 " - "framework supports two formats: human readable format (HRF) and dot graph " - "format (DOT). If value is omitted HRF value is assumed." - )); - list_content.add_cla_id( "--", LIST_CONTENT, "=" ); - store.add( list_content ); - - /////////////////////////////////////////////// - - rt::option list_labels( LIST_LABELS, ( - rt::description = "Lists all available labels.", - rt::env_var = "BOOST_TEST_LIST_LABELS", - rt::help = "Option " + LIST_LABELS + " instructs the framework to list all the the labels " - "defined in the test module instead of executing the test cases." - )); - - list_labels.add_cla_id( "--", LIST_LABELS, "=" ); - store.add( list_labels ); - - /////////////////////////////////////////////// - - rt::enum_parameter log_format( LOG_FORMAT, ( - rt::description = "Specifies log format.", - rt::env_var = "BOOST_TEST_LOG_FORMAT", - rt::default_value = OF_CLF, - rt::enum_values::value = { - { "HRF", OF_CLF }, - { "CLF", OF_CLF }, - { "XML", OF_XML } - }, - rt::help = "Parameter " + LOG_FORMAT + " allows to 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 " - "format is similar to compiler error format. Alternatively you can specify XML " - "as log format. This format is easier to process by testing automation tools." - )); - - log_format.add_cla_id( "--", LOG_FORMAT, "=" ); - log_format.add_cla_id( "-", "f", " " ); - store.add( log_format ); - - /////////////////////////////////////////////// - - rt::enum_parameter log_level( LOG_LEVEL, ( - rt::description = "Specifies log level.", - rt::env_var = "BOOST_TEST_LOG_LEVEL", - rt::default_value = log_all_errors, - rt::enum_values::value = { - { "all" , log_successful_tests }, - { "success" , log_successful_tests }, - { "test_suite" , log_test_units }, - { "unit_scope" , log_test_units }, - { "message" , log_messages }, - { "warning" , log_warnings }, - { "error" , log_all_errors }, - { "cpp_exception" , log_cpp_exception_errors }, - { "system_error" , log_system_errors }, - { "fatal_error" , log_fatal_errors }, - { "nothing" , log_nothing } - }, - rt::help = "Parameter " + LOG_LEVEL + " allows to set the framework's log level. " - "Log level defines the verbosity of testing log produced by a testing " - "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 " - "is reported to a testing log stream." - )); - - log_level.add_cla_id( "--", LOG_LEVEL, "=" ); - log_level.add_cla_id( "-", "l", " " ); - store.add( log_level ); - - /////////////////////////////////////////////// - - rt::parameter log_sink( LOG_SINK, ( - rt::description = "Specifies log sink: stdout(default), stderr or file name.", - rt::env_var = "BOOST_TEST_LOG_SINK", - rt::value_hint = "", - rt::help = "Parameter " + LOG_SINK + " allows to set the log sink - location " - "where we report the log to, thus it allows to easily redirect the " - "test logs to file or standard streams. By default testing log is " - "directed to standard output." - )); - - log_sink.add_cla_id( "--", LOG_SINK, "=" ); - log_sink.add_cla_id( "-", "k", " " ); - store.add( log_sink ); - - /////////////////////////////////////////////// - - rt::enum_parameter output_format( OUTPUT_FORMAT, ( - rt::description = "Specifies output format (both log and report).", - rt::env_var = "BOOST_TEST_OUTPUT_FORMAT", - rt::enum_values::value = { - { "HRF", OF_CLF }, - { "CLF", OF_CLF }, - { "XML", OF_XML } - }, - rt::help = "Parameter " + OUTPUT_FORMAT + " combines an effect of " + REPORT_FORMAT + - " and " + 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 " - "have a default value. The only acceptable values are string names of " - "output formats: HRF - human readable format and XML - XML formats for " - "automation tools processing." - )); - - output_format.add_cla_id( "--", OUTPUT_FORMAT, "=" ); - output_format.add_cla_id( "-", "o", " " ); - store.add( output_format ); - - /////////////////////////////////////////////// - - rt::parameter random_seed( RANDOM_SEED, ( - rt::description = "Allows to switch between sequential and random order of test units execution." - " Optionally allows to specify concrete seed for random number generator.", - rt::env_var = "BOOST_TEST_RANDOM", - rt::default_value = 0U, - rt::optional_value = 1U, - rt::value_hint = "", - rt::help = "Parameter " + 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 " - "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." - )); - - random_seed.add_cla_id( "--", RANDOM_SEED, "=" ); - store.add( random_seed ); - - /////////////////////////////////////////////// - - rt::enum_parameter report_format( REPORT_FORMAT, ( - rt::description = "Specifies report format.", - rt::env_var = "BOOST_TEST_REPORT_FORMAT", - rt::default_value = OF_CLF, - rt::enum_values::value = { - { "HRF", OF_CLF }, - { "CLF", OF_CLF }, - { "XML", OF_XML } - }, - rt::help = "Parameter " + REPORT_FORMAT + " allows to 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 " - "specify XML as report format. This format is easier to process by testing " - "automation tools." - )); - - report_format.add_cla_id( "--", REPORT_FORMAT, "=" ); - report_format.add_cla_id( "-", "m", " " ); - store.add( report_format ); - - /////////////////////////////////////////////// - - rt::enum_parameter report_level( REPORT_LEVEL, ( - rt::description = "Specifies report level.", - rt::env_var = "BOOST_TEST_REPORT_LEVEL", - rt::default_value = CONFIRMATION_REPORT, - rt::enum_values::value = { - { "confirm", CONFIRMATION_REPORT }, - { "short", SHORT_REPORT }, - { "detailed", DETAILED_REPORT }, - { "no", NO_REPORT } - }, - rt::help = "Parameter " + 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." - )); - - report_level.add_cla_id( "--", REPORT_LEVEL, "=" ); - report_level.add_cla_id( "-", "r", " " ); - store.add( report_level ); - - /////////////////////////////////////////////// - - rt::parameter report_mem_leaks( REPORT_MEM_LEAKS, ( - rt::description = "File where to report memory leaks to.", - rt::env_var = "BOOST_TEST_REPORT_MEMORY_LEAKS_TO", - rt::default_value = std::string(), - rt::value_hint = "", - rt::help = "Parameter " + REPORT_MEM_LEAKS + " allows to specify a file where to report " - "memory leaks to. The parameter does not have default value. If it is not specified, " - "memory leaks (if any) are reported to the standard error stream." - )); - - report_mem_leaks.add_cla_id( "--", REPORT_MEM_LEAKS, "=" ); - store.add( report_mem_leaks ); - - /////////////////////////////////////////////// - - rt::parameter report_sink( REPORT_SINK, ( - rt::description = "Specifies report sink: stderr(default), stdout or file name.", - rt::env_var = "BOOST_TEST_REPORT_SINK", - rt::value_hint = "", - rt::help = "Parameter " + 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 " - "standard error stream." - )); - - report_sink.add_cla_id( "--", REPORT_SINK, "=" ); - report_sink.add_cla_id( "-", "e", " " ); - store.add( report_sink ); - - /////////////////////////////////////////////// - - rt::option result_code( RESULT_CODE, ( - rt::description = "Disables test modules's result code generation.", - rt::env_var = "BOOST_TEST_RESULT_CODE", - rt::default_value = true, - rt::help = "The 'no' argument value for the parameter " + RESULT_CODE + " instructs the " - "framework to always return zero result code. This can be used for test programs " - "executed within IDE. By default this parameter has value 'yes'." - )); - - result_code.add_cla_id( "--", RESULT_CODE, "=", true ); - result_code.add_cla_id( "-", "c", " " ); - store.add( result_code ); - - /////////////////////////////////////////////// - - rt::parameter tests_to_run( RUN_FILTERS, ( - rt::description = "Filters, which test units to include or exclude from test module execution.", - rt::env_var = "BOOST_TEST_RUN_FILTERS", - rt::value_hint = "", - rt::help = "Parameter " + RUN_FILTERS + " allows to filter which test units to execute during " - "testing. 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 " - "enabling/disabling test units at compile time. These settings identify the default " - "set of test units to run. Parameter " + RUN_FILTERS + " is used to change this default. " - "This parameter is repeatable, so you can specify more than one filter if necessary." - )); - - tests_to_run.add_cla_id( "--", RUN_FILTERS, "=" ); - tests_to_run.add_cla_id( "-", "t", " " ); - store.add( tests_to_run ); - - /////////////////////////////////////////////// - - rt::option save_test_pattern( SAVE_TEST_PATTERN, ( - rt::description = "Allows to switch between saving or matching test pattern file.", - rt::env_var = "BOOST_TEST_SAVE_PATTERN", - rt::help = "Parameter " + SAVE_TEST_PATTERN + " facilitates switching mode of operation for " - "testing output streams.\n\nThis parameter serves no particular purpose within the " - "framework itself. It can be used by test modules relying on output_test_stream to " - "implement testing logic. Default mode is 'match' (false)." - )); - - save_test_pattern.add_cla_id( "--", SAVE_TEST_PATTERN, "=" ); - store.add( save_test_pattern ); - - /////////////////////////////////////////////// - - rt::option show_progress( SHOW_PROGRESS, ( - rt::description = "Turns on progress display.", - rt::env_var = "BOOST_TEST_SHOW_PROGRESS", - rt::help = "Parameter " + SHOW_PROGRESS + " instructs the framework to display test progress " - "information. By default the test progress is not shown." - )); - - show_progress.add_cla_id( "--", SHOW_PROGRESS, "=" ); - show_progress.add_cla_id( "-", "p", " " ); - store.add( show_progress ); - - /////////////////////////////////////////////// - - rt::option use_alt_stack( USE_ALT_STACK, ( - 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 " + 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." - )); - - use_alt_stack.add_cla_id( "--", USE_ALT_STACK, "=", true ); - store.add( use_alt_stack ); - - /////////////////////////////////////////////// - - rt::option wait_for_debugger( 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 " + 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." - )); - - wait_for_debugger.add_cla_id( "--", WAIT_FOR_DEBUGGER, "=" ); - wait_for_debugger.add_cla_id( "-", "w", " " ); - store.add( wait_for_debugger ); - - /////////////////////////////////////////////// - - rt::parameter help( HELP, ( - rt::description = "Help for framework parameters.", - rt::optional_value = std::string(), - rt::value_hint = "", - rt::help = "Parameter " + 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 " - "or ambiguous error is reported. If argument value is absent, a summary of all " - "framework's parameter is displayed." - )); - help.add_cla_id( "--", HELP, "=" ); - store.add( help ); - - /////////////////////////////////////////////// - - rt::option usage( USAGE, ( - rt::description = "Short message explaining usage of Boost.Test parameters." - )); - usage.add_cla_id( "-", "?", " " ); - store.add( usage ); + if( v ) + return *v; + else + return default_value; } -static rt::arguments_store s_arguments_store; -static rt::parameters_store s_parameters_store; +//____________________________________________________________________________// + +void +disable_use( cla::parameter const&, std::string const& ) +{ + BOOST_TEST_SETUP_ASSERT( false, "parameter break_exec_path is disabled in this release" ); +} //____________________________________________________________________________// @@ -563,86 +272,157 @@ static rt::parameters_store s_parameters_store; void init( int& argc, char** argv ) { - shared_ptr parser; + using namespace cla; - BOOST_TEST_I_TRY { - // Initialize parameters list - if( s_parameters_store.is_empty() ) - register_parameters( s_parameters_store ); + 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( 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( 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( BUILD_INFO + "|i" ) + - (cla::prefix = "--|-",cla::separator = "=| ",cla::guess_name,cla::optional, + cla::description = "Shows library build information" ) + << cla::dual_name_parameter( 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( 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( 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( 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( LOG_FORMAT + "|f" ) + - (cla::prefix = "--|-",cla::separator = "=| ",cla::guess_name,cla::optional, + cla::description = "Specifies log format") + << cla::dual_name_parameter( LOG_LEVEL + "|l" ) + - (cla::prefix = "--|-",cla::separator = "=| ",cla::guess_name,cla::optional, + cla::description = "Specifies log level") + << cla::dual_name_parameter( 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( 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( 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( REPORT_FORMAT + "|m" ) + - (cla::prefix = "--|-",cla::separator = "=| ",cla::guess_name,cla::optional, + cla::description = "Specifies report format") + << cla::dual_name_parameter(REPORT_LEVEL + "|r") + - (cla::prefix = "--|-",cla::separator = "=| ",cla::guess_name,cla::optional, + cla::description = "Specifies report level") + << cla::dual_name_parameter( 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( 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( 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( 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( SHOW_PROGRESS + "|p" ) + - (cla::prefix = "--|-",cla::separator = "=| ",cla::guess_name,cla::optional, + cla::description = "Turns on progress display") + << cla::dual_name_parameter( 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( LIST_LABELS ) + - (cla::prefix = "--",cla::separator = "= ",cla::guess_name,cla::optional, + cla::description = "Lists all available labels") + << cla::named_parameter( 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( 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") - // Clear up arguments store just in case (of multiple init invocations) - s_arguments_store.clear(); + << cla::dual_name_parameter( "help|?" ) + - (cla::prefix = "--|-",cla::separator = "=",cla::guess_name,cla::optional, + cla::description = "this help message") + ; - // Parse CLA they take precedence over environment - parser.reset( new rt::cla::parser( s_parameters_store, (rt::end_of_params = "--", rt::negation_prefix = "no_") ) ); - parser->parse( argc, argv, s_arguments_store ); + s_cla_parser.parse( argc, argv ); - // Try to fetch missing arguments from environment - rt::env::fetch_absent( s_parameters_store, s_arguments_store ); - - // Set arguments to default values if defined and perform all the validations - rt::finalize_arguments( s_parameters_store, s_arguments_store ); - - // Report help if requested - if( runtime_config::get( USAGE ) ) { - parser->usage( std::cerr ); - BOOST_TEST_I_THROW( framework::nothing_to_test() ); - } - else if( s_arguments_store.has( HELP ) ) { - parser->help( std::cerr, s_parameters_store, runtime_config::get( HELP ) ); - BOOST_TEST_I_THROW( framework::nothing_to_test() ); + if( s_cla_parser["help"] ) { + s_cla_parser.help( std::cout ); + BOOST_TEST_IMPL_THROW( framework::nothing_to_test() ); } - // A bit of business logic: output_format takes precedence over log/report formats - if( s_arguments_store.has( OUTPUT_FORMAT ) ) { - unit_test::output_format of = s_arguments_store.get( OUTPUT_FORMAT ); - s_arguments_store.set( REPORT_FORMAT, of ); - s_arguments_store.set( LOG_FORMAT, of ); - } + 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::OF_INVALID ); + + if( of != unit_test::OF_INVALID ) + s_report_format = s_log_format = of; + + s_test_to_run = retrieve_parameter >( TESTS_TO_RUN, s_cla_parser ); } - BOOST_TEST_I_CATCH( rt::init_error, ex ) { - BOOST_TEST_SETUP_ASSERT( false, ex.msg ); - } - BOOST_TEST_I_CATCH( rt::ambiguous_param, ex ) { - std::cerr << ex.msg << "\n Did you mean one of these?\n"; + BOOST_TEST_IMPL_CATCH( rt::logic_error, ex ) { + std::ostringstream err; - BOOST_TEST_FOREACH( rt::cstring, name, ex.m_amb_candidates ) - std::cerr << " " << name << "\n"; + err << "Fail to process runtime parameters: " << ex.msg() << std::endl; + s_cla_parser.usage( err ); - BOOST_TEST_I_THROW( framework::nothing_to_test() ); - } - BOOST_TEST_I_CATCH( rt::unrecognized_param, ex ) { - std::cerr << ex.msg << "\n"; - - if( !ex.m_typo_candidates.empty() ) { - std::cerr << " Did you mean one of these?\n"; - - BOOST_TEST_FOREACH( rt::cstring, name, ex.m_typo_candidates ) - std::cerr << " " << name << "\n"; - } - else if( parser ) { - std::cerr << "\n"; - parser->usage( std::cerr ); - } - - BOOST_TEST_I_THROW( framework::nothing_to_test() ); - } - BOOST_TEST_I_CATCH( rt::input_error, ex ) { - std::cerr << ex.msg << "\n\n"; - - if( parser ) - parser->usage( std::cerr, ex.param_name ); - - BOOST_TEST_I_THROW( framework::nothing_to_test() ); + BOOST_TEST_SETUP_ASSERT( false, err.str() ); } } //____________________________________________________________________________// -rt::arguments_store const& -argument_store() +unit_test::log_level +log_level() { - return s_arguments_store; + return retrieve_parameter( LOG_LEVEL, s_cla_parser, unit_test::log_all_errors ); +} + +//____________________________________________________________________________// + +bool +no_result_code() +{ + return !retrieve_parameter( RESULT_CODE, s_cla_parser, true ); +} + +//____________________________________________________________________________// + +unit_test::report_level +report_level() +{ + return retrieve_parameter( REPORT_LEVEL, s_cla_parser, unit_test::CONFIRMATION_REPORT ); +} + +//____________________________________________________________________________// + +std::list const& +test_to_run() +{ + return s_test_to_run; +} + +//____________________________________________________________________________// + +const_string +break_exec_path() +{ + static std::string s_break_exec_path = retrieve_parameter( BREAK_EXEC_PATH, s_cla_parser, s_empty ); + + return s_break_exec_path; } //____________________________________________________________________________// @@ -650,7 +430,203 @@ argument_store() bool save_pattern() { - return runtime_config::get( SAVE_TEST_PATTERN ); + return retrieve_parameter( SAVE_TEST_PATTERN, s_cla_parser, false ); +} + +//____________________________________________________________________________// + +bool +show_progress() +{ + return retrieve_parameter( SHOW_PROGRESS, s_cla_parser, false ); +} + +//____________________________________________________________________________// + +bool +show_build_info() +{ + return retrieve_parameter( BUILD_INFO, s_cla_parser, false ); +} + +//____________________________________________________________________________// + +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, +#ifdef BOOST_TEST_DEFAULTS_TO_CORE_DUMP + false +#else + true +#endif + ); +} + +//____________________________________________________________________________// + +bool +color_output() +{ + return retrieve_parameter( COLOR_OUTPUT, s_cla_parser, false ); +} + +//____________________________________________________________________________// + +bool +auto_start_dbg() +{ + // !! ?? set debugger as an option + return retrieve_parameter( AUTO_START_DBG, s_cla_parser, false ); +; +} + +//____________________________________________________________________________// + +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 ); +} + +//____________________________________________________________________________// + +bool +detect_fp_exceptions() +{ + return retrieve_parameter( DETECT_FP_EXCEPT, s_cla_parser, false ); +} + +//____________________________________________________________________________// + +output_format +report_format() +{ + return s_report_format; +} + +//____________________________________________________________________________// + +output_format +log_format() +{ + return s_log_format; +} + +//____________________________________________________________________________// + +std::ostream* +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; + + if( sink_name == "stdout" ) + return &std::cout; + + static std::ofstream report_file( sink_name.c_str() ); + return &report_file; +} + +//____________________________________________________________________________// + +std::ostream* +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; + + if( sink_name == "stderr" ) + return &std::cerr; + + static std::ofstream log_file( sink_name.c_str() ); + return &log_file; +} + +//____________________________________________________________________________// + +long +detect_memory_leaks() +{ + 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_val; + if( runtime::interpret_argument_value_impl::_( 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( 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( DETECT_MEM_LEAKS, s_cla_parser ); + + optional bool_val; + if( runtime::interpret_argument_value_impl::_( s_value, bool_val ) ) + s_value.clear(); + } + + return s_value; +} + +//____________________________________________________________________________// + +unsigned +random_seed() +{ + return retrieve_parameter( RANDOM_SEED, s_cla_parser, 0U, 1U ); } //____________________________________________________________________________// diff --git a/include/boost/test/impl/xml_log_formatter.ipp b/include/boost/test/impl/xml_log_formatter.ipp index 9363baa1..286cd600 100644 --- a/include/boost/test/impl/xml_log_formatter.ipp +++ b/include/boost/test/impl/xml_log_formatter.ipp @@ -82,7 +82,7 @@ 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(); - if( !tu.p_file_name.empty() ) + 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; @@ -106,7 +106,7 @@ void 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 + << " name" << attr_value() << tu.p_name.get() << " skipped" << attr_value() << "yes" << " reason" << attr_value() << reason << "/>"; diff --git a/include/boost/test/impl/xml_report_formatter.ipp b/include/boost/test/impl/xml_report_formatter.ipp index 4e2c5b6d..5606fdc0 100644 --- a/include/boost/test/impl/xml_report_formatter.ipp +++ b/include/boost/test/impl/xml_report_formatter.ipp @@ -65,7 +65,7 @@ xml_report_formatter::test_unit_report_start( test_unit const& tu, std::ostream& descr = "failed"; ostr << '<' << ( tu.p_type == TUT_CASE ? "TestCase" : "TestSuite" ) - << " name" << attr_value() << tu.p_name + << " 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 @@ -80,6 +80,7 @@ xml_report_formatter::test_unit_report_start( test_unit const& tu, std::ostream& << " test_cases_aborted" << attr_value() << tr.p_test_cases_aborted; } + ostr << '>'; } diff --git a/include/boost/test/output/compiler_log_formatter.hpp b/include/boost/test/output/compiler_log_formatter.hpp index b5b3074a..0b3e8811 100644 --- a/include/boost/test/output/compiler_log_formatter.hpp +++ b/include/boost/test/output/compiler_log_formatter.hpp @@ -33,8 +33,6 @@ namespace output { class BOOST_TEST_DECL compiler_log_formatter : public unit_test_log_formatter { public: - compiler_log_formatter() : m_color_output( false ) {} - // Formatter interface void log_start( std::ostream&, counter_t test_cases_amount ); void log_finish( std::ostream& ); @@ -58,9 +56,6 @@ public: protected: virtual void print_prefix( std::ostream&, const_string file, std::size_t line ); - - // Data members - bool m_color_output; }; } // namespace output diff --git a/include/boost/test/output/plain_report_formatter.hpp b/include/boost/test/output/plain_report_formatter.hpp index 3809de9a..ff8924f6 100644 --- a/include/boost/test/output/plain_report_formatter.hpp +++ b/include/boost/test/output/plain_report_formatter.hpp @@ -33,8 +33,6 @@ namespace output { class plain_report_formatter : public results_reporter::format { public: - plain_report_formatter() : m_indent( 0 ), m_color_output( false ) {} - // Formatter interface void results_report_start( std::ostream& ostr ); void results_report_finish( std::ostream& ostr ); @@ -47,7 +45,6 @@ public: private: // Data members counter_t m_indent; - bool m_color_output; }; } // namespace output diff --git a/include/boost/test/tools/collection_comparison_op.hpp b/include/boost/test/tools/collection_comparison_op.hpp index 9a5d9f52..81a70467 100644 --- a/include/boost/test/tools/collection_comparison_op.hpp +++ b/include/boost/test/tools/collection_comparison_op.hpp @@ -325,7 +325,7 @@ compare_collections( Lhs const& lhs, Rhs const& rhs, boost::type >* // ********* specialization of comparison operators for collections ********* // // ************************************************************************** // -#define DEFINE_COLLECTION_COMPARISON( oper, name, rev ) \ +#define DEFINE_COLLECTION_COMPARISON( oper, name, _ ) \ template \ struct name::value && \ @@ -356,10 +356,6 @@ public: \ report( std::ostream&, \ PrevExprType const&, \ Rhs const& ) {} \ - \ - static char const* revert() \ - { return " " #rev " "; } \ - \ }; \ /**/ diff --git a/include/boost/test/tree/test_unit.hpp b/include/boost/test/tree/test_unit.hpp index b4332067..4791bd15 100644 --- a/include/boost/test/tree/test_unit.hpp +++ b/include/boost/test/tree/test_unit.hpp @@ -82,10 +82,10 @@ public: std::string full_name() const; // Public r/o properties - test_unit_type const p_type; ///< type for this test unit - const_string const p_type_name; ///< "case"/"suite"/"module" - const_string const p_file_name; - std::size_t const p_line_num; + readonly_property p_type; ///< type for this test unit + readonly_property p_type_name; ///< "case"/"suite"/"module" + readonly_property p_file_name; + readonly_property p_line_num; id_t p_id; ///< unique id for this test unit parent_id_t p_parent_id; ///< parent test suite id label_list_t p_labels; ///< list of labels associated with this test unit diff --git a/include/boost/test/unit_test_parameters.hpp b/include/boost/test/unit_test_parameters.hpp index 2075ad82..31f76d7b 100644 --- a/include/boost/test/unit_test_parameters.hpp +++ b/include/boost/test/unit_test_parameters.hpp @@ -14,16 +14,15 @@ #ifndef BOOST_TEST_UNIT_TEST_PARAMETERS_HPP_071894GER #define BOOST_TEST_UNIT_TEST_PARAMETERS_HPP_071894GER -// Boost.Test #include -#include - -// STL -#include -#include +#include #include +// STL +#include +#include + //____________________________________________________________________________// namespace boost { @@ -34,88 +33,53 @@ namespace runtime_config { // ************** runtime_config ************** // // ************************************************************************** // -// UTF parameters -BOOST_TEST_DECL extern std::string AUTO_START_DBG; -BOOST_TEST_DECL extern std::string BREAK_EXEC_PATH; -BOOST_TEST_DECL extern std::string BUILD_INFO; -BOOST_TEST_DECL extern std::string CATCH_SYS_ERRORS; -BOOST_TEST_DECL extern std::string COLOR_OUTPUT; -BOOST_TEST_DECL extern std::string DETECT_FP_EXCEPT; -BOOST_TEST_DECL extern std::string DETECT_MEM_LEAKS; -BOOST_TEST_DECL extern std::string LIST_CONTENT; -BOOST_TEST_DECL extern std::string LIST_LABELS; -BOOST_TEST_DECL extern std::string LOG_FORMAT; -BOOST_TEST_DECL extern std::string LOG_LEVEL; -BOOST_TEST_DECL extern std::string LOG_SINK; -BOOST_TEST_DECL extern std::string OUTPUT_FORMAT; -BOOST_TEST_DECL extern std::string RANDOM_SEED; -BOOST_TEST_DECL extern std::string REPORT_FORMAT; -BOOST_TEST_DECL extern std::string REPORT_LEVEL; -BOOST_TEST_DECL extern std::string REPORT_MEM_LEAKS; -BOOST_TEST_DECL extern std::string REPORT_SINK; -BOOST_TEST_DECL extern std::string RESULT_CODE; -BOOST_TEST_DECL extern std::string RUN_FILTERS; -BOOST_TEST_DECL extern std::string SAVE_TEST_PATTERN; -BOOST_TEST_DECL extern std::string SHOW_PROGRESS; -BOOST_TEST_DECL extern std::string USE_ALT_STACK; -BOOST_TEST_DECL extern std::string WAIT_FOR_DEBUGGER; +BOOST_TEST_DECL void init( int& argc, char** argv ); -BOOST_TEST_DECL void init( int& argc, char** argv ); - -// ************************************************************************** // -// ************** runtime_param::get ************** // -// ************************************************************************** // - -/// Access to arguments -BOOST_TEST_DECL runtime::arguments_store const& argument_store(); - -template -inline T const& -get( runtime::cstring parameter_name ) -{ - return argument_store().get( parameter_name ); -} - -/// For public access -BOOST_TEST_DECL bool save_pattern(); - -// ************************************************************************** // -// ************** stream_holder ************** // -// ************************************************************************** // - -class stream_holder { -public: - // Constructor - explicit stream_holder( std::ostream& default_stream ) - : m_stream( &default_stream ) - { - } - - void setup( runtime::cstring param_name ) - { - if( !runtime_config::argument_store().has( param_name ) ) - return; - - std::string const& file_name = runtime_config::get( param_name ); - - if( file_name == "stderr" ) - m_stream = &std::cerr; - else if( file_name == "stdout" ) - m_stream = &std::cout; - else { - m_file.open( file_name.c_str() ); - m_stream = &m_file; - } - } - - // Access methods - std::ostream& ref() const { return *m_stream; } - -private: - // Data members - std::ofstream m_file; - std::ostream* m_stream; -}; +/// Automatically attach debugger in a location of fatal error +BOOST_TEST_DECL bool auto_start_dbg(); +BOOST_TEST_DECL const_string break_exec_path(); +/// Should we catch system errors/sygnals? +BOOST_TEST_DECL bool catch_sys_errors(); +/// Should we try to produce color output? +BOOST_TEST_DECL bool color_output(); +/// Should we detect floating point exceptions? +BOOST_TEST_DECL bool detect_fp_exceptions(); +/// Should we detect memory leaks (>0)? And if yes, which specific memory allocation should we break. +BOOST_TEST_DECL long detect_memory_leaks(); +/// List content of test tree? +BOOST_TEST_DECL output_format list_content(); +/// List available labels? +BOOST_TEST_DECL bool list_labels(); +/// Which output format to use +BOOST_TEST_DECL output_format log_format(); +/// Which log level to set +BOOST_TEST_DECL unit_test::log_level log_level(); +/// Where to direct log stream into +BOOST_TEST_DECL std::ostream* log_sink(); +/// If memory leak detection, where to direct the report +BOOST_TEST_DECL const_string memory_leaks_report_file(); +/// Do not prodce result code +BOOST_TEST_DECL bool no_result_code(); +/// Random seed to use to randomize order of test units being run +BOOST_TEST_DECL unsigned random_seed(); +/// Which format to use to report results +BOOST_TEST_DECL output_format report_format(); +/// Wht lever of report format to set +BOOST_TEST_DECL unit_test::report_level report_level(); +/// Where to direct results report into +BOOST_TEST_DECL std::ostream* report_sink(); +/// Should we save pattern (true) or match against existing pattern (used by output validation tool) +BOOST_TEST_DECL bool save_pattern(); +/// Should Unit Test framework show the build information? +BOOST_TEST_DECL bool show_build_info(); +/// Tells Unit Test Framework to show test progress (forces specific log level) +BOOST_TEST_DECL bool show_progress(); +/// Specific test units to run/exclude +BOOST_TEST_DECL std::list const& test_to_run(); +/// Should execution monitor use alternative stack for signal handling +BOOST_TEST_DECL bool use_alt_stack(); +/// Tells Unit Test Framework to wait for debugger to attach +BOOST_TEST_DECL bool wait_for_debugger(); } // namespace runtime_config } // namespace unit_test diff --git a/include/boost/test/utils/fixed_mapping.hpp b/include/boost/test/utils/fixed_mapping.hpp new file mode 100644 index 00000000..299a77b7 --- /dev/null +++ b/include/boost/test/utils/fixed_mapping.hpp @@ -0,0 +1,120 @@ +// (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) + +// See http://www.boost.org/libs/test for the library home page. +// +// File : $RCSfile$ +// +// Version : $Revision$ +// +// Description : fixed sized mapping with specified invalid value +// *************************************************************************** + +#ifndef BOOST_TEST_UTILS_FIXED_MAPPING_HPP +#define BOOST_TEST_UTILS_FIXED_MAPPING_HPP + +// Boost +#include +#include +#include +#include + +// STL +#include +#include +#include +#include + +#include + +//____________________________________________________________________________// + +namespace boost { +namespace unit_test { + +// configurable maximum fixed sized mapping size supported by this header. +// You can redefine it before inclusion of this file. +#ifndef MAX_MAP_SIZE +#define MAX_MAP_SIZE 20 +#endif + +#define CONSTR_DECL_MID( z, i, dummy1 ) key_param_type key##i, value_param_type v##i, +#define CONSTR_BODY_MID( z, i, dummy1 ) add_pair( key##i, v##i ); + +#define CONSTR_DECL( z, n, dummy1 ) \ + fixed_mapping( BOOST_PP_REPEAT_ ## z( n, CONSTR_DECL_MID, "" ) \ + value_param_type invalid_value ) \ + : m_invalid_value( invalid_value ) \ + { \ + BOOST_PP_REPEAT_ ## z( n, CONSTR_BODY_MID, "" ) \ + init(); \ + } \ +/**/ + +#define CONTRUCTORS( n ) BOOST_PP_REPEAT( n, CONSTR_DECL, "" ) + +template > +class fixed_mapping +{ + typedef std::pair elem_type; + typedef std::vector map_type; + typedef typename std::vector::const_iterator iterator; + + typedef typename call_traits::param_type key_param_type; + typedef typename call_traits::param_type value_param_type; + typedef typename call_traits::const_reference value_ref_type; + +#if BOOST_WORKAROUND(__DECCXX_VER, BOOST_TESTED_AT(60590042)) + struct p1; friend struct p1; + struct p2; friend struct p2; +#endif + + // bind( Compare(), bind(select1st(), _1), bind(identity(), _2) ) + struct p1 : public std::binary_function + { + bool operator()( elem_type const& x, Key const& y ) const { return Compare()( x.first, y ); } + }; + + // bind( Compare(), bind(select1st(), _1), bind(select1st(), _2) ) + struct p2 : public std::binary_function + { + bool operator()( elem_type const& x, elem_type const& y ) const { return Compare()( x.first, y.first ); } + }; + +public: + // Constructors + CONTRUCTORS( BOOST_PP_ADD( MAX_MAP_SIZE, 1 ) ) + + // key -> value access + value_ref_type operator[]( key_param_type key ) const + { + iterator it = boost::detail::lower_bound( m_map.begin(), m_map.end(), key, p1() ); + + return (it == m_map.end() || Compare()( key, it->first ) ) ? m_invalid_value : it->second; + } + +private: + // Implementation + void init() { std::sort( m_map.begin(), m_map.end(), p2() ); } + void add_pair( key_param_type key, value_param_type value ) { m_map.push_back( elem_type( key, value ) ); } + + // Data members + Value m_invalid_value; + map_type m_map; +}; + +} // namespace unit_test +} // namespace boost + +#include + +#undef MAX_MAP_SIZE +#undef CONSTR_DECL_MID +#undef CONSTR_BODY_MID +#undef CONSTR_DECL +#undef CONTRUCTORS + +#endif // BOOST_TEST_UTILS_FIXED_MAPPING_HPP + diff --git a/include/boost/test/utils/iterator/ifstream_line_iterator.hpp b/include/boost/test/utils/iterator/ifstream_line_iterator.hpp new file mode 100644 index 00000000..9a215482 --- /dev/null +++ b/include/boost/test/utils/iterator/ifstream_line_iterator.hpp @@ -0,0 +1,105 @@ +// (C) Copyright Gennadiy Rozental 2004-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 : +// *************************************************************************** + +#ifndef BOOST_TEST_UTILS_IFSTREAM_LINE_ITERATOR_HPP +#define BOOST_TEST_UTILS_IFSTREAM_LINE_ITERATOR_HPP + +// Boost +#include + +// STL +#include + +#include + +//____________________________________________________________________________// + +namespace boost { + +namespace unit_test { + +namespace ut_detail { + +// ************************************************************************** // +// ************** ifstream_holder ************** // +// ************************************************************************** // + +template +class ifstream_holder { +public: + // Constructor + explicit ifstream_holder( basic_cstring file_name ) + { + if( file_name.is_empty() ) + return; + + m_stream.open( file_name.begin(), std::ios::in ); + } + + bool is_valid() + { + return m_stream.is_open(); + } + +protected: +#ifdef BOOST_CLASSIC_IOSTREAMS + typedef std::ifstream stream_t; +#else + typedef std::basic_ifstream > stream_t; +#endif + + // Data members + stream_t m_stream; +}; + +} // namespace ut_detail + +// ************************************************************************** // +// ************** basic_ifstream_line_iterator ************** // +// ************************************************************************** // + +#ifdef BOOST_MSVC +# pragma warning(push) +# pragma warning(disable: 4355) // 'this' : used in base member initializer list +#endif + +template +class basic_ifstream_line_iterator : ut_detail::ifstream_holder, public basic_istream_line_iterator +{ +public: + basic_ifstream_line_iterator( basic_cstring file_name, CharT delimeter ) + : ut_detail::ifstream_holder( file_name ), basic_istream_line_iterator( this->m_stream, delimeter ) {} + + explicit basic_ifstream_line_iterator( basic_cstring file_name = basic_cstring() ) + : ut_detail::ifstream_holder( file_name ), basic_istream_line_iterator( this->m_stream ) {} +}; + +#ifdef BOOST_MSVC +# pragma warning(default: 4355) +# pragma warning(pop) +#endif + +typedef basic_ifstream_line_iterator ifstream_line_iterator; +typedef basic_ifstream_line_iterator wifstream_line_iterator; + +} // namespace unit_test + +} // namespace boost + +//____________________________________________________________________________// + +#include + +#endif // BOOST_TEST_UTILS_IFSTREAM_LINE_ITERATOR_HPP + diff --git a/include/boost/test/utils/iterator/istream_line_iterator.hpp b/include/boost/test/utils/iterator/istream_line_iterator.hpp new file mode 100644 index 00000000..f75be9ca --- /dev/null +++ b/include/boost/test/utils/iterator/istream_line_iterator.hpp @@ -0,0 +1,93 @@ +// (C) Copyright Gennadiy Rozental 2004-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 : +// *************************************************************************** + +#ifndef BOOST_TEST_UTILS_ISTREAM_LINE_ITERATOR_HPP +#define BOOST_TEST_UTILS_ISTREAM_LINE_ITERATOR_HPP + +// Boost +#include +#include + +// STL +#include + +#include + +//____________________________________________________________________________// + +namespace boost { + +namespace unit_test { + +// ************************************************************************** // +// ************** basic_istream_line_iterator ************** // +// ************************************************************************** // + +// !! Should we support policy based delimitation + +template +class basic_istream_line_iterator +: public input_iterator_facade, + std::basic_string, + basic_cstring > { + typedef input_iterator_facade, + std::basic_string, + basic_cstring > base; +#ifdef BOOST_CLASSIC_IOSTREAMS + typedef std::istream istream_type; +#else + typedef std::basic_istream istream_type; +#endif +public: + // Constructors + basic_istream_line_iterator() {} + basic_istream_line_iterator( istream_type& input, CharT delimeter ) + : m_input_stream( &input ), m_delimeter( delimeter ) + { + this->init(); + } + explicit basic_istream_line_iterator( istream_type& input ) + : m_input_stream( &input ) + , m_delimeter( input.widen( '\n' ) ) + { + this->init(); + } + +private: + friend class input_iterator_core_access; + + // increment implementation + bool get() + { + return !!std::getline( *m_input_stream, this->m_value, m_delimeter ); + } + + // Data members + istream_type* m_input_stream; + CharT m_delimeter; +}; + +typedef basic_istream_line_iterator istream_line_iterator; +typedef basic_istream_line_iterator wistream_line_iterator; + +} // namespace unit_test + +} // namespace boost + +//____________________________________________________________________________// + +#include + +#endif // BOOST_TEST_UTILS_ISTREAM_LINE_ITERATOR_HPP + diff --git a/include/boost/test/utils/iterator/token_iterator.hpp b/include/boost/test/utils/iterator/token_iterator.hpp index cf7411c2..c41f0717 100644 --- a/include/boost/test/utils/iterator/token_iterator.hpp +++ b/include/boost/test/utils/iterator/token_iterator.hpp @@ -89,14 +89,15 @@ public: } void set_delimeters( ti_delimeter_type t ) { m_type = t; } - void set_delimeters( cstring d ) + template + void set_delimeters( Src d ) { - m_delimeters = d; + nfp::optionally_assign( m_delimeters, d ); if( !m_delimeters.is_empty() ) m_type = dt_char; } - void set_delimeters( nfp::nil ) {} + bool operator()( CharT c ) { switch( m_type ) { @@ -209,7 +210,7 @@ protected: if( m.has( keep_empty_tokens ) ) m_keep_empty_tokens = true; - nfp::opt_assign( m_tokens_left, m, max_tokens ); + nfp::optionally_assign( m_tokens_left, m, max_tokens ); } template diff --git a/include/boost/test/utils/named_params.hpp b/include/boost/test/utils/named_params.hpp index 0549f8ae..0e66dc39 100644 --- a/include/boost/test/utils/named_params.hpp +++ b/include/boost/test/utils/named_params.hpp @@ -1,4 +1,4 @@ -// (C) Copyright Gennadiy Rozental 2005-2015. +// (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) @@ -9,7 +9,7 @@ // // Version : $Revision$ // -// Description : named function parameters library +// Description : facilities for named function parameters support // *************************************************************************** #ifndef BOOST_TEST_UTILS_NAMED_PARAM @@ -18,6 +18,7 @@ // Boost #include #include +#include // Boost.Test #include @@ -28,14 +29,6 @@ #include -// Boost -#include -#include -#include -#include -#include -#include - #include //____________________________________________________________________________// @@ -47,78 +40,29 @@ namespace nfp { // named function parameters // ************** forward declarations ************** // // ************************************************************************** // -template struct keyword; -template struct typed_keyword; +template struct named_parameter; +template struct keyword; -template struct named_parameter; -template struct named_parameter_combine; +namespace nfp_detail { -// ************************************************************************** // -// ************** is_named_param_pack ************** // -// ************************************************************************** // - -/// is_named_param_pack::value is true if T is parameters pack - -template -struct is_named_param_pack : public mpl::false_ {}; - -template -struct is_named_param_pack > : public mpl::true_ {}; - -template -struct is_named_param_pack> : public mpl::true_ {}; - -// ************************************************************************** // -// ************** param_type ************** // -// ************************************************************************** // - -/// param_type::type is is the type of the parameter -/// corresponding to the Keyword (if parameter is present) or Default - -template -struct param_type -: mpl::if_::type, - typename remove_cv::type, - DefaultType> {}; - -template -struct param_type,Keyword,DefaultType> -: mpl::if_::type, - typename remove_cv::type, - typename param_type::type> {}; - -// ************************************************************************** // -// ************** has_param ************** // -// ************************************************************************** // - -/// has_param::value is true id Params has parameter corresponding -/// to the Keyword - -template -struct has_param : is_same {}; - -template -struct has_param,Keyword> -: mpl::or_::type, - typename has_param::type> {}; +template struct named_parameter_combine; // ************************************************************************** // // ************** access_to_invalid_parameter ************** // // ************************************************************************** // -namespace nfp_detail { - struct access_to_invalid_parameter {}; //____________________________________________________________________________// inline void -report_access_to_invalid_parameter( bool v ) +report_access_to_invalid_parameter(bool v) { - BOOST_TEST_I_ASSRT( !v, access_to_invalid_parameter() ); + if(v) + BOOST_TEST_IMPL_THROW( access_to_invalid_parameter() ); } -} // namespace nfp_detail +//____________________________________________________________________________// // ************************************************************************** // // ************** nil ************** // @@ -131,23 +75,23 @@ struct nil { #else operator T const&() const #endif - { nfp_detail::report_access_to_invalid_parameter(true); static T* v = 0; return *v; } + { report_access_to_invalid_parameter(true); static T* v = 0; return *v; } template T any_cast() const - { nfp_detail::report_access_to_invalid_parameter(true); static typename remove_reference::type* v = 0; return *v; } + { report_access_to_invalid_parameter(true); static typename remove_reference::type* v = 0; return *v; } template nil operator()( Arg1 const& ) - { nfp_detail::report_access_to_invalid_parameter(true); return nil(); } + { report_access_to_invalid_parameter(true); return nil(); } template nil operator()( Arg1 const&, Arg2 const& ) - { nfp_detail::report_access_to_invalid_parameter(true); return nil(); } + { report_access_to_invalid_parameter(true); return nil(); } template nil operator()( Arg1 const&, Arg2 const&, Arg3 const& ) - { nfp_detail::report_access_to_invalid_parameter(true); return nil(); } + { report_access_to_invalid_parameter(true); return nil(); } // Visitation support template @@ -162,8 +106,6 @@ private: // ************** named_parameter_base ************** // // ************************************************************************** // -namespace nfp_detail { - template struct named_parameter_base { template @@ -171,7 +113,7 @@ struct named_parameter_base { operator,( NP const& np ) const { return named_parameter_combine( np, *static_cast(this) ); } }; -} // namespace nfp_detail +//____________________________________________________________________________// // ************************************************************************** // // ************** named_parameter_combine ************** // @@ -180,7 +122,7 @@ struct named_parameter_base { template struct named_parameter_combine : Rest -, nfp_detail::named_parameter_base > { +, named_parameter_base > { typedef typename NP::ref_type res_type; typedef named_parameter_combine self_type; @@ -188,8 +130,7 @@ struct named_parameter_combine named_parameter_combine( NP const& np, Rest const& r ) : Rest( r ) , m_param( np ) - { - } + {} // Access methods res_type operator[]( keyword kw ) const { return m_param[kw]; } @@ -202,7 +143,14 @@ struct named_parameter_combine void erase( keyword kw ) const { m_param.erase( kw ); } using Rest::erase; - using nfp_detail::named_parameter_base>::operator,; +#if BOOST_WORKAROUND(__MWERKS__, BOOST_TESTED_AT(0x3206)) || \ + BOOST_WORKAROUND(__BORLANDC__, BOOST_TESTED_AT(0x0610)) + template + named_parameter_combine operator,( NP const& np ) const + { return named_parameter_combine( np, *this ); } +#else + using named_parameter_base >::operator,; +#endif // Visitation support template @@ -217,16 +165,19 @@ private: NP m_param; }; +} // namespace nfp_detail + // ************************************************************************** // // ************** named_parameter ************** // // ************************************************************************** // -template +template struct named_parameter -: nfp_detail::named_parameter_base > +: nfp_detail::named_parameter_base > { + typedef nfp_detail::nil nil_t; typedef T data_type; - typedef RefType ref_type; + typedef ReferenceType ref_type; typedef unique_id id; // Constructor @@ -240,10 +191,10 @@ struct named_parameter {} // Access methods - ref_type operator[]( keyword ) const { return m_erased ? nil::inst().template any_cast() : m_value; } - ref_type operator[]( keyword ) const { return m_erased ? nil::inst().template any_cast() : m_value; } + ref_type operator[]( keyword ) const { return m_erased ? nil_t::inst().template any_cast() : m_value; } + ref_type operator[]( keyword ) const { return m_erased ? nil_t::inst().template any_cast() : m_value; } template - nil operator[]( keyword ) const { return nil::inst(); } + nil_t operator[]( keyword ) const { return nil_t::inst(); } bool has( keyword ) const { return !m_erased; } template @@ -266,16 +217,22 @@ private: mutable bool m_erased; }; +//____________________________________________________________________________// + // ************************************************************************** // // ************** no_params ************** // // ************************************************************************** // +namespace nfp_detail { typedef named_parameter no_params_type; +} // namespace nfp_detail namespace { -no_params_type no_params( '\0' ); +nfp_detail::no_params_type no_params( '\0' ); } // local namespace +//____________________________________________________________________________// + // ************************************************************************** // // ************** keyword ************** // // ************************************************************************** // @@ -290,10 +247,10 @@ struct keyword { template named_parameter - operator=( T& t ) const { return named_parameter( t ); } + operator=( T& t ) const { return named_parameter( t ); } named_parameter - operator=( char const* t ) const { return named_parameter( t ); } + operator=( char const* t ) const { return named_parameter( t ); } }; //____________________________________________________________________________// @@ -302,7 +259,7 @@ struct keyword { // ************** typed_keyword ************** // // ************************************************************************** // -template +template struct typed_keyword : keyword { named_parameter operator=( T const& t ) const { return named_parameter( t ); } @@ -313,9 +270,9 @@ struct typed_keyword : keyword { //____________________________________________________________________________// -template -struct typed_keyword -: keyword +template +struct typed_keyword +: keyword , named_parameter { typedef unique_id id; @@ -325,64 +282,89 @@ struct typed_keyword operator!() const { return named_parameter( false ); } }; +//____________________________________________________________________________// + // ************************************************************************** // -// ************** opt_assign ************** // +// ************** optionally_assign ************** // // ************************************************************************** // -template -inline typename enable_if_c::value,void>::type -opt_assign( T& target, Params const& p, Keyword k ) +template +inline void +optionally_assign( T&, nfp_detail::nil ) { + nfp_detail::report_access_to_invalid_parameter(true); } //____________________________________________________________________________// -template -inline typename enable_if_c::value,void>::type -opt_assign( T& target, Params const& p, Keyword k ) +template +inline void +#if BOOST_WORKAROUND( __MWERKS__, BOOST_TESTED_AT( 0x3003 ) ) \ + || BOOST_WORKAROUND( __DECCXX_VER, BOOST_TESTED_AT(60590042) ) +optionally_assign( T& target, Source src ) +#else +optionally_assign( T& target, Source const& src ) +#endif { using namespace unit_test; - assign_op( target, p[k], static_cast(0) ); -} - -// ************************************************************************** // -// ************** opt_get ************** // -// ************************************************************************** // - -template -inline T -opt_get( Params const& p, Keyword k, T default_val ) -{ - opt_assign( default_val, p, k ); - - return default_val; -} - -// ************************************************************************** // -// ************** opt_get ************** // -// ************************************************************************** // - -template -inline typename enable_if_c>::value, -named_parameter_combine>::type -opt_append( Params const& params, NP const& np ) -{ - return (params,np); + assign_op( target, src, static_cast(0) ); } //____________________________________________________________________________// -template -inline typename enable_if_c>::value,Params>::type -opt_append( Params const& params, NP const& ) +template +inline void +optionally_assign( T& target, Params const& p, Keyword k ) { - return params; + if( p.has(k) ) + optionally_assign( target, p[k] ); } +//____________________________________________________________________________// + +// ************************************************************************** // +// ************** is_named_params ************** // +// ************************************************************************** // + +template +struct is_named_params : public boost::mpl::false_ {}; + +template +struct is_named_params > : public boost::mpl::true_ {}; + +template +struct is_named_params > : public boost::mpl::true_ {}; + +// ************************************************************************** // +// ************** param_type ************** // +// ************************************************************************** // + +template +struct param_type { + typedef DefaultType type; +}; + +template +struct param_type,Keyword,DefaultType> : param_type { +}; + +template +struct param_type,keyword,DefaultType> { + typedef typename boost::remove_cv::type type; +}; + +template +struct param_type,Rest>, + keyword, + DefaultType> { + typedef typename boost::remove_cv::type type; +}; + } // namespace nfp } // namespace boost #include #endif // BOOST_TEST_UTILS_NAMED_PARAM + diff --git a/include/boost/test/utils/rtti.hpp b/include/boost/test/utils/rtti.hpp index 2421e80f..42f2bc64 100644 --- a/include/boost/test/utils/rtti.hpp +++ b/include/boost/test/utils/rtti.hpp @@ -36,7 +36,7 @@ struct rttid_holder { private: struct rttid {}; - static rttid const& inst() { static rttid s_inst; return s_inst; } + static rttid const& inst() { static rttid s_inst; return s_inst; } }; } // namespace rtti_detail diff --git a/include/boost/test/utils/runtime/argument.hpp b/include/boost/test/utils/runtime/argument.hpp index 876b31b0..b5133e23 100644 --- a/include/boost/test/utils/runtime/argument.hpp +++ b/include/boost/test/utils/runtime/argument.hpp @@ -1,4 +1,4 @@ -// (C) Copyright Gennadiy Rozental 2005-2015. +// (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) @@ -15,40 +15,45 @@ #ifndef BOOST_TEST_UTILS_RUNTIME_ARGUMENT_HPP #define BOOST_TEST_UTILS_RUNTIME_ARGUMENT_HPP -// Boost.Test Runtime parameters +// Boost.Runtime.Parameter +#include #include -#include +#include // Boost.Test #include #include -#include -#include // STL #include -#include - namespace boost { -namespace runtime { + +namespace BOOST_TEST_UTILS_RUNTIME_PARAM_NAMESPACE { // ************************************************************************** // // ************** runtime::argument ************** // // ************************************************************************** // +#ifdef BOOST_MSVC +# pragma warning(push) +# pragma warning(disable:4244) +#endif + class argument { public: // Constructor - argument( rtti::id_t value_type ) - : p_value_type( value_type ) + argument( parameter const& p, rtti::id_t value_type ) + : p_formal_parameter( p ) + , p_value_type( value_type ) {} // Destructor virtual ~argument() {} // Public properties - rtti::id_t const p_value_type; + unit_test::readonly_property p_formal_parameter; + unit_test::readonly_property p_value_type; }; // ************************************************************************** // @@ -59,71 +64,49 @@ template class typed_argument : public argument { public: // Constructor - explicit typed_argument( T const& v ) - : argument( rtti::type_id() ) - , p_value( v ) + explicit typed_argument( parameter const& p ) + : argument( p, rtti::type_id() ) + {} + typed_argument( parameter const& p, T const& t ) + : argument( p, rtti::type_id() ) + , p_value( t ) {} unit_test::readwrite_property p_value; }; // ************************************************************************** // -// ************** runtime::arguments_store ************** // +// ************** runtime::arg_value ************** // // ************************************************************************** // -class arguments_store { -public: - typedef std::map storage_type; +template +inline T const& +arg_value( argument const& arg_ ) +{ + assert( arg_.p_value_type == rtti::type_id() ); // detect logic error - /// Returns number of arguments in the store; mostly used for testing - std::size_t size() const { return m_arguments.size(); } + return static_cast const&>( arg_ ).p_value.value; +} - /// Clears the store for reuse - void clear() { m_arguments.clear(); } +//____________________________________________________________________________// - /// Returns true if there is an argument corresponding to the specified parameter name - bool has( cstring parameter_name ) const - { - return m_arguments.find( parameter_name ) != m_arguments.end(); - } +template +inline T& +arg_value( argument& arg_ ) +{ + assert( arg_.p_value_type == rtti::type_id() ); // detect logic error - /// Provides types access to argument value by parameter name - template - T const& get( cstring parameter_name ) const { - return const_cast(this)->get( parameter_name ); - } + return static_cast&>( arg_ ).p_value.value; +} - template - T& get( cstring parameter_name ) { - auto found = m_arguments.find( parameter_name ); - BOOST_TEST_I_ASSRT( found != m_arguments.end(), - access_to_missing_argument() - << "There is no argument provided for parameter " << parameter_name ); +#ifdef BOOST_MSVC +# pragma warning(pop) +#endif - argument_ptr arg = found->second; +//____________________________________________________________________________// - BOOST_TEST_I_ASSRT( arg->p_value_type == rtti::type_id(), - arg_type_mismatch() << "Access with invalid type for argument corresponding to parameter " - << parameter_name ); +} // namespace BOOST_TEST_UTILS_RUNTIME_PARAM_NAMESPACE - return static_cast&>( *arg ).p_value.value; - } - - /// Set's the argument value for specified parameter name - template - void set( cstring parameter_name, T const& value ) - { - m_arguments[parameter_name] = argument_ptr( new typed_argument( value ) ); - } - -private: - // Data members - storage_type m_arguments; -}; - -} // namespace runtime } // namespace boost -#include - #endif // BOOST_TEST_UTILS_RUNTIME_ARGUMENT_HPP diff --git a/include/boost/test/utils/runtime/argument_factory.hpp b/include/boost/test/utils/runtime/argument_factory.hpp deleted file mode 100644 index 792e6f2c..00000000 --- a/include/boost/test/utils/runtime/argument_factory.hpp +++ /dev/null @@ -1,236 +0,0 @@ -// (C) Copyright Gennadiy Rozental 2005-2015. -// 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 : argument factories for different kinds of parameters -// *************************************************************************** - -#ifndef BOOST_TEST_UTILS_RUNTIME_ARGUMENT_FACTORY_HPP -#define BOOST_TEST_UTILS_RUNTIME_ARGUMENT_FACTORY_HPP - -// Boost.Test Runtime parameters -#include -#include - -// Boost.Test -#include -#include - -// Boost -#include -#include - -// STL -#include - -#include - -namespace boost { -namespace runtime { - -// ************************************************************************** // -// ************** runtime::value_interpreter ************** // -// ************************************************************************** // - -template -struct value_interpreter; - -//____________________________________________________________________________// - -template -struct value_interpreter { - template - explicit value_interpreter( Modifiers const& ) {} - - ValueType interpret( cstring param_name, cstring source ) const - { - BOOST_TEST_I_TRY{ - return lexical_cast(source); - } BOOST_TEST_I_CATCH0( bad_lexical_cast ) { - BOOST_TEST_I_THROW( format_error( param_name ) << source << - " can't be interpreted as value of parameter " << param_name << "." ); - } - return ValueType{}; - } -}; - -//____________________________________________________________________________// - -template<> -struct value_interpreter { - template - explicit value_interpreter( Modifiers const& ) {} - - std::string interpret( cstring, cstring source ) const - { - return std::string( source.begin(), source.size() ); - } -}; - -//____________________________________________________________________________// - -template<> -struct value_interpreter { - template - explicit value_interpreter( Modifiers const& ) {} - - cstring interpret( cstring, cstring source ) const - { - return source; - } -}; - -//____________________________________________________________________________// - -template<> -struct value_interpreter { - template - explicit value_interpreter( Modifiers const& ) {} - - bool interpret( cstring param_name, cstring source ) const - { - static cstring const s_YES( "YES" ); - static cstring const s_Y( "Y" ); - static cstring const s_NO( "NO" ); - static cstring const s_N( "N" ); - static cstring const s_TRUE( "TRUE" ); - static cstring const s_FALSE( "FALSE" ); - static cstring const s_one( "1" ); - static cstring const s_zero( "0" ); - - source.trim(); - - if( source.is_empty() || - case_ins_eq( source, s_YES ) || - case_ins_eq( source, s_Y ) || - case_ins_eq( source, s_one ) || - case_ins_eq( source, s_TRUE ) ) - return true; - - if( case_ins_eq( source, s_NO ) || - case_ins_eq( source, s_N ) || - case_ins_eq( source, s_zero ) || - case_ins_eq( source, s_FALSE ) ) - return false; - - BOOST_TEST_I_THROW( format_error( param_name ) << source << " can't be interpreted as bool value." ); - } -}; - -//____________________________________________________________________________// - -template -struct value_interpreter { - template - explicit value_interpreter( Modifiers const& m ) - : m_name_to_value( m[enum_values::value] ) - { - } - - EnumType interpret( cstring param_name, cstring source ) const - { - auto found = m_name_to_value.find( source ); - - BOOST_TEST_I_ASSRT( found != m_name_to_value.end(), - format_error( param_name ) << source << - " is not a valid enumeration value name for parameter " << param_name << "." ); - - return found->second; - } - -private: - // Data members - std::map m_name_to_value; -}; - -//____________________________________________________________________________// - -// ************************************************************************** // -// ************** runtime::argument_factory ************** // -// ************************************************************************** // - -template -class argument_factory; - -//____________________________________________________________________________// - -template -class argument_factory { -public: - template - explicit argument_factory( Modifiers const& m ) - : m_interpreter( m ) - , m_optional_value( nfp::opt_get( m, optional_value, ValueType{} ) ) - , m_default_value( nfp::opt_get( m, default_value, ValueType{} ) ) - { - } - - void produce_argument( cstring source, cstring param_name, arguments_store& store ) const - { - store.set( param_name, source.empty() ? m_optional_value : m_interpreter.interpret( param_name, source ) ); - } - - void produce_default( cstring param_name, arguments_store& store ) const - { - store.set( param_name, m_default_value ); - } - -private: - // Data members - typedef value_interpreter interp_t; - interp_t m_interpreter; - ValueType m_optional_value; - ValueType m_default_value; -}; - -//____________________________________________________________________________// - -template -class argument_factory { -public: - template - explicit argument_factory( Modifiers const& m ) - : m_interpreter( m ) - { - } - - void produce_argument( cstring source, cstring param_name, arguments_store& store ) const - { - ValueType value = m_interpreter.interpret( param_name, source ); - - if( store.has( param_name ) ) { - std::vector& values = store.get>( param_name ); - values.push_back( value ); - } - else { - std::vector values( 1, value ); - - store.set( param_name, values ); - } - - } - void produce_default( cstring param_name, arguments_store& store ) const - { - store.set( param_name, std::vector{} ); - } - -private: - // Data members - value_interpreter m_interpreter; -}; - -//____________________________________________________________________________// - -} // namespace runtime -} // namespace boost - -#include - -#endif // BOOST_TEST_UTILS_RUNTIME_ARGUMENT_FACTORY_HPP diff --git a/include/boost/test/utils/runtime/cla/argument_factory.hpp b/include/boost/test/utils/runtime/cla/argument_factory.hpp new file mode 100644 index 00000000..66835406 --- /dev/null +++ b/include/boost/test/utils/runtime/cla/argument_factory.hpp @@ -0,0 +1,216 @@ +// (C) Copyright Gennadiy Rozental 2005-2014. +// Use, modification, and distribution are subject to 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 : generic typed_argument_factory implementation +// *************************************************************************** + +#ifndef BOOST_TEST_UTILS_RUNTIME_CLA_ARGUMENT_FACTORY_HPP +#define BOOST_TEST_UTILS_RUNTIME_CLA_ARGUMENT_FACTORY_HPP + +// Boost.Runtime.Parameter +#include + +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include + +#include + +// Boost +#include +#include + +namespace boost { + +namespace BOOST_TEST_UTILS_RUNTIME_PARAM_NAMESPACE { + +namespace cla { + +// ************************************************************************** // +// ************** default_value_interpreter ************** // +// ************************************************************************** // + +namespace rt_cla_detail { + +struct default_value_interpreter { + template + void operator()( argv_traverser& tr, boost::optional& value ) + { + if( interpret_argument_value( tr.token(), value, 0 ) ) + tr.next_token(); + } +}; + +} // namespace rt_cla_detail + +// ************************************************************************** // +// ************** typed_argument_factory ************** // +// ************************************************************************** // + +template +struct typed_argument_factory : public argument_factory { + // Constructor + typed_argument_factory() + : m_value_interpreter( rt_cla_detail::default_value_interpreter() ) + {} + BOOST_TEST_UTILS_RUNTIME_PARAM_UNNEEDED_VIRTUAL ~typed_argument_factory() {} + + // properties modification + template + void accept_modifier( Modifier const& m ) + { + optionally_assign( m_value_handler, m, handler ); + optionally_assign( m_value_interpreter, m, interpreter ); + + if( m.has( default_value ) ) { + BOOST_TEST_UTILS_RUNTIME_PARAM_VALIDATE_LOGIC( !m_value_generator, + BOOST_TEST_UTILS_RUNTIME_PARAM_LITERAL( "multiple value generators for parameter" ) ); + + T const& dv_ref = m[default_value]; + m_value_generator = rt_cla_detail::const_generator( dv_ref ); + } + + if( m.has( default_refer_to ) ) { + BOOST_TEST_UTILS_RUNTIME_PARAM_VALIDATE_LOGIC( !m_value_generator, + BOOST_TEST_UTILS_RUNTIME_PARAM_LITERAL( "multiple value generators for parameter" ) ); + + cstring ref_id = m[default_refer_to]; + m_value_generator = rt_cla_detail::ref_generator( ref_id ); + } + + if( m.has( assign_to ) ) { + BOOST_TEST_UTILS_RUNTIME_PARAM_VALIDATE_LOGIC( !m_value_handler, + BOOST_TEST_UTILS_RUNTIME_PARAM_LITERAL( "multiple value handlers for parameter" ) ); + + m_value_handler = rt_cla_detail::assigner( m[assign_to] ); + } + } + + // Argument factory implementation + virtual argument_ptr produce_using( parameter& p, argv_traverser& tr ); + virtual argument_ptr produce_using( parameter& p, parser const& ); + virtual void argument_usage_info( format_stream& fs ); + +// !! private? + // Data members + boost::function m_value_handler; + boost::function&)> m_value_generator; + boost::function&)> m_value_interpreter; +}; + +//____________________________________________________________________________// + +template +inline argument_ptr +typed_argument_factory::produce_using( parameter& p, argv_traverser& tr ) +{ + boost::optional value; + + BOOST_TEST_IMPL_TRY { + m_value_interpreter( tr, value ); + } + BOOST_TEST_IMPL_CATCHALL() { // !! should we do that? + BOOST_TEST_UTILS_RUNTIME_PARAM_TRACE( "Fail to parse argument value" ); + + if( !p.p_optional_value ) + BOOST_TEST_IMPL_RETHROW; + } + + argument_ptr actual_arg = p.actual_argument(); + + BOOST_TEST_UTILS_RUNTIME_CLA_VALIDATE_INPUT( !!value || p.p_optional_value, tr, + BOOST_TEST_UTILS_RUNTIME_PARAM_LITERAL( "Argument value missing for parameter " ) << p.id_2_report() ); + + BOOST_TEST_UTILS_RUNTIME_CLA_VALIDATE_INPUT( !actual_arg || p.p_multiplicable, tr, + BOOST_TEST_UTILS_RUNTIME_PARAM_LITERAL( "Unexpected repetition of the parameter " ) << p.id_2_report() ); + + if( !!value && !!m_value_handler ) + m_value_handler( p, *value ); + + if( !p.p_multiplicable ) + actual_arg.reset( p.p_optional_value && (rtti::type_id() != rtti::type_id()) + ? static_cast(new typed_argument >( p, value )) + : static_cast(new typed_argument( p, *value )) ); + else { + typedef std::list > optional_list; + + if( !actual_arg ) + actual_arg.reset( p.p_optional_value + ? static_cast(new typed_argument( p )) + : static_cast(new typed_argument >( p )) ); + + if( p.p_optional_value ) { + optional_list& values = arg_value( *actual_arg ); + + values.push_back( value ); + } + else { + std::list& values = arg_value >( *actual_arg ); + + values.push_back( *value ); + } + } + + return actual_arg; +} + +//____________________________________________________________________________// + +template +inline argument_ptr +typed_argument_factory::produce_using( parameter& p, parser const& pa ) +{ + argument_ptr actual_arg; + + if( !m_value_generator ) + return actual_arg; + + boost::optional value; + m_value_generator( pa, value ); + + if( !value ) + return actual_arg; + + if( !!m_value_handler ) + m_value_handler( p, *value ); + + actual_arg.reset( new typed_argument( p, *value ) ); + + return actual_arg; +} + +//____________________________________________________________________________// + +template +inline void +typed_argument_factory::argument_usage_info( format_stream& fs ) +{ + rt_cla_detail::argument_value_usage( fs, 0, reinterpret_cast(0) ); +} + +//____________________________________________________________________________// + +} // namespace boost + +} // namespace BOOST_TEST_UTILS_RUNTIME_PARAM_NAMESPACE + +} // namespace cla + +#endif // BOOST_TEST_UTILS_RUNTIME_CLA_ARGUMENT_FACTORY_HPP diff --git a/include/boost/test/utils/runtime/cla/argv_traverser.cpp b/include/boost/test/utils/runtime/cla/argv_traverser.cpp new file mode 100644 index 00000000..9716b8fb --- /dev/null +++ b/include/boost/test/utils/runtime/cla/argv_traverser.cpp @@ -0,0 +1,16 @@ +// (C) Copyright Gennadiy Rozental 2005-2014. +// Use, modification, and distribution are subject to 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 : offline implementation for argc/argv traverser +// *************************************************************************** + +#define BOOST_TEST_UTILS_RUNTIME_PARAM_INLINE +#include diff --git a/include/boost/test/utils/runtime/cla/argv_traverser.hpp b/include/boost/test/utils/runtime/cla/argv_traverser.hpp index fe93288c..6f6e03df 100644 --- a/include/boost/test/utils/runtime/cla/argv_traverser.hpp +++ b/include/boost/test/utils/runtime/cla/argv_traverser.hpp @@ -1,4 +1,4 @@ -// (C) Copyright Gennadiy Rozental 2005-2015. +// (C) Copyright Gennadiy Rozental 2005-2014. // Use, modification, and distribution are subject to 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) @@ -15,133 +15,86 @@ #ifndef BOOST_TEST_UTILS_RUNTIME_CLA_ARGV_TRAVERSER_HPP #define BOOST_TEST_UTILS_RUNTIME_CLA_ARGV_TRAVERSER_HPP -// Boost.Test Runtime parameters -#include +// Boost.Runtime.Parameter +#include -#include +// Boost.Test +#include + +// Boost +#include +#include namespace boost { -namespace runtime { + +namespace BOOST_TEST_UTILS_RUNTIME_PARAM_NAMESPACE { + namespace cla { // ************************************************************************** // // ************** runtime::cla::argv_traverser ************** // // ************************************************************************** // -/// End of input token indicator -static const char END_OF_TOKEN = '\0'; - -class argv_traverser { - typedef char const** argv_type; +class argv_traverser : noncopyable { + class parser; public: - /// Constructs traverser based on argc/argv pair - /// argv is taken "by reference" and later can be - /// updated in remainder method - argv_traverser( int argc, argv_type argv ) - : m_argc( argc ) - , m_curr_arg( 0 ) - , m_arg_size( 0 ) - , m_arg_pos( 0 ) - , m_argv( argv ) - { - next_arg(); - } + // Constructor + argv_traverser(); - /// Updates argv to contain the remainder of the input - /// and returns new argc - int remainder() - { - std::size_t new_argc = m_argc - m_curr_arg + 1; + // public_properties + unit_test::readwrite_property p_ignore_mismatch; + unit_test::readwrite_property p_separator; - if( new_argc != m_argc ) - for( std::size_t i = 1; i < new_argc ; ++i ) - m_argv[i] = m_argv[m_curr_arg + i - 1]; + // argc+argv <-> internal buffer exchange + void init( int argc, char_type** argv ); + void remainder( int& argc, char_type** argv ); - m_argv[1] += m_arg_pos; + // token based parsing + cstring token() const; + void next_token(); - return (int)new_argc; - } + // whole input parsing + cstring input() const; + void trim( std::size_t size ); + bool match_front( cstring ); + bool match_front( char_type c ); + bool eoi() const; - /// Returns true, if we reached end on input - bool eoi() const - { - return m_curr_arg == m_argc; - } + // transaction logic support + void commit(); + void rollback(); - /// For the purposes of error reporting produces current token being parsed - /// (from the begining) - cstring current_token() - { - if( eoi() ) - return cstring(); + // current position access; used to save some reference points in input + std::size_t input_pos() const; - return cstring( m_argv[m_curr_arg], m_arg_size ); - } - - /// Skips ahead by num_chars characters - void skip( std::size_t num_chars ) - { - m_arg_pos += num_chars; - if( m_arg_pos >= m_arg_size ) { - next_arg(); - } - } - - /// Gets single character from input. If we reached end of - /// input, alwars returns END_OF_TOKEN. If we reached end - /// of token returns END_OF_TOKEN and moves to next token. - /// Note that END_OF_TOKEN is returned after we read the - /// last charter in a token - char get_char() - { - if( eoi() ) - return END_OF_TOKEN; - - if( m_arg_pos == m_arg_size ) { - next_arg(); - return END_OF_TOKEN; - } - - return m_argv[m_curr_arg][m_arg_pos++]; - } - - /// Returns all the characters ramaining in the current token and moves - /// to next token - cstring get_token() - { - if( eoi() ) - return cstring(); - - cstring token( m_argv[m_curr_arg] + m_arg_pos, m_arg_size - m_arg_pos ); - - next_arg(); - - return token; - } + // returns true if mismatch detected during input parsing handled successfully + bool handle_mismatch(); private: - void next_arg() - { - ++m_curr_arg; - - if( !eoi() ) { - m_arg_size = ::strlen( m_argv[m_curr_arg] ); - m_arg_pos = 0; - } - } - // Data members - std::size_t m_argc; // total number of arguments - std::size_t m_curr_arg; // current argument index in argv - std::size_t m_arg_size; // current argument size - std::size_t m_arg_pos; // current argument position - argv_type m_argv; // all arguments + dstring m_buffer; + cstring m_work_buffer; + + cstring m_token; + cstring::iterator m_commited_end; + + shared_array m_remainder; + std::size_t m_remainder_size; }; } // namespace cla -} // namespace runtime + +} // namespace BOOST_TEST_UTILS_RUNTIME_PARAM_NAMESPACE + } // namespace boost -#include +#ifndef BOOST_TEST_UTILS_RUNTIME_PARAM_OFFLINE + +#ifndef BOOST_TEST_UTILS_RUNTIME_PARAM_INLINE +# define BOOST_TEST_UTILS_RUNTIME_PARAM_INLINE inline +#endif +# include + +#endif #endif // BOOST_TEST_UTILS_RUNTIME_CLA_ARGV_TRAVERSER_HPP diff --git a/include/boost/test/utils/runtime/cla/argv_traverser.ipp b/include/boost/test/utils/runtime/cla/argv_traverser.ipp new file mode 100644 index 00000000..d1ae93be --- /dev/null +++ b/include/boost/test/utils/runtime/cla/argv_traverser.ipp @@ -0,0 +1,212 @@ +// (C) Copyright Gennadiy Rozental 2005-2014. +// Use, modification, and distribution are subject to 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 : implements facility to hide input traversing details +// *************************************************************************** + +#ifndef BOOST_TEST_UTILS_RUNTIME_CLA_ARGV_TRAVERSER_IPP +#define BOOST_TEST_UTILS_RUNTIME_CLA_ARGV_TRAVERSER_IPP + +// Boost.Runtime.Parameter +#include + +#include + +// STL +#include +#include + +#ifdef BOOST_NO_STDC_NAMESPACE +namespace std { using ::memcpy; } +#endif + +namespace boost { + +namespace BOOST_TEST_UTILS_RUNTIME_PARAM_NAMESPACE { + +namespace cla { + +// ************************************************************************** // +// ************** runtime::cla::argv_traverser ************** // +// ************************************************************************** // + +BOOST_TEST_UTILS_RUNTIME_PARAM_INLINE +argv_traverser::argv_traverser() +: p_ignore_mismatch( false ), p_separator( BOOST_TEST_UTILS_RUNTIME_PARAM_LITERAL( ' ' ) ) +{ +} + +//____________________________________________________________________________// + +BOOST_TEST_UTILS_RUNTIME_PARAM_INLINE void +argv_traverser::init( int argc, char_type** argv ) +{ + m_buffer.clear(); + + for( int index = 1; index < argc; ++index ) { + m_buffer += argv[index]; + if( index != argc-1 ) + m_buffer += BOOST_TEST_UTILS_RUNTIME_PARAM_LITERAL( ' ' ); + } + + m_remainder.reset( new char_type[m_buffer.size()+1] ); + m_remainder_size = 0; + m_work_buffer = m_buffer; + m_commited_end = m_work_buffer.begin(); + + BOOST_TEST_UTILS_RUNTIME_PARAM_TRACE( "Input buffer: " << m_buffer ); + + next_token(); +} + +//____________________________________________________________________________// + +BOOST_TEST_UTILS_RUNTIME_PARAM_INLINE void +argv_traverser::remainder( int& argc, char_type** argv ) +{ + argc = 1; + std::size_t pos = 0; + while(pos < m_remainder_size ) { + argv[argc++] = m_remainder.get() + pos; + + pos = static_cast(std::find( m_remainder.get() + pos, m_remainder.get() + m_remainder_size, + BOOST_TEST_UTILS_RUNTIME_PARAM_LITERAL( ' ' ) ) - + m_remainder.get()); + m_remainder[pos++] = BOOST_TEST_UTILS_RUNTIME_PARAM_LITERAL( '\0' ); + } +} + +//____________________________________________________________________________// + +BOOST_TEST_UTILS_RUNTIME_PARAM_INLINE cstring +argv_traverser::token() const +{ + return m_token; +} + +//____________________________________________________________________________// + +BOOST_TEST_UTILS_RUNTIME_PARAM_INLINE void +argv_traverser::next_token() +{ + if( m_work_buffer.is_empty() ) + return; + + m_work_buffer.trim_left( m_token.size() ); // skip remainder of current token + + if( m_work_buffer.size() != m_buffer.size() ) // !! is there a better way to identify first token + m_work_buffer.trim_left( 1 ); // skip separator if not first token; + + m_token.assign( m_work_buffer.begin(), + std::find( m_work_buffer.begin(), m_work_buffer.end(), p_separator ) ); +} + +//____________________________________________________________________________// + +BOOST_TEST_UTILS_RUNTIME_PARAM_INLINE cstring +argv_traverser::input() const +{ + return m_work_buffer; +} + +//____________________________________________________________________________// + +BOOST_TEST_UTILS_RUNTIME_PARAM_INLINE void +argv_traverser::trim( std::size_t size ) +{ + m_work_buffer.trim_left( size ); + + if( size <= m_token.size() ) + m_token.trim_left( size ); + else { + m_token.assign( m_work_buffer.begin(), + std::find( m_work_buffer.begin(), m_work_buffer.end(), p_separator ) ); + } +} + +//____________________________________________________________________________// + +BOOST_TEST_UTILS_RUNTIME_PARAM_INLINE bool +argv_traverser::match_front( cstring str ) +{ + return m_work_buffer.size() < str.size() ? false : m_work_buffer.substr( 0, str.size() ) == str; +} + +//____________________________________________________________________________// + +BOOST_TEST_UTILS_RUNTIME_PARAM_INLINE bool +argv_traverser::match_front( char_type c ) +{ + return first_char( m_work_buffer ) == c; +} + +//____________________________________________________________________________// + +BOOST_TEST_UTILS_RUNTIME_PARAM_INLINE bool +argv_traverser::eoi() const +{ + return m_work_buffer.is_empty(); +} + +//____________________________________________________________________________// + +BOOST_TEST_UTILS_RUNTIME_PARAM_INLINE void +argv_traverser::commit() +{ + m_commited_end = m_work_buffer.begin(); +} + +//____________________________________________________________________________// + +BOOST_TEST_UTILS_RUNTIME_PARAM_INLINE void +argv_traverser::rollback() +{ + m_work_buffer.assign( m_commited_end, m_work_buffer.end() ); + m_token.assign( m_work_buffer.begin(), + std::find( m_work_buffer.begin(), m_work_buffer.end(), p_separator ) ); + +} + +//____________________________________________________________________________// + +BOOST_TEST_UTILS_RUNTIME_PARAM_INLINE std::size_t +argv_traverser::input_pos() const +{ + return static_cast(m_work_buffer.begin() - m_commited_end); +} + +//____________________________________________________________________________// + +BOOST_TEST_UTILS_RUNTIME_PARAM_INLINE bool +argv_traverser::handle_mismatch() +{ + if( !p_ignore_mismatch ) + return false; + + std::memcpy( m_remainder.get() + m_remainder_size, token().begin(), token().size() ); + m_remainder_size += token().size(); + m_remainder[m_remainder_size++] = p_separator; + + next_token(); + commit(); + + return true; +} + +//____________________________________________________________________________// + +} // namespace cla + +} // namespace BOOST_TEST_UTILS_RUNTIME_PARAM_NAMESPACE + +} // namespace boost + +#endif // BOOST_TEST_UTILS_RUNTIME_CLA_ARGV_TRAVERSER_IPP diff --git a/include/boost/test/utils/runtime/cla/basic_parameter.hpp b/include/boost/test/utils/runtime/cla/basic_parameter.hpp new file mode 100644 index 00000000..817b12a3 --- /dev/null +++ b/include/boost/test/utils/runtime/cla/basic_parameter.hpp @@ -0,0 +1,85 @@ +// (C) Copyright Gennadiy Rozental 2005-2014. +// Use, modification, and distribution are subject to 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 : generic custom parameter generator +// *************************************************************************** + +#ifndef BOOST_TEST_UTILS_RUNTIME_CLA_BASIC_PARAMETER_HPP +#define BOOST_TEST_UTILS_RUNTIME_CLA_BASIC_PARAMETER_HPP + +// Boost.Runtime.Parameter +#include + +#include + +// Boost.Test +#include + +// Boost +#include + +namespace boost { + +namespace BOOST_TEST_UTILS_RUNTIME_PARAM_NAMESPACE { + +namespace cla { + +// ************************************************************************** // +// ************** runtime::cla::basic_parameter ************** // +// ************************************************************************** // + +template +class basic_parameter : private base_from_member, public typed_parameter { +public: + // Constructors + explicit basic_parameter( cstring n ) + : base_from_member() + , typed_parameter( base_from_member::member ) + { + this->accept_modifier( name = n ); + } + + // parameter properties modification + template + void accept_modifier( Modifier const& m ) + { + typed_parameter::accept_modifier( m ); + + base_from_member::member.accept_modifier( m ); + } +}; + +//____________________________________________________________________________// + +#define BOOST_TEST_UTILS_RUNTIME_CLA_NAMED_PARAM_GENERATORS( param_type ) \ +template \ +inline shared_ptr > \ +param_type( cstring name = cstring() ) \ +{ \ + return shared_ptr >( new param_type ## _t( name ) ); \ +} \ + \ +inline shared_ptr > \ +param_type( cstring name = cstring() ) \ +{ \ + return shared_ptr >( new param_type ## _t( name ) ); \ +} \ +/**/ + +//____________________________________________________________________________// + +} // namespace cla + +} // namespace BOOST_TEST_UTILS_RUNTIME_PARAM_NAMESPACE + +} // namespace boost + +#endif // BOOST_TEST_UTILS_RUNTIME_CLA_BASIC_PARAMETER_HPP diff --git a/include/boost/test/utils/runtime/cla/char_parameter.cpp b/include/boost/test/utils/runtime/cla/char_parameter.cpp new file mode 100644 index 00000000..6e85fe41 --- /dev/null +++ b/include/boost/test/utils/runtime/cla/char_parameter.cpp @@ -0,0 +1,16 @@ +// (C) Copyright Gennadiy Rozental 2005-2014. +// Use, modification, and distribution are subject to 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 : offline implementation of char parameter +// *************************************************************************** + +#define BOOST_TEST_UTILS_RUNTIME_PARAM_INLINE +#include diff --git a/include/boost/test/utils/runtime/cla/char_parameter.hpp b/include/boost/test/utils/runtime/cla/char_parameter.hpp new file mode 100644 index 00000000..0e2928b1 --- /dev/null +++ b/include/boost/test/utils/runtime/cla/char_parameter.hpp @@ -0,0 +1,100 @@ +// (C) Copyright Gennadiy Rozental 2005-2014. +// Use, modification, and distribution are subject to 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 : defines model of parameter with single char name +// *************************************************************************** + +#ifndef BOOST_TEST_UTILS_RUNTIME_CLA_CHAR_PARAMETER_HPP +#define BOOST_TEST_UTILS_RUNTIME_CLA_CHAR_PARAMETER_HPP + +// Boost.Runtime.Parameter +#include +#include + +#include +#include + +namespace boost { + +namespace BOOST_TEST_UTILS_RUNTIME_PARAM_NAMESPACE { + +namespace cla { + +// ************************************************************************** // +// ************** char_name_policy ************** // +// ************************************************************************** // + +class char_name_policy : public basic_naming_policy { +public: + // Constructor + char_name_policy(); + BOOST_TEST_UTILS_RUNTIME_PARAM_UNNEEDED_VIRTUAL ~char_name_policy() {} + + // policy interface + virtual bool conflict_with( identification_policy const& ) const; + + // Accept modifier + template + void accept_modifier( Modifier const& m ) + { + basic_naming_policy::accept_modifier( m ); + + BOOST_TEST_UTILS_RUNTIME_PARAM_VALIDATE_LOGIC( p_name->size() <= 1, "Invalid parameter name " << p_name ); + } +}; + +// ************************************************************************** // +// ************** runtime::cla::char_parameter ************** // +// ************************************************************************** // + +template +class char_parameter_t : public basic_parameter { + typedef basic_parameter base; +public: + // Constructors + explicit char_parameter_t( char_type name ) : base( cstring( &name, 1 ) ) {} +}; + +//____________________________________________________________________________// + +template +inline shared_ptr > +char_parameter( char_type name ) +{ + return shared_ptr >( new char_parameter_t( name ) ); +} + +//____________________________________________________________________________// + +inline shared_ptr > +char_parameter( char_type name ) +{ + return shared_ptr >( new char_parameter_t( name ) ); +} + +//____________________________________________________________________________// + +} // namespace cla + +} // namespace BOOST_TEST_UTILS_RUNTIME_PARAM_NAMESPACE + +} // namespace boost + +#ifndef BOOST_TEST_UTILS_RUNTIME_PARAM_OFFLINE + +#ifndef BOOST_TEST_UTILS_RUNTIME_PARAM_INLINE +# define BOOST_TEST_UTILS_RUNTIME_PARAM_INLINE inline +#endif +# include + +#endif + +#endif // BOOST_TEST_UTILS_RUNTIME_CLA_CHAR_PARAMETER_HPP diff --git a/include/boost/test/utils/runtime/cla/char_parameter.ipp b/include/boost/test/utils/runtime/cla/char_parameter.ipp new file mode 100644 index 00000000..398ce79a --- /dev/null +++ b/include/boost/test/utils/runtime/cla/char_parameter.ipp @@ -0,0 +1,57 @@ +// (C) Copyright Gennadiy Rozental 2005-2014. +// Use, modification, and distribution are subject to 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 : implements model of parameter with single char name +// *************************************************************************** + +#ifndef BOOST_TEST_UTILS_RUNTIME_CLA_CHAR_PARAMETER_IPP +#define BOOST_TEST_UTILS_RUNTIME_CLA_CHAR_PARAMETER_IPP + +// Boost.Runtime.Parameter +#include + +#include + +namespace boost { + +namespace BOOST_TEST_UTILS_RUNTIME_PARAM_NAMESPACE { + +namespace cla { + +// ************************************************************************** // +// ************** char_name_policy ************** // +// ************************************************************************** // + +BOOST_TEST_UTILS_RUNTIME_PARAM_INLINE +char_name_policy::char_name_policy() +: basic_naming_policy( rtti::type_id() ) +{ + assign_op( p_prefix.value, BOOST_TEST_UTILS_RUNTIME_PARAM_CSTRING_LITERAL( "-" ), 0 ); +} + +//____________________________________________________________________________// + +BOOST_TEST_UTILS_RUNTIME_PARAM_INLINE bool +char_name_policy::conflict_with( identification_policy const& id ) const +{ + return id.p_type_id == p_type_id && + p_name == static_cast( id ).p_name; +} + +//____________________________________________________________________________// + +} // namespace cla + +} // namespace BOOST_TEST_UTILS_RUNTIME_PARAM_NAMESPACE + +} // namespace boost + +#endif // BOOST_TEST_UTILS_RUNTIME_CLA_CHAR_PARAMETER_IPP diff --git a/include/boost/test/utils/runtime/cla/detail/argument_value_usage.hpp b/include/boost/test/utils/runtime/cla/detail/argument_value_usage.hpp new file mode 100644 index 00000000..a70b6d1f --- /dev/null +++ b/include/boost/test/utils/runtime/cla/detail/argument_value_usage.hpp @@ -0,0 +1,81 @@ +// (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 : $RCSfile$ +// +// Version : $Revision$ +// +// Description : argument usage printing helpers +// *************************************************************************** + +#ifndef BOOST_TEST_UTILS_RUNTIME_CLA_ARGUMENT_VALUE_USAGE_HPP +#define BOOST_TEST_UTILS_RUNTIME_CLA_ARGUMENT_VALUE_USAGE_HPP + +// Boost.Runtime.Parameter +#include +#include + +// Boost.Test +#include +#include + +#include + +// STL +// !! can we eliminate these includes? +#include + +namespace boost { + +namespace BOOST_TEST_UTILS_RUNTIME_PARAM_NAMESPACE { + +namespace cla { + +namespace rt_cla_detail { + +// ************************************************************************** // +// ************** argument_value_usage ************** // +// ************************************************************************** // + +// generic case +template +inline void +argument_value_usage( format_stream& fs, long, T* = 0 ) +{ + fs << BOOST_TEST_UTILS_RUNTIME_PARAM_CSTRING_LITERAL( "" ); +} + +//____________________________________________________________________________// + +// specialization for list of values +template +inline void +argument_value_usage( format_stream& fs, int, std::list* = 0 ) +{ + fs << BOOST_TEST_UTILS_RUNTIME_PARAM_CSTRING_LITERAL( "(, ..., )" ); +} + +//____________________________________________________________________________// + +// specialization for type bool +inline void +argument_value_usage( format_stream& fs, int, bool* = 0 ) +{ + fs << BOOST_TEST_UTILS_RUNTIME_PARAM_CSTRING_LITERAL( "yes|y|no|n" ); +} + +//____________________________________________________________________________// + +} // namespace rt_cla_detail + +} // namespace cla + +} // namespace BOOST_TEST_UTILS_RUNTIME_PARAM_NAMESPACE + +} // namespace boost + +#endif // BOOST_TEST_UTILS_RUNTIME_CLA_ARGUMENT_VALUE_USAGE_HPP diff --git a/include/boost/test/utils/runtime/cla/dual_name_parameter.cpp b/include/boost/test/utils/runtime/cla/dual_name_parameter.cpp new file mode 100644 index 00000000..ab034ff0 --- /dev/null +++ b/include/boost/test/utils/runtime/cla/dual_name_parameter.cpp @@ -0,0 +1,16 @@ +// (C) Copyright Gennadiy Rozental 2005-2014. +// Use, modification, and distribution are subject to 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 : offline implementation of generic parameter with dual naming +// *************************************************************************** + +#define BOOST_TEST_UTILS_RUNTIME_PARAM_INLINE +#include diff --git a/include/boost/test/utils/runtime/cla/dual_name_parameter.hpp b/include/boost/test/utils/runtime/cla/dual_name_parameter.hpp new file mode 100644 index 00000000..789b67ad --- /dev/null +++ b/include/boost/test/utils/runtime/cla/dual_name_parameter.hpp @@ -0,0 +1,98 @@ +// (C) Copyright Gennadiy Rozental 2005-2014. +// Use, modification, and distribution are subject to 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 : defines model of generic parameter with dual naming +// *************************************************************************** + +#ifndef BOOST_TEST_UTILS_RUNTIME_CLA_DUAL_NAME_PARAMETER_HPP +#define BOOST_TEST_UTILS_RUNTIME_CLA_DUAL_NAME_PARAMETER_HPP + +// Boost.Runtime.Parameter +#include + +#include +#include + +namespace boost { + +namespace BOOST_TEST_UTILS_RUNTIME_PARAM_NAMESPACE { + +namespace cla { + +// ************************************************************************** // +// ************** dual_name_policy ************** // +// ************************************************************************** // + +class dual_name_policy : public dual_id_policy { +public: + dual_name_policy(); + + // Accept modifier + template + void accept_modifier( Modifier const& m ) + { + if( m.has( prefix ) ) { + set_prefix( m[prefix] ); + m.erase( prefix ); + } + + if( m.has( name ) ) { + set_name( m[name] ); + m.erase( name ); + } + + if( m.has( separator ) ) { + set_separator( m[separator] ); + m.erase( separator ); + } + + dual_id_policy::accept_modifier( m ); + } +private: + void set_prefix( cstring ); + void set_name( cstring ); + void set_separator( cstring ); +}; + +// ************************************************************************** // +// ************** runtime::cla::dual_name_parameter ************** // +// ************************************************************************** // + +template +class dual_name_parameter_t : public basic_parameter { + typedef basic_parameter base; +public: + // Constructors + explicit dual_name_parameter_t( cstring name ) : base( name ) {} +}; + +//____________________________________________________________________________// + +BOOST_TEST_UTILS_RUNTIME_CLA_NAMED_PARAM_GENERATORS( dual_name_parameter ) + +//____________________________________________________________________________// + +} // namespace cla + +} // namespace BOOST_TEST_UTILS_RUNTIME_PARAM_NAMESPACE + +} // namespace boost + +#ifndef BOOST_TEST_UTILS_RUNTIME_PARAM_OFFLINE + +#ifndef BOOST_TEST_UTILS_RUNTIME_PARAM_INLINE +# define BOOST_TEST_UTILS_RUNTIME_PARAM_INLINE inline +#endif +# include + +#endif + +#endif // BOOST_TEST_UTILS_RUNTIME_CLA_DUAL_NAME_PARAMETER_HPP diff --git a/include/boost/test/utils/runtime/cla/dual_name_parameter.ipp b/include/boost/test/utils/runtime/cla/dual_name_parameter.ipp new file mode 100644 index 00000000..e39d132d --- /dev/null +++ b/include/boost/test/utils/runtime/cla/dual_name_parameter.ipp @@ -0,0 +1,90 @@ +// (C) Copyright Gennadiy Rozental 2005-2014. +// Use, modification, and distribution are subject to 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 : implements model of generic parameter with dual naming +// *************************************************************************** + +#ifndef BOOST_TEST_UTILS_RUNTIME_CLA_DUAL_NAME_PARAMETER_IPP +#define BOOST_TEST_UTILS_RUNTIME_CLA_DUAL_NAME_PARAMETER_IPP + +// Boost.Runtime.Parameter +#include +#include + +#include + +namespace boost { + +namespace BOOST_TEST_UTILS_RUNTIME_PARAM_NAMESPACE { + +namespace cla { + +// ************************************************************************** // +// ************** dual_name_policy ************** // +// ************************************************************************** // + +BOOST_TEST_UTILS_RUNTIME_PARAM_INLINE +dual_name_policy::dual_name_policy() +{ + m_primary.accept_modifier( prefix = BOOST_TEST_UTILS_RUNTIME_PARAM_CSTRING_LITERAL( "--" ) ); + m_secondary.accept_modifier( prefix = BOOST_TEST_UTILS_RUNTIME_PARAM_CSTRING_LITERAL( "-" ) ); +} + +//____________________________________________________________________________// + +namespace { + +template +inline void +split( string_name_policy& snp, char_name_policy& cnp, cstring src, K const& k ) +{ + cstring::iterator sep = std::find( src.begin(), src.end(), BOOST_TEST_UTILS_RUNTIME_PARAM_LITERAL( '|' ) ); + + if( sep != src.begin() ) + snp.accept_modifier( k = cstring( src.begin(), sep ) ); + + if( sep != src.end() ) + cnp.accept_modifier( k = cstring( sep+1, src.end() ) ); +} + +} // local namespace + +BOOST_TEST_UTILS_RUNTIME_PARAM_INLINE void +dual_name_policy::set_prefix( cstring src ) +{ + split( m_primary, m_secondary, src, prefix ); +} + +//____________________________________________________________________________// + +BOOST_TEST_UTILS_RUNTIME_PARAM_INLINE void +dual_name_policy::set_name( cstring src ) +{ + split( m_primary, m_secondary, src, name ); +} + +//____________________________________________________________________________// + +BOOST_TEST_UTILS_RUNTIME_PARAM_INLINE void +dual_name_policy::set_separator( cstring src ) +{ + split( m_primary, m_secondary, src, separator ); +} + +//____________________________________________________________________________// + +} // namespace cla + +} // namespace BOOST_TEST_UTILS_RUNTIME_PARAM_NAMESPACE + +} // namespace boost + +#endif // BOOST_TEST_UTILS_RUNTIME_CLA_DUAL_NAME_PARAMETER_IPP diff --git a/include/boost/test/utils/runtime/cla/fwd.hpp b/include/boost/test/utils/runtime/cla/fwd.hpp new file mode 100644 index 00000000..df029743 --- /dev/null +++ b/include/boost/test/utils/runtime/cla/fwd.hpp @@ -0,0 +1,55 @@ +// (C) Copyright Gennadiy Rozental 2005-2014. +// Use, modification, and distribution are subject to 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 : cla subsystem forward declarations +// *************************************************************************** + +#ifndef BOOST_TEST_UTILS_RUNTIME_CLA_FWD_HPP +#define BOOST_TEST_UTILS_RUNTIME_CLA_FWD_HPP + +// Boost.Runtime.Parameter +#include + +// Boost +#include + +namespace boost { + +namespace BOOST_TEST_UTILS_RUNTIME_PARAM_NAMESPACE { + +namespace cla { + +class parser; +class parameter; +typedef shared_ptr parameter_ptr; +class naming_policy; +typedef shared_ptr naming_policy_ptr; +class argv_traverser; + +namespace rt_cla_detail { + +template class const_generator; +template class ref_generator; + +template class assigner; + +class named_parameter_base; +class positional_parameter_base; + +} // namespace rt_cla_detail + +} // namespace cla + +} // namespace BOOST_TEST_UTILS_RUNTIME_PARAM_NAMESPACE + +} // namespace boost + +#endif // BOOST_TEST_UTILS_RUNTIME_CLA_FWD_HPP diff --git a/include/boost/test/utils/runtime/cla/id_policy.cpp b/include/boost/test/utils/runtime/cla/id_policy.cpp new file mode 100644 index 00000000..b000e26f --- /dev/null +++ b/include/boost/test/utils/runtime/cla/id_policy.cpp @@ -0,0 +1,16 @@ +// (C) Copyright Gennadiy Rozental 2005-2014. +// Use, modification, and distribution are subject to 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 : some generic identification policies offline implementation +// *************************************************************************** + +#define BOOST_TEST_UTILS_RUNTIME_PARAM_INLINE +#include diff --git a/include/boost/test/utils/runtime/cla/id_policy.hpp b/include/boost/test/utils/runtime/cla/id_policy.hpp new file mode 100644 index 00000000..3308b07c --- /dev/null +++ b/include/boost/test/utils/runtime/cla/id_policy.hpp @@ -0,0 +1,147 @@ +// (C) Copyright Gennadiy Rozental 2005-2014. +// Use, modification, and distribution are subject to 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 : some generic identification policies definition +// *************************************************************************** + +#ifndef BOOST_TEST_UTILS_RUNTIME_CLA_ID_POLICY_HPP +#define BOOST_TEST_UTILS_RUNTIME_CLA_ID_POLICY_HPP + +// Boost.Runtime.Parameter +#include + +#include +#include +#include + +#include + +// Boost.Test +#include +#include + +namespace boost { + +namespace BOOST_TEST_UTILS_RUNTIME_PARAM_NAMESPACE { + +namespace cla { + +// ************************************************************************** // +// ************** naming_policy_base ************** // +// ************************************************************************** // +// model: + +class basic_naming_policy : public identification_policy { +public: + // Public properties + unit_test::readwrite_property p_prefix; + unit_test::readwrite_property p_name; + unit_test::readwrite_property p_separator; + + // Policy interface + virtual bool responds_to( cstring name ) const { return p_name == name; } + virtual cstring id_2_report() const { return p_name.get(); } + virtual void usage_info( format_stream& fs ) const; + virtual bool matching( parameter const& p, argv_traverser& tr, bool primary ) const; + + // Accept modifier + template + void accept_modifier( Modifier const& m ) + { + nfp::optionally_assign( p_prefix.value, m, prefix ); + nfp::optionally_assign( p_name.value, m, name ); + nfp::optionally_assign( p_separator.value, m, separator ); + } + +protected: + explicit basic_naming_policy( rtti::id_t dyn_type ) + : identification_policy( dyn_type ) + {} + BOOST_TEST_UTILS_RUNTIME_PARAM_UNNEEDED_VIRTUAL ~basic_naming_policy() {} + + // Naming policy interface + virtual bool match_prefix( argv_traverser& tr ) const; + virtual bool match_name( argv_traverser& tr ) const; + virtual bool match_separator( argv_traverser& tr, bool optional_value ) const; +}; + +// ************************************************************************** // +// ************** dual_id_policy ************** // +// ************************************************************************** // + +template +class dual_id_policy : public identification_policy { +public: + // Constructor + dual_id_policy() + : identification_policy( rtti::type_id() ) + , m_primary() + , m_secondary() + {} + + // Policy interface + virtual bool responds_to( cstring name ) const + { + return m_primary.responds_to( name ) || m_secondary.responds_to( name ); + } + virtual bool conflict_with( identification_policy const& id_p ) const + { + return id_p.conflict_with( m_primary ) || id_p.conflict_with( m_secondary ); + } + virtual cstring id_2_report() const + { + return m_primary.id_2_report(); + } + virtual void usage_info( format_stream& fs ) const + { + fs << BOOST_TEST_UTILS_RUNTIME_PARAM_LITERAL( '{' ); + m_primary.usage_info( fs ); + fs << BOOST_TEST_UTILS_RUNTIME_PARAM_LITERAL( '|' ); + m_secondary.usage_info( fs ); + fs << BOOST_TEST_UTILS_RUNTIME_PARAM_LITERAL( '}' ); + } + virtual bool matching( parameter const& p, argv_traverser& tr, bool primary ) const + { + return m_primary.matching( p, tr, primary ) || m_secondary.matching( p, tr, primary ); + } + + // Accept modifier + template + void accept_modifier( Modifier const& m ) + { + m_primary.accept_modifier( m ); + m_secondary.accept_modifier( m ); + } + +protected: + BOOST_TEST_UTILS_RUNTIME_PARAM_UNNEEDED_VIRTUAL ~dual_id_policy() {} + + // Data members + PrimaryId m_primary; + SecondId m_secondary; +}; + +} // namespace cla + +} // namespace BOOST_TEST_UTILS_RUNTIME_PARAM_NAMESPACE + +} // namespace boost + +#ifndef BOOST_TEST_UTILS_RUNTIME_PARAM_OFFLINE + +#ifndef BOOST_TEST_UTILS_RUNTIME_PARAM_INLINE +# define BOOST_TEST_UTILS_RUNTIME_PARAM_INLINE inline +#endif +# include + +#endif + +#endif // BOOST_TEST_UTILS_RUNTIME_CLA_ID_POLICY_HPP diff --git a/include/boost/test/utils/runtime/cla/id_policy.ipp b/include/boost/test/utils/runtime/cla/id_policy.ipp new file mode 100644 index 00000000..879ccfd1 --- /dev/null +++ b/include/boost/test/utils/runtime/cla/id_policy.ipp @@ -0,0 +1,118 @@ +// (C) Copyright Gennadiy Rozental 2005-2014. +// Use, modification, and distribution are subject to 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 : some generic identification policies implementation +// *************************************************************************** + +#ifndef BOOST_TEST_UTILS_RUNTIME_CLA_ID_POLICY_IPP +#define BOOST_TEST_UTILS_RUNTIME_CLA_ID_POLICY_IPP + +// Boost.Runtime.Parameter +#include + +#include +#include + +namespace boost { + +namespace BOOST_TEST_UTILS_RUNTIME_PARAM_NAMESPACE { + +namespace cla { + +// ************************************************************************** // +// ************** basic_naming_policy ************** // +// ************************************************************************** // + +BOOST_TEST_UTILS_RUNTIME_PARAM_INLINE void +basic_naming_policy::usage_info( format_stream& fs ) const +{ + fs << p_prefix << p_name << p_separator; + + if( p_separator->empty() ) + fs << BOOST_TEST_UTILS_RUNTIME_PARAM_LITERAL( ' ' ); +} + +//____________________________________________________________________________// + +BOOST_TEST_UTILS_RUNTIME_PARAM_INLINE bool +basic_naming_policy::match_prefix( argv_traverser& tr ) const +{ + if( !tr.match_front( p_prefix.get() ) ) + return false; + + tr.trim( p_prefix->size() ); + return true; +} + +//____________________________________________________________________________// + +BOOST_TEST_UTILS_RUNTIME_PARAM_INLINE bool +basic_naming_policy::match_name( argv_traverser& tr ) const +{ + if( !tr.match_front( p_name.get() ) ) + return false; + + tr.trim( p_name->size() ); + return true; +} + +//____________________________________________________________________________// + +BOOST_TEST_UTILS_RUNTIME_PARAM_INLINE bool +basic_naming_policy::match_separator( argv_traverser& tr, bool optional_value ) const +{ + if( p_separator->empty() ) { + if( !tr.token().is_empty() ) + return false; + + tr.trim( 1 ); + } + else { + if( !tr.match_front( p_separator.get() ) ) { + // if parameter has optional value separator is optional as well + if( optional_value && ( tr.eoi() || tr.match_front( ' ' ) ) ) { + return true; + } + return false; + } + + tr.trim( p_separator->size() ); + } + + return true; +} + +//____________________________________________________________________________// + +BOOST_TEST_UTILS_RUNTIME_PARAM_INLINE bool +basic_naming_policy::matching( parameter const& p, argv_traverser& tr, bool ) const +{ + if( !match_prefix( tr ) ) + return false; + + if( !match_name( tr ) ) + return false; + + if( !match_separator( tr, p.p_optional_value ) ) + return false; + + return true; +} + +//____________________________________________________________________________// + +} // namespace cla + +} // namespace BOOST_TEST_UTILS_RUNTIME_PARAM_NAMESPACE + +} // namespace boost + +#endif // BOOST_TEST_UTILS_RUNTIME_CLA_ID_POLICY_IPP diff --git a/include/boost/test/utils/runtime/cla/iface/argument_factory.hpp b/include/boost/test/utils/runtime/cla/iface/argument_factory.hpp new file mode 100644 index 00000000..cbca713b --- /dev/null +++ b/include/boost/test/utils/runtime/cla/iface/argument_factory.hpp @@ -0,0 +1,51 @@ +// (C) Copyright Gennadiy Rozental 2005-2014. +// Use, modification, and distribution are subject to 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 : defines interface for argument_factory +// *************************************************************************** + +#ifndef BOOST_TEST_UTILS_RUNTIME_CLA_IFACE_ARGUMENT_FACTORY_HPP +#define BOOST_TEST_UTILS_RUNTIME_CLA_IFACE_ARGUMENT_FACTORY_HPP + +// Boost.Runtime.Parameter +#include +#include + +#include + +namespace boost { + +namespace BOOST_TEST_UTILS_RUNTIME_PARAM_NAMESPACE { + +namespace cla { + +// ************************************************************************** // +// ************** argument_factory ************** // +// ************************************************************************** // +// another name can be argument production policy + +class argument_factory { +public: + // Argument factory interface + virtual argument_ptr produce_using( parameter& p, argv_traverser& tr ) = 0; /// produce argument based on input + virtual argument_ptr produce_using( parameter& p, parser const& ) = 0; /// produce argument based on internal generator and/or values of other parameters + virtual void argument_usage_info( format_stream& fs ) = 0; /// argument value format information +protected: + BOOST_TEST_PROTECTED_VIRTUAL ~argument_factory() {} +}; + +} // namespace boost + +} // namespace BOOST_TEST_UTILS_RUNTIME_PARAM_NAMESPACE + +} // namespace cla + +#endif // BOOST_TEST_UTILS_RUNTIME_CLA_IFACE_ARGUMENT_FACTORY_HPP diff --git a/include/boost/test/utils/runtime/cla/iface/id_policy.hpp b/include/boost/test/utils/runtime/cla/iface/id_policy.hpp new file mode 100644 index 00000000..5fa13e6b --- /dev/null +++ b/include/boost/test/utils/runtime/cla/iface/id_policy.hpp @@ -0,0 +1,73 @@ +// (C) Copyright Gennadiy Rozental 2005-2014. +// Use, modification, and distribution are subject to 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 : defines interface for identification_policy +// *************************************************************************** + +#ifndef BOOST_TEST_UTILS_RUNTIME_CLA_IFACE_ID_POLICY_HPP +#define BOOST_TEST_UTILS_RUNTIME_CLA_IFACE_ID_POLICY_HPP + +// Boost.Runtime.Parameter +#include + +#include + +// Boost.Test +#include +#include + +namespace boost { + +namespace BOOST_TEST_UTILS_RUNTIME_PARAM_NAMESPACE { + +namespace cla { + +// ************************************************************************** // +// ************** identification_policy ************** // +// ************************************************************************** // + +#ifdef BOOST_MSVC +# pragma warning(push) +# pragma warning(disable:4244) +#endif + +class identification_policy { +public: + // Public properties + unit_test::readwrite_property p_type_id; + + // Policy interface + virtual bool responds_to( cstring name ) const = 0; + virtual cstring id_2_report() const = 0; + virtual void usage_info( format_stream& fs ) const = 0; + virtual bool matching( parameter const& p, argv_traverser& tr, bool primary ) const = 0; + + virtual bool conflict_with( identification_policy const& ) const = 0; + +protected: + // Constructor + explicit identification_policy( rtti::id_t dyn_type ) + : p_type_id( dyn_type ) + {} + BOOST_TEST_PROTECTED_VIRTUAL ~identification_policy() {} +}; + +#ifdef BOOST_MSVC +# pragma warning(pop) +#endif + +} // namespace cla + +} // namespace BOOST_TEST_UTILS_RUNTIME_PARAM_NAMESPACE + +} // namespace boost + +#endif // BOOST_TEST_UTILS_RUNTIME_CLA_IFACE_ID_POLICY_HPP diff --git a/include/boost/test/utils/runtime/cla/modifier.hpp b/include/boost/test/utils/runtime/cla/modifier.hpp new file mode 100644 index 00000000..4b55536b --- /dev/null +++ b/include/boost/test/utils/runtime/cla/modifier.hpp @@ -0,0 +1,69 @@ +// (C) Copyright Gennadiy Rozental 2005-2014. +// Use, modification, and distribution are subject to 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 : parameter modifiers +// *************************************************************************** + +#ifndef BOOST_TEST_UTILS_RUNTIME_CLA_MODIFIER_HPP +#define BOOST_TEST_UTILS_RUNTIME_CLA_MODIFIER_HPP + +// Boost.Runtime.Parameter +#include + +// Boost.Test +#include + +namespace boost { + +namespace BOOST_TEST_UTILS_RUNTIME_PARAM_NAMESPACE { + +namespace cla { + +// ************************************************************************** // +// ************** environment variable modifiers ************** // +// ************************************************************************** // + +namespace { + +nfp::typed_keyword optional_m; +nfp::named_parameter optional( true ); +nfp::typed_keyword required_m; +nfp::named_parameter required( true ); +nfp::typed_keyword multiplicable_m; +nfp::named_parameter multiplicable( true ); +nfp::typed_keyword guess_name_m; +nfp::named_parameter guess_name( true ); +nfp::typed_keyword ignore_mismatch_m; +nfp::named_parameter ignore_mismatch( true ); +nfp::typed_keyword optional_value_m; +nfp::named_parameter optional_value( true ); + +nfp::typed_keyword input_separator; +nfp::typed_keyword prefix; +nfp::typed_keyword name; +nfp::typed_keyword separator; +nfp::typed_keyword description; +nfp::typed_keyword default_refer_to; + +nfp::keyword default_value; +nfp::keyword handler; +nfp::keyword interpreter; +nfp::keyword assign_to; + +} // local namespace + +} // namespace cla + +} // namespace BOOST_TEST_UTILS_RUNTIME_PARAM_NAMESPACE + +} // namespace boost + +#endif // BOOST_TEST_UTILS_RUNTIME_CLA_MODIFIER_HPP diff --git a/include/boost/test/utils/runtime/cla/named_parameter.cpp b/include/boost/test/utils/runtime/cla/named_parameter.cpp new file mode 100644 index 00000000..7e94722d --- /dev/null +++ b/include/boost/test/utils/runtime/cla/named_parameter.cpp @@ -0,0 +1,16 @@ +// (C) Copyright Gennadiy Rozental 2005-2014. +// Use, modification, and distribution are subject to 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 : offline implementation of named parameter +// *************************************************************************** + +#define BOOST_TEST_UTILS_RUNTIME_PARAM_INLINE +#include diff --git a/include/boost/test/utils/runtime/cla/named_parameter.hpp b/include/boost/test/utils/runtime/cla/named_parameter.hpp new file mode 100644 index 00000000..be3f9c57 --- /dev/null +++ b/include/boost/test/utils/runtime/cla/named_parameter.hpp @@ -0,0 +1,95 @@ +// (C) Copyright Gennadiy Rozental 2005-2014. +// Use, modification, and distribution are subject to 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 : defines model of named parameter +// *************************************************************************** + +#ifndef BOOST_TEST_UTILS_RUNTIME_CLA_NAMED_PARAMETER_HPP +#define BOOST_TEST_UTILS_RUNTIME_CLA_NAMED_PARAMETER_HPP + +// Boost.Runtime.Parameter +#include + +#include +#include + +namespace boost { + +namespace BOOST_TEST_UTILS_RUNTIME_PARAM_NAMESPACE { + +namespace cla { + +// ************************************************************************** // +// ************** string_name_policy ************** // +// ************************************************************************** // + +class string_name_policy : public basic_naming_policy { +public: + // Constructor + string_name_policy(); + BOOST_TEST_UTILS_RUNTIME_PARAM_UNNEEDED_VIRTUAL ~string_name_policy() {} + + // policy interface + virtual bool responds_to( cstring name ) const; + virtual bool conflict_with( identification_policy const& ) const; + + // Accept modifier + template + void accept_modifier( Modifier const& m ) + { + basic_naming_policy::accept_modifier( m ); + + if( m.has( guess_name_m ) ) + m_guess_name = true; + } + +private: + // Naming policy interface + virtual bool match_name( argv_traverser& tr ) const; + + // Data members + bool m_guess_name; +}; + +// ************************************************************************** // +// ************** runtime::cla::named_parameter ************** // +// ************************************************************************** // + +template +class named_parameter_t : public basic_parameter { + typedef basic_parameter base; +public: + // Constructors + explicit named_parameter_t( cstring name ) : base( name ) {} +}; + +//____________________________________________________________________________// + +BOOST_TEST_UTILS_RUNTIME_CLA_NAMED_PARAM_GENERATORS( named_parameter ) + +//____________________________________________________________________________// + +} // namespace cla + +} // namespace BOOST_TEST_UTILS_RUNTIME_PARAM_NAMESPACE + +} // namespace boost + +#ifndef BOOST_TEST_UTILS_RUNTIME_PARAM_OFFLINE + +#ifndef BOOST_TEST_UTILS_RUNTIME_PARAM_INLINE +# define BOOST_TEST_UTILS_RUNTIME_PARAM_INLINE inline +#endif +# include + +#endif + +#endif // BOOST_TEST_UTILS_RUNTIME_CLA_NAMED_PARAMETER_HPP diff --git a/include/boost/test/utils/runtime/cla/named_parameter.ipp b/include/boost/test/utils/runtime/cla/named_parameter.ipp new file mode 100644 index 00000000..e59ebdf8 --- /dev/null +++ b/include/boost/test/utils/runtime/cla/named_parameter.ipp @@ -0,0 +1,129 @@ +// (C) Copyright Gennadiy Rozental 2005-2014. +// Use, modification, and distribution are subject to 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 : implements model of named parameter +// *************************************************************************** + +#ifndef BOOST_TEST_UTILS_RUNTIME_CLA_NAMED_PARAMETER_IPP +#define BOOST_TEST_UTILS_RUNTIME_CLA_NAMED_PARAMETER_IPP + +// Boost.Runtime.Parameter +#include + +#include +#include + +// Boost.Test +#include + +namespace boost { + +namespace BOOST_TEST_UTILS_RUNTIME_PARAM_NAMESPACE { + +namespace cla { + +// ************************************************************************** // +// ************** string_name_policy ************** // +// ************************************************************************** // + +BOOST_TEST_UTILS_RUNTIME_PARAM_INLINE +string_name_policy::string_name_policy() +: basic_naming_policy( rtti::type_id() ) +, m_guess_name( false ) +{ + assign_op( p_prefix.value, BOOST_TEST_UTILS_RUNTIME_PARAM_CSTRING_LITERAL( "-" ), 0 ); +} + +//____________________________________________________________________________// + +BOOST_TEST_UTILS_RUNTIME_PARAM_INLINE bool +string_name_policy::responds_to( cstring name ) const +{ + std::pair mm_pos; + + mm_pos = unit_test::mismatch( name.begin(), name.end(), p_name->begin(), p_name->end() ); + + return mm_pos.first == name.end() && (m_guess_name || (mm_pos.second == p_name->end()) ); +} + +//____________________________________________________________________________// + +#ifdef BOOST_MSVC +# pragma warning(push) +# pragma warning(disable:4244) +#endif + +BOOST_TEST_UTILS_RUNTIME_PARAM_INLINE bool +string_name_policy::conflict_with( identification_policy const& id ) const +{ + if( id.p_type_id == p_type_id ) { + string_name_policy const& snp = static_cast( id ); + + if( p_name->empty() || snp.p_name->empty() ) + return false; + + if( p_prefix != snp.p_prefix ) + return false; + + std::pair mm_pos = + unit_test::mismatch( p_name->begin(), p_name->end(), snp.p_name->begin(), snp.p_name->end() ); + + return mm_pos.first != p_name->begin() && // there is common substring + ((m_guess_name && (mm_pos.second == snp.p_name->end()) ) || // that match other guy and I am guessing + (snp.m_guess_name && (mm_pos.first == p_name->end()) )); // or me and the other guy is + } + + if( id.p_type_id == rtti::type_id() ) { + char_name_policy const& cnp = static_cast( id ); + + return m_guess_name && + (p_prefix == cnp.p_prefix) && + unit_test::first_char( cstring( p_name ) ) == unit_test::first_char( cstring( cnp.p_name ) ); + } + + return false; +} + +#ifdef BOOST_MSVC +# pragma warning(pop) +#endif + +//____________________________________________________________________________// + +BOOST_TEST_UTILS_RUNTIME_PARAM_INLINE bool +string_name_policy::match_name( argv_traverser& tr ) const +{ + if( !m_guess_name ) + return basic_naming_policy::match_name( tr ); + + cstring in = tr.input(); + + std::pair mm_pos; + + mm_pos = unit_test::mismatch( in.begin(), in.end(), p_name->begin(), p_name->end() ); + + if( mm_pos.first == in.begin() ) + return false; + + tr.trim( static_cast(mm_pos.first - in.begin()) ); + + return true; +} + +//____________________________________________________________________________// + +} // namespace cla + +} // namespace BOOST_TEST_UTILS_RUNTIME_PARAM_NAMESPACE + +} // namespace boost + +#endif // BOOST_TEST_UTILS_RUNTIME_CLA_NAMED_PARAMETER_IPP diff --git a/include/boost/test/utils/runtime/cla/parameter.hpp b/include/boost/test/utils/runtime/cla/parameter.hpp new file mode 100644 index 00000000..9e26d250 --- /dev/null +++ b/include/boost/test/utils/runtime/cla/parameter.hpp @@ -0,0 +1,151 @@ +// (C) Copyright Gennadiy Rozental 2005-2014. +// Use, modification, and distribution are subject to 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 : defines model of formal parameter +// *************************************************************************** + +#ifndef BOOST_TEST_UTILS_RUNTIME_CLA_PARAMETER_HPP +#define BOOST_TEST_UTILS_RUNTIME_CLA_PARAMETER_HPP + +// Boost.Runtime.Parameter +#include + +#include +#include +#include + +#include +#include +#include +#include + +// Boost.Test +#include + +namespace boost { + +namespace BOOST_TEST_UTILS_RUNTIME_PARAM_NAMESPACE { + +namespace cla { + +// ************************************************************************** // +// ************** runtime::cla::parameter ************** // +// ************************************************************************** // + +class parameter : public BOOST_TEST_UTILS_RUNTIME_PARAM_NAMESPACE::parameter { +public: + parameter( identification_policy& ID, argument_factory& F, bool optional_value = false ) + : p_optional( false ) + , p_multiplicable( false ) + , p_optional_value( optional_value ) + , m_id_policy( ID ) + , m_arg_factory( F ) + {} + + // Destructor + virtual ~parameter() {} + + unit_test::readwrite_property p_optional; + unit_test::readwrite_property p_multiplicable; + unit_test::readwrite_property p_optional_value; + unit_test::readwrite_property p_description; + + // parameter properties modification + template + void accept_modifier( Modifier const& m ) + { + if( m.has( optional_m ) ) + p_optional.value = true; + + if( m.has( required_m ) ) + p_optional.value = false; + + if( m.has( multiplicable_m ) ) + p_multiplicable.value = true; + + if( m.has( optional_value_m ) ) + p_optional_value.value = true; + + nfp::optionally_assign( p_description.value, m, description ); + } + + // access methods + bool has_argument() const { return !!m_actual_argument; } + argument const& actual_argument() const { return *m_actual_argument; } + argument_ptr actual_argument() { return m_actual_argument; } + void reset() { m_actual_argument.reset(); } + + + // identification interface + bool responds_to( cstring name ) const { return m_id_policy.responds_to( name ); } + bool conflict_with( parameter const& p ) const + { + return (id_2_report() == p.id_2_report() && !id_2_report().is_empty()) || + m_id_policy.conflict_with( p.m_id_policy ) || + ((m_id_policy.p_type_id != p.m_id_policy.p_type_id) && p.m_id_policy.conflict_with( m_id_policy )); + } + cstring id_2_report() const { return m_id_policy.id_2_report(); } + void usage_info( format_stream& fs ) const + { + m_id_policy.usage_info( fs ); + if( p_optional_value ) + fs << BOOST_TEST_UTILS_RUNTIME_PARAM_LITERAL( '[' ); + + m_arg_factory.argument_usage_info( fs ); + + if( p_optional_value ) + fs << BOOST_TEST_UTILS_RUNTIME_PARAM_LITERAL( ']' ); + } + + // argument match/produce based on input + bool matching( argv_traverser& tr, bool primary ) const + { + return m_id_policy.matching( *this, tr, primary ); + } + + // argument production based on different source + void produce_argument( argv_traverser& tr ) + { + m_id_policy.matching( *this, tr, true ); // !! can we save this position somehow + m_actual_argument = m_arg_factory.produce_using( *this, tr ); + } + void produce_argument( parser const& p ) + { + m_actual_argument = m_arg_factory.produce_using( *this, p ); + } + +private: + //Data members + identification_policy& m_id_policy; + argument_factory& m_arg_factory; + argument_ptr m_actual_argument; +}; + +//____________________________________________________________________________// + +template +inline shared_ptr +operator-( shared_ptr p, Modifier const& m ) +{ + p->accept_modifier( m ); + + return p; +} + +//____________________________________________________________________________// + +} // namespace cla + +} // namespace BOOST_TEST_UTILS_RUNTIME_PARAM_NAMESPACE + +} // namespace boost + +#endif // BOOST_TEST_UTILS_RUNTIME_CLA_PARAMETER_HPP diff --git a/include/boost/test/utils/runtime/cla/parser.cpp b/include/boost/test/utils/runtime/cla/parser.cpp new file mode 100644 index 00000000..8efc17d3 --- /dev/null +++ b/include/boost/test/utils/runtime/cla/parser.cpp @@ -0,0 +1,18 @@ +// (C) Copyright Gennadiy Rozental 2005-2014. +// Use, modification, and distribution are subject to 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 : offline implementation for parser +// *************************************************************************** + +#include + +#define BOOST_TEST_UTILS_RUNTIME_PARAM_INLINE +#include diff --git a/include/boost/test/utils/runtime/cla/parser.hpp b/include/boost/test/utils/runtime/cla/parser.hpp index 9017cf5b..ffe09e4a 100644 --- a/include/boost/test/utils/runtime/cla/parser.hpp +++ b/include/boost/test/utils/runtime/cla/parser.hpp @@ -1,4 +1,4 @@ -// (C) Copyright Gennadiy Rozental 2005-2015. +// (C) Copyright Gennadiy Rozental 2005-2014. // Use, modification, and distribution are subject to 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) @@ -15,95 +15,59 @@ #ifndef BOOST_TEST_UTILS_RUNTIME_CLA_PARSER_HPP #define BOOST_TEST_UTILS_RUNTIME_CLA_PARSER_HPP -// Boost.Test Runtime parameters +// Boost.Runtime.Parameter +#include +#include #include -#include -#include +#include +#include #include -// Boost.Test -#include -#include -#include +// Boost +#include // STL -#include - -#include +#include namespace boost { -namespace runtime { + +namespace BOOST_TEST_UTILS_RUNTIME_PARAM_NAMESPACE { + namespace cla { // ************************************************************************** // -// ************** runtime::cla::parameter_trie ************** // +// ************** runtime::cla::parser ************** // // ************************************************************************** // -namespace rt_cla_detail { +namespace cla_detail { -struct parameter_trie; -typedef shared_ptr parameter_trie_ptr; -typedef std::map trie_per_char; -typedef std::vector> param_cla_id_list; +template +class global_mod_parser { +public: + global_mod_parser( parser& p, Modifier const& m ) + : m_parser( p ) + , m_modifiers( m ) + {} -struct parameter_trie { - parameter_trie() : m_has_final_candidate( false ) {} - - /// If subtrie corresponding to the char c exists returns it otherwise creates new - parameter_trie_ptr make_subtrie( char c ) + template + global_mod_parser const& + operator<<( shared_ptr param ) const { - trie_per_char::const_iterator it = m_subtrie.find( c ); + param->accept_modifier( m_modifiers ); - if( it == m_subtrie.end() ) - it = m_subtrie.insert( std::make_pair( c, parameter_trie_ptr( new parameter_trie ) ) ).first; + m_parser << param; - return it->second; + return *this; } - /// Creates series of sub-tries per characters in a string - parameter_trie_ptr make_subtrie( cstring s ) - { - parameter_trie_ptr res; - - BOOST_TEST_FOREACH( char, c, s ) - res = (res ? res->make_subtrie( c ) : make_subtrie( c )); - - return res; - } - - /// Registers candidate parameter for this subtrie. If final, it needs to be unique - void add_candidate_id( parameter_cla_id const& param_id, basic_param_ptr param_candidate, bool final ) - { - BOOST_TEST_I_ASSRT( !m_has_final_candidate && (!final || m_id_candidates.empty()), - conflicting_param() << "Parameter cla id " << param_id.m_tag << " conflicts with the " - << "parameter cla id " << m_id_candidates.back().get().m_tag ); - - m_has_final_candidate = final; - m_id_candidates.push_back( param_id ); - - if( m_id_candidates.size() == 1 ) - m_param_candidate = param_candidate; - else - m_param_candidate.reset(); - } - - /// Gets subtrie for specified char if present or nullptr otherwise - parameter_trie_ptr get_subtrie( char c ) const - { - trie_per_char::const_iterator it = m_subtrie.find( c ); - - return it != m_subtrie.end() ? it->second : parameter_trie_ptr(); - } - - // Data members - trie_per_char m_subtrie; - param_cla_id_list m_id_candidates; - basic_param_ptr m_param_candidate; - bool m_has_final_candidate; +private: + // Data members; + parser& m_parser; + Modifier const& m_modifiers; }; -} // namespace rt_cla_detail +} // ************************************************************************** // // ************** runtime::cla::parser ************** // @@ -111,339 +75,84 @@ struct parameter_trie { class parser { public: - /// Initializes a parser and builds internal trie representation used for - /// parsing based on the supplied parameters - template - parser( parameters_store const& parameters, Modifiers const& m = nfp::no_params ) + typedef std::list::const_iterator param_iterator; + typedef std::list::size_type param_size_type; + + // Constructor + explicit parser( cstring program_name = cstring() ); + + // parameter list construction interface + parser& operator<<( parameter_ptr param ); + + // parser and global parameters modifiers + template + cla_detail::global_mod_parser + operator-( Modifier const& m ) { - nfp::opt_assign( m_end_of_param_indicator, m, end_of_params ); - nfp::opt_assign( m_negation_prefix, m, negation_prefix ); + nfp::optionally_assign( m_traverser.p_separator.value, m, input_separator ); + nfp::optionally_assign( m_traverser.p_ignore_mismatch.value, m, ignore_mismatch_m ); - BOOST_TEST_I_ASSRT( std::all_of( m_end_of_param_indicator.begin(), - m_end_of_param_indicator.end(), - parameter_cla_id::valid_prefix_char ), - invalid_cla_id() << "End of parameters indicator can only consist of prefix characters." ); - - BOOST_TEST_I_ASSRT( std::all_of( m_negation_prefix.begin(), - m_negation_prefix.end(), - parameter_cla_id::valid_name_char ), - invalid_cla_id() << "Negation prefix can only consist of prefix characters." ); - - build_trie( parameters ); + return cla_detail::global_mod_parser( *this, m ); } // input processing method - int - parse( int argc, char** argv, runtime::arguments_store& res ) + void parse( int& argc, char_type** argv ); + + // parameters access + param_iterator first_param() const; + param_iterator last_param() const; + param_size_type num_params() const { return m_parameters.size(); } + void reset(); + + // arguments access + const_argument_ptr operator[]( cstring string_id ) const; + cstring get( cstring string_id ) const; + + template + T const& get( cstring string_id ) const { - // save program name for help message - m_program_name = argv[0]; - cstring path_sep( "\\/" ); + return arg_value( valid_argument( string_id ) ); + } - auto it = unit_test::find_last_of( m_program_name.begin(), m_program_name.end(), - path_sep.begin(), path_sep.end() ); - if( it != m_program_name.end() ) - m_program_name.trim_left( it + 1 ); + template + void get( cstring string_id, boost::optional& res ) const + { + const_argument_ptr actual_arg = (*this)[string_id]; - // Set up the traverser - argv_traverser tr( argc, (char const**)argv ); - - // Loop till we reach end of input - while( !tr.eoi() ) { - cstring curr_token = tr.current_token(); - - cstring prefix; - cstring name; - cstring value_separator; - bool negative_form = false; - - // Perform format validations and split the argument into prefix, name and separator - // False return value indicates end of params indicator is met - if( !validate_token_format( curr_token, prefix, name, value_separator, negative_form ) ) { - // get rid of "end of params" token - tr.get_token(); - break; - } - - // Locate trie corresponding to found prefix and skip it in the input - trie_ptr curr_trie = m_param_trie[prefix]; - - BOOST_TEST_I_ASSRT( curr_trie, - format_error() << "Unrecognized parameter prefix in the argument " - << curr_token ); - - tr.skip( prefix.size() ); - - // Locate parameter based on a name and skip it in the input - auto locate_res = locate_parameter( curr_trie, name, curr_token ); - parameter_cla_id const& found_id = locate_res.first; - basic_param_ptr found_param = locate_res.second; - - if( negative_form ) { - BOOST_TEST_I_ASSRT( found_id.m_negatable, - format_error( found_param->p_name ) - << "Parameter tag " << found_id.m_tag << " is not negatable." ); - - tr.skip( m_negation_prefix.size() ); - } - - tr.skip( name.size() ); - - cstring value; - - // Skip validations if parameter has optional value and we are at the end of token - if( !value_separator.is_empty() || !found_param->p_has_optional_value ) { - // Validate and skip value separator in the input - BOOST_TEST_I_ASSRT( found_id.m_value_separator == value_separator, - format_error( found_param->p_name ) - << "Invalid separator for the parameter " - << found_param->p_name - << " in the argument " << curr_token ); - - tr.skip( value_separator.size() ); - - // Deduce value source - value = tr.get_token(); - - BOOST_TEST_I_ASSRT( !value.is_empty(), - format_error( found_param->p_name ) - << "Missing an argument value for the parameter " - << found_param->p_name - << " in the argument " << curr_token ); - } - - // Validate against argument duplication - BOOST_TEST_I_ASSRT( !res.has( found_param->p_name ) || found_param->p_repeatable, - duplicate_arg( found_param->p_name ) - << "Duplicate argument value for the parameter " - << found_param->p_name - << " in the argument " << curr_token ); - - // Produce argument value - found_param->produce_argument( value, negative_form, res ); - } - - // generate the remainder and return it's size - return tr.remainder(); + if( actual_arg ) + res = arg_value( *actual_arg ); + else + res.reset(); } // help/usage - void - usage( std::ostream& ostr, cstring param_name = cstring() ) - { - if( !param_name.is_empty() ) { - auto 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 << "\nFor detailed help on Boost.Test parameters use:\n" - << " " << m_program_name << " --help\n" - << "or\n" - << " " << m_program_name << " --help=\n"; - } - - void - help( std::ostream& ostr, parameters_store const& parameters, cstring param_name ) - { - if( !param_name.is_empty() ) { - auto param = locate_parameter( m_param_trie[help_prefix], param_name, "" ).second; - param->help( ostr, m_negation_prefix ); - 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]..."; - - 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."; - - 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 << "\nUse --help= to display detailed help for specific parameter.\n"; - } + void usage( out_stream& ostr ); + void help( out_stream& ostr ); private: - typedef rt_cla_detail::parameter_trie_ptr trie_ptr; - typedef rt_cla_detail::trie_per_char trie_per_char; - typedef std::map str_to_trie; - - void - build_trie( parameters_store const& parameters ) - { - // Iterate over all parameters - BOOST_TEST_FOREACH( parameters_store::storage_type::value_type const&, v, parameters.all() ) { - basic_param_ptr param = v.second; - - // Register all parameter's ids in trie. - BOOST_TEST_FOREACH( parameter_cla_id const&, id, param->cla_ids() ) { - // This is the trie corresponding to the prefix. - trie_ptr next_trie = m_param_trie[id.m_prefix]; - if( !next_trie ) - next_trie = m_param_trie[id.m_prefix] = trie_ptr( new rt_cla_detail::parameter_trie ); - - // Build the trie, by following name's characters - // and register this parameter as candidate on each level - for( size_t index = 0; index < id.m_tag.size(); ++index ) { - next_trie = next_trie->make_subtrie( id.m_tag[index] ); - - next_trie->add_candidate_id( id, param, index == (id.m_tag.size() - 1) ); - } - } - } - } - - bool - validate_token_format( cstring token, cstring& prefix, cstring& name, cstring& separator, bool& negative_form ) - { - // Match prefix - auto it = token.begin(); - while( it != token.end() && parameter_cla_id::valid_prefix_char( *it ) ) - ++it; - - prefix.assign( token.begin(), it ); - - // Match name - while( it != token.end() && parameter_cla_id::valid_name_char( *it ) ) - ++it; - - name.assign( prefix.end(), it ); - - if( name.empty() ) { - if( !prefix.is_empty() && prefix == m_end_of_param_indicator ) - return false; - - BOOST_TEST_I_THROW( format_error() << "Invalid format for an actual argument " << token ); - } - - // Match value separator - while( it != token.end() && parameter_cla_id::valid_separator_char(*it) ) - ++it; - - separator.assign( name.end(), it ); - - // Match negation prefix - negative_form = !m_negation_prefix.empty() && ( name.substr( 0, m_negation_prefix.size() ) == m_negation_prefix ); - if( negative_form ) - name.trim_left( m_negation_prefix.size() ); - - return true; - } - - typedef std::pair locate_result; - - locate_result - locate_parameter( trie_ptr curr_trie, cstring name, cstring token ) - { - std::vector typo_candidates; - std::vector next_typo_candidates; - trie_ptr next_trie; - - BOOST_TEST_FOREACH( char, c, name ) { - if( curr_trie ) { - // locate next subtrie corresponding to the char - next_trie = curr_trie->get_subtrie( c ); - - if( next_trie ) - curr_trie = next_trie; - else { - // Initiate search for typo candicates. We will account for 'wrong char' typo - // 'missing char' typo and 'extra char' typo - BOOST_TEST_FOREACH( trie_per_char::value_type const&, typo_cand, curr_trie->m_subtrie ) { - // 'wrong char' typo - typo_candidates.push_back( typo_cand.second ); - - // 'missing char' typo - if( next_trie = typo_cand.second->get_subtrie( c ) ) - typo_candidates.push_back( next_trie ); - } - - // 'extra char' typo - typo_candidates.push_back( curr_trie ); - - curr_trie.reset(); - } - } - else { - // go over existing typo candidates and see if they are still viable - BOOST_TEST_FOREACH( trie_ptr, typo_cand, typo_candidates ) { - trie_ptr next_typo_cand = typo_cand->get_subtrie( c ); - - if( next_typo_cand ) - next_typo_candidates.push_back( next_typo_cand ); - } - - next_typo_candidates.swap( typo_candidates ); - next_typo_candidates.clear(); - } - } - - if( !curr_trie ) { - std::vector typo_candidate_names; - std::unordered_set unique_typo_candidate; - typo_candidate_names.reserve( typo_candidates.size() ); - unique_typo_candidate.reserve( typo_candidates.size() ); - - BOOST_TEST_FOREACH( trie_ptr, trie_cand, typo_candidates ) { - // avoid ambiguos candidate trie - if( trie_cand->m_id_candidates.size() > 1 ) - continue; - - BOOST_TEST_FOREACH( parameter_cla_id const&, param_cand, trie_cand->m_id_candidates ) { - if( !unique_typo_candidate.insert( ¶m_cand ).second ) - continue; - - typo_candidate_names.push_back( param_cand.m_tag ); - } - } - - BOOST_TEST_I_THROW( unrecognized_param( std::move(typo_candidate_names) ) - << "An unrecognized parameter in the argument " - << token ); - } - - if( curr_trie->m_id_candidates.size() > 1 ) { - std::vector amb_names; - BOOST_TEST_FOREACH( parameter_cla_id const&, param_id, curr_trie->m_id_candidates ) - amb_names.push_back( param_id.m_tag ); - - BOOST_TEST_I_THROW( ambiguous_param( std::move( amb_names ) ) << - "An ambiguous parameter name in the argument " << token ); - } - - return locate_result( curr_trie->m_id_candidates.back().get(), curr_trie->m_param_candidate ); - } + argument const& valid_argument( cstring string_id ) const; // Data members - cstring m_program_name; - std::string m_end_of_param_indicator; - std::string m_negation_prefix; - str_to_trie m_param_trie; + argv_traverser m_traverser; + std::list m_parameters; + dstring m_program_name; }; +//____________________________________________________________________________// + } // namespace cla -} // namespace runtime + +} // namespace BOOST_TEST_UTILS_RUNTIME_PARAM_NAMESPACE + } // namespace boost -#include +#ifndef BOOST_TEST_UTILS_RUNTIME_PARAM_OFFLINE + +#ifndef BOOST_TEST_UTILS_RUNTIME_PARAM_INLINE +# define BOOST_TEST_UTILS_RUNTIME_PARAM_INLINE inline +#endif +# include + +#endif #endif // BOOST_TEST_UTILS_RUNTIME_CLA_PARSER_HPP diff --git a/include/boost/test/utils/runtime/cla/parser.ipp b/include/boost/test/utils/runtime/cla/parser.ipp new file mode 100644 index 00000000..b8a4ca46 --- /dev/null +++ b/include/boost/test/utils/runtime/cla/parser.ipp @@ -0,0 +1,267 @@ +// (C) Copyright Gennadiy Rozental 2005-2014. +// Use, modification, and distribution are subject to 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 : implements parser - public interface for CLA parsing and accessing +// *************************************************************************** + +#ifndef BOOST_TEST_UTILS_RUNTIME_CLA_PARSER_IPP +#define BOOST_TEST_UTILS_RUNTIME_CLA_PARSER_IPP + +// Boost.Runtime.Parameter +#include +#include +#include + +#include +#include +#include +#include +#include + +// Boost.Test +#include +#include + +// Boost +#include + +namespace boost { + +namespace BOOST_TEST_UTILS_RUNTIME_PARAM_NAMESPACE { + +namespace cla { + +// ************************************************************************** // +// ************** runtime::cla::parser ************** // +// ************************************************************************** // + +BOOST_TEST_UTILS_RUNTIME_PARAM_INLINE +parser::parser( cstring program_name ) +{ + assign_op( m_program_name, program_name, 0 ); +} + +//____________________________________________________________________________// + +BOOST_TEST_UTILS_RUNTIME_PARAM_INLINE parser::param_iterator +parser::first_param() const +{ + return m_parameters.begin(); +} + +//____________________________________________________________________________// + +BOOST_TEST_UTILS_RUNTIME_PARAM_INLINE parser::param_iterator +parser::last_param() const +{ + return m_parameters.end(); +} + +//____________________________________________________________________________// + +BOOST_TEST_UTILS_RUNTIME_PARAM_INLINE argument const& +parser::valid_argument( cstring string_id ) const +{ + const_argument_ptr arg = (*this)[string_id]; + + BOOST_TEST_UTILS_RUNTIME_PARAM_VALIDATE_LOGIC( !!arg, "Actual argument for parameter " << string_id << " is not present" ); + + return *arg; +} + +//____________________________________________________________________________// + +BOOST_TEST_UTILS_RUNTIME_PARAM_INLINE parser& +parser::operator<<( parameter_ptr new_param ) +{ + BOOST_TEST_FOREACH( parameter_ptr, old_param, m_parameters ) { + BOOST_TEST_UTILS_RUNTIME_PARAM_VALIDATE_LOGIC( !old_param->conflict_with( *new_param ), + BOOST_TEST_UTILS_RUNTIME_PARAM_LITERAL( "Definition of parameter " ) << new_param->id_2_report() << + BOOST_TEST_UTILS_RUNTIME_PARAM_LITERAL( " conflicts with defintion of parameter " ) << old_param->id_2_report() ); + } + + m_parameters.push_back( new_param ); + + return *this; +} + +//____________________________________________________________________________// + +BOOST_TEST_UTILS_RUNTIME_PARAM_INLINE void +parser::parse( int& argc, char_type** argv ) +{ + if( m_program_name.empty() ) { + m_program_name.assign( argv[0] ); + dstring::size_type pos = m_program_name.find_last_of( BOOST_TEST_UTILS_RUNTIME_PARAM_LITERAL( "/\\" ) ); + + if( pos != static_cast(cstring::npos) ) + m_program_name.erase( 0, pos+1 ); + } + + m_traverser.init( argc, argv ); + + BOOST_TEST_IMPL_TRY { + while( !m_traverser.eoi() ) { + parameter_ptr found_param; + + BOOST_TEST_UTILS_RUNTIME_PARAM_TRACE( "Total " << m_parameters.size() << " parameters registered" ); + + BOOST_TEST_FOREACH( parameter_ptr const&, curr_param, m_parameters ) { + BOOST_TEST_UTILS_RUNTIME_PARAM_TRACE( "Try parameter " << curr_param->id_2_report() ); + + if( curr_param->matching( m_traverser, !found_param ) ) { + BOOST_TEST_UTILS_RUNTIME_PARAM_TRACE( "Match found" ); + BOOST_TEST_UTILS_RUNTIME_CLA_VALIDATE_INPUT( !found_param, (m_traverser.rollback(),m_traverser), "Ambiguous input" ); + + found_param = curr_param; + } + + m_traverser.rollback(); + } + + if( !found_param ) { + BOOST_TEST_UTILS_RUNTIME_PARAM_TRACE( "No match found" ); + BOOST_TEST_UTILS_RUNTIME_CLA_VALIDATE_INPUT( m_traverser.handle_mismatch(), m_traverser, + BOOST_TEST_UTILS_RUNTIME_PARAM_LITERAL( "Unexpected input" ) ); + + continue; + } + + BOOST_TEST_UTILS_RUNTIME_PARAM_TRACE( "Parse argument value" ); + found_param->produce_argument( m_traverser ); + + m_traverser.commit(); + } + + BOOST_TEST_FOREACH( parameter_ptr const&, curr_param, m_parameters ) { + if( !curr_param->p_optional && !curr_param->actual_argument() ) { + curr_param->produce_argument( *this ); + + BOOST_TEST_UTILS_RUNTIME_PARAM_VALIDATE_LOGIC( curr_param->actual_argument(), + BOOST_TEST_UTILS_RUNTIME_PARAM_LITERAL( "Required argument for parameter " ) << curr_param->id_2_report() + << BOOST_TEST_UTILS_RUNTIME_PARAM_LITERAL( " is missing" ) ); + } + } + } + BOOST_TEST_IMPL_CATCH0( bad_lexical_cast ) { + BOOST_TEST_UTILS_RUNTIME_PARAM_REPORT_LOGIC_ERROR( + BOOST_TEST_UTILS_RUNTIME_PARAM_LITERAL( "String to value convertion error during input parsing" ) ); + }; + + m_traverser.remainder( argc, argv ); +} + +//____________________________________________________________________________// + +BOOST_TEST_UTILS_RUNTIME_PARAM_INLINE const_argument_ptr +parser::operator[]( cstring string_id ) const +{ + parameter_ptr found_param; + + BOOST_TEST_FOREACH( parameter_ptr const&, curr_param, m_parameters ) { + if( curr_param->responds_to( string_id ) ) { + BOOST_TEST_UTILS_RUNTIME_PARAM_VALIDATE_LOGIC( !found_param, + BOOST_TEST_UTILS_RUNTIME_PARAM_LITERAL( "Ambiguous parameter string id: " ) << string_id ); + + found_param = curr_param; + } + } + + return found_param ? found_param->actual_argument() : argument_ptr(); +} + +//____________________________________________________________________________// + +BOOST_TEST_UTILS_RUNTIME_PARAM_INLINE cstring +parser::get( cstring string_id ) const +{ + return get( string_id ); +} + +//____________________________________________________________________________// + +BOOST_TEST_UTILS_RUNTIME_PARAM_INLINE void +parser::usage( out_stream& ostr ) +{ + if( m_program_name.empty() ) + assign_op( m_program_name, BOOST_TEST_UTILS_RUNTIME_PARAM_CSTRING_LITERAL( "" ), 0 ); + + format_stream fs; + + fs << m_program_name; + + BOOST_TEST_FOREACH( parameter_ptr const&, curr_param, m_parameters ) { + fs << BOOST_TEST_UTILS_RUNTIME_PARAM_LITERAL( ' ' ); + + if( curr_param->p_optional ) + fs << BOOST_TEST_UTILS_RUNTIME_PARAM_LITERAL( '[' ); + + curr_param->usage_info( fs ); + + if( curr_param->p_optional ) + fs << BOOST_TEST_UTILS_RUNTIME_PARAM_LITERAL( ']' ); + + if( curr_param->p_multiplicable ) { + fs << BOOST_TEST_UTILS_RUNTIME_PARAM_CSTRING_LITERAL( " ... " ); + + if( curr_param->p_optional ) + fs << BOOST_TEST_UTILS_RUNTIME_PARAM_LITERAL( '[' ); + + curr_param->usage_info( fs ); + + if( curr_param->p_optional ) + fs << BOOST_TEST_UTILS_RUNTIME_PARAM_LITERAL( ']' ); + } + } + + ostr << BOOST_TEST_UTILS_RUNTIME_PARAM_CSTRING_LITERAL( "Usage:\n" ) << fs.str() << std::endl; +} + +//____________________________________________________________________________// + +BOOST_TEST_UTILS_RUNTIME_PARAM_INLINE void +parser::help( out_stream& ostr ) +{ + usage( ostr ); + + bool need_where = true; + + BOOST_TEST_FOREACH( parameter_ptr const&, curr_param, m_parameters ) { + if( curr_param->p_description->empty() ) + continue; + + if( need_where ) { + ostr << BOOST_TEST_UTILS_RUNTIME_PARAM_CSTRING_LITERAL( "where:\n" ); + need_where = false; + } + + ostr << curr_param->id_2_report() << BOOST_TEST_UTILS_RUNTIME_PARAM_CSTRING_LITERAL( " - " ) << curr_param->p_description << std::endl; + } +} + +//____________________________________________________________________________// + +BOOST_TEST_UTILS_RUNTIME_PARAM_INLINE void +parser::reset() +{ + BOOST_TEST_FOREACH( parameter_ptr const&, param, m_parameters ) + param->reset(); +} + +//____________________________________________________________________________// + +} // namespace cla + +} // namespace BOOST_TEST_UTILS_RUNTIME_PARAM_NAMESPACE + +} // namespace boost + +#endif // BOOST_TEST_UTILS_RUNTIME_CLA_PARSER_IPP diff --git a/include/boost/test/utils/runtime/cla/positional_parameter.hpp b/include/boost/test/utils/runtime/cla/positional_parameter.hpp new file mode 100644 index 00000000..f378743d --- /dev/null +++ b/include/boost/test/utils/runtime/cla/positional_parameter.hpp @@ -0,0 +1,91 @@ +// (C) Copyright Gennadiy Rozental 2005-2014. +// Use, modification, and distribution are subject to 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 : positional parameter model +// *************************************************************************** + +#ifndef BOOST_TEST_UTILS_RUNTIME_CLA_POSITIONAL_PARAMETER_HPP +#define BOOST_TEST_UTILS_RUNTIME_CLA_POSITIONAL_PARAMETER_HPP + +// Boost.Runtime.Parameter +#include + +#include + +namespace boost { + +namespace BOOST_TEST_UTILS_RUNTIME_PARAM_NAMESPACE { + +namespace cla { + +// ************************************************************************** // +// ************** trivial_id_policy ************** // +// ************************************************************************** // + +class trivial_id_policy : public identification_policy { +public: + trivial_id_policy() + : identification_policy( rtti::type_id() ) + {} + BOOST_TEST_UTILS_RUNTIME_PARAM_UNNEEDED_VIRTUAL ~trivial_id_policy() {} + + virtual bool responds_to( cstring name ) const { return m_name == name; } + virtual bool conflict_with( identification_policy const& ) const { return false; } + virtual cstring id_2_report() const { return m_name; } + virtual void usage_info( format_stream& fs ) const + { + if( !m_name.empty() ) + fs << BOOST_TEST_UTILS_RUNTIME_PARAM_LITERAL( '<' ) << m_name << BOOST_TEST_UTILS_RUNTIME_PARAM_LITERAL( '>' ); + else + fs << BOOST_TEST_UTILS_RUNTIME_PARAM_CSTRING_LITERAL( "" ); + } + + virtual bool matching( parameter const& p, argv_traverser&, bool primary ) const + { + return primary && ( !p.has_argument() || p.p_multiplicable ); + } + + template + void accept_modifier( Modifier const& m ) + { + nfp::optionally_assign( m_name, m, name ); + } + +private: + // Data members + dstring m_name; +}; + +// ************************************************************************** // +// ************** runtime::cla::positional_parameter ************** // +// ************************************************************************** // + +template +class positional_parameter_t : public basic_parameter { + typedef basic_parameter base; +public: + // Constructors + explicit positional_parameter_t( cstring name ) + : base( name ) + {} +}; + +//____________________________________________________________________________// + +BOOST_TEST_UTILS_RUNTIME_CLA_NAMED_PARAM_GENERATORS( positional_parameter ) + +} // namespace cla + +} // namespace BOOST_TEST_UTILS_RUNTIME_PARAM_NAMESPACE + +} // namespace boost + +#endif // BOOST_TEST_UTILS_RUNTIME_CLA_POSITIONAL_PARAMETER_HPP diff --git a/include/boost/test/utils/runtime/cla/typed_parameter.hpp b/include/boost/test/utils/runtime/cla/typed_parameter.hpp new file mode 100644 index 00000000..70c5bbc0 --- /dev/null +++ b/include/boost/test/utils/runtime/cla/typed_parameter.hpp @@ -0,0 +1,70 @@ +// (C) Copyright Gennadiy Rozental 2005-2014. +// Use, modification, and distribution are subject to 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 : generic typed parameter model +// *************************************************************************** + +#ifndef BOOST_TEST_UTILS_RUNTIME_CLA_TYPED_PARAMETER_HPP +#define BOOST_TEST_UTILS_RUNTIME_CLA_TYPED_PARAMETER_HPP + +// Boost.Runtime.Parameter +#include + +#include +#include + +#include +#include + +// Boost.Test +#include + +namespace boost { + +namespace BOOST_TEST_UTILS_RUNTIME_PARAM_NAMESPACE { + +namespace cla { + +// ************************************************************************** // +// ************** runtime::cla::typed_parameter ************** // +// ************************************************************************** // + +template +class typed_parameter : public cla::parameter { +public: + explicit typed_parameter( identification_policy& ID ) + : cla::parameter( ID, m_arg_factory, rtti::type_id() == rtti::type_id() ) + {} + + // parameter properties modification + template + void accept_modifier( Modifier const& m ) + { + cla::parameter::accept_modifier( m ); + + m_arg_factory.accept_modifier( m ); + + BOOST_TEST_UTILS_RUNTIME_PARAM_VALIDATE_LOGIC( !p_optional || !m_arg_factory.m_value_generator, + BOOST_TEST_UTILS_RUNTIME_PARAM_LITERAL( "can't define a value generator for optional parameter " ) << id_2_report() ); + } + +private: + // Data members + typed_argument_factory m_arg_factory; +}; + +} // namespace cla + +} // namespace BOOST_TEST_UTILS_RUNTIME_PARAM_NAMESPACE + +} // namespace boost + +#endif // BOOST_TEST_UTILS_RUNTIME_CLA_TYPED_PARAMETER_HPP diff --git a/include/boost/test/utils/runtime/cla/validation.cpp b/include/boost/test/utils/runtime/cla/validation.cpp new file mode 100644 index 00000000..7f19a5ca --- /dev/null +++ b/include/boost/test/utils/runtime/cla/validation.cpp @@ -0,0 +1,16 @@ +// (C) Copyright Gennadiy Rozental 2005-2014. +// Use, modification, and distribution are subject to 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 : input validation helpers offline implementation +// *************************************************************************** + +#define BOOST_TEST_UTILS_RUNTIME_PARAM_INLINE +#include diff --git a/include/boost/test/utils/runtime/cla/validation.hpp b/include/boost/test/utils/runtime/cla/validation.hpp new file mode 100644 index 00000000..8a3da14c --- /dev/null +++ b/include/boost/test/utils/runtime/cla/validation.hpp @@ -0,0 +1,57 @@ +// (C) Copyright Gennadiy Rozental 2005-2014. +// Use, modification, and distribution are subject to 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 : input validation helpers definition +// *************************************************************************** + +#ifndef BOOST_TEST_UTILS_RUNTIME_CLA_VALIDATION_HPP +#define BOOST_TEST_UTILS_RUNTIME_CLA_VALIDATION_HPP + +// Boost.Runtime.Parameter +#include + +#include + +namespace boost { + +namespace BOOST_TEST_UTILS_RUNTIME_PARAM_NAMESPACE { + +namespace cla { + +// ************************************************************************** // +// ************** runtime::cla::report_input_error ************** // +// ************************************************************************** // + +void report_input_error( argv_traverser const& tr, format_stream& msg ); + +//____________________________________________________________________________// + +#define BOOST_TEST_UTILS_RUNTIME_CLA_VALIDATE_INPUT( b, tr, msg ) \ + if( b ) ; else ::boost::BOOST_TEST_UTILS_RUNTIME_PARAM_NAMESPACE::cla::report_input_error( tr, format_stream().ref() << msg ) + +//____________________________________________________________________________// + +} // namespace cla + +} // namespace BOOST_TEST_UTILS_RUNTIME_PARAM_NAMESPACE + +} // namespace boost + +#ifndef BOOST_TEST_UTILS_RUNTIME_PARAM_OFFLINE + +#ifndef BOOST_TEST_UTILS_RUNTIME_PARAM_INLINE +# define BOOST_TEST_UTILS_RUNTIME_PARAM_INLINE inline +#endif +# include + +#endif + +#endif // BOOST_TEST_UTILS_RUNTIME_CLA_VALIDATION_HPP diff --git a/include/boost/test/utils/runtime/cla/validation.ipp b/include/boost/test/utils/runtime/cla/validation.ipp new file mode 100644 index 00000000..9d8cd27b --- /dev/null +++ b/include/boost/test/utils/runtime/cla/validation.ipp @@ -0,0 +1,61 @@ +// (C) Copyright Gennadiy Rozental 2005-2014. +// Use, modification, and distribution are subject to the +// Boost Software License, Version 1.0. (See accompanying file +// LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) + +// See http://www.boost.org/libs/test for the library home page. +// +//! @file +//! @brief Input validation helpers implementation +// *************************************************************************** + +#ifndef BOOST_TEST_UTILS_RUNTIME_CLA_VALIDATION_IPP +#define BOOST_TEST_UTILS_RUNTIME_CLA_VALIDATION_IPP + +// Boost.Runtime.Parameter +#include + +#include +#include +#include // BOOST_TEST_UTILS_RUNTIME_PARAM_NAMESPACE::logic_error + +// Boost.Test +#include +#include + +namespace boost { + +namespace BOOST_TEST_UTILS_RUNTIME_PARAM_NAMESPACE { + +namespace cla { + +// ************************************************************************** // +// ************** runtime::cla::validation ************** // +// ************************************************************************** // + +BOOST_TEST_UTILS_RUNTIME_PARAM_INLINE void +report_input_error( argv_traverser const& tr, format_stream& msg ) +{ + if( tr.eoi() ) + msg << BOOST_TEST_UTILS_RUNTIME_PARAM_LITERAL( " at the end of input" ); + else { + msg << BOOST_TEST_UTILS_RUNTIME_PARAM_LITERAL( " in the following position: " ); + + if( tr.input().size() > 5 ) + msg << tr.input().substr( 0, 5 ) << BOOST_TEST_UTILS_RUNTIME_PARAM_LITERAL( "..." ); + else + msg << tr.input(); + } + + BOOST_TEST_IMPL_THROW( BOOST_TEST_UTILS_RUNTIME_PARAM_NAMESPACE::logic_error( msg.str() ) ); +} + +//____________________________________________________________________________// + +} // namespace cla + +} // namespace BOOST_TEST_UTILS_RUNTIME_PARAM_NAMESPACE + +} // namespace boost + +#endif // BOOST_TEST_UTILS_RUNTIME_CLA_VALIDATION_IPP diff --git a/include/boost/test/utils/runtime/cla/value_generator.hpp b/include/boost/test/utils/runtime/cla/value_generator.hpp new file mode 100644 index 00000000..0efc25de --- /dev/null +++ b/include/boost/test/utils/runtime/cla/value_generator.hpp @@ -0,0 +1,81 @@ +// (C) Copyright Gennadiy Rozental 2005-2014. +// Use, modification, and distribution are subject to 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 : specific value generators +// *************************************************************************** + +#ifndef BOOST_TEST_UTILS_RUNTIME_CLA_VALUE_GENERATOR_HPP +#define BOOST_TEST_UTILS_RUNTIME_CLA_VALUE_GENERATOR_HPP + +// Boost.Runtime.Parameter +#include + +#include +#include + +namespace boost { + +namespace BOOST_TEST_UTILS_RUNTIME_PARAM_NAMESPACE { + +namespace cla { + +namespace rt_cla_detail { + +// ************************************************************************** // +// ************** runtime::cla::const_generator ************** // +// ************************************************************************** // + +template +class const_generator { +public: + // Constructor + explicit const_generator( T const& t ) : m_const_value( t ) {} + + // generator interface + void operator()( parser const&, boost::optional& t ) const { t = m_const_value; } + +private: + // Data members + T m_const_value; +}; + +// ************************************************************************** // +// ************** runtime::cla::ref_generator ************** // +// ************************************************************************** // + +template +class ref_generator { +public: + // Constructor + explicit ref_generator( cstring ref_id ) : m_ref_id( ref_id ) {} + + // generator interface + void operator()( parser const& p, boost::optional& t ) const + { + p.get( m_ref_id, t ); + } + +private: + // Data members + cstring m_ref_id; +}; + +//____________________________________________________________________________// + +} // namespace rt_cla_detail + +} // namespace cla + +} // namespace BOOST_TEST_UTILS_RUNTIME_PARAM_NAMESPACE + +} // namespace boost + +#endif // BOOST_TEST_UTILS_RUNTIME_CLA_VALUE_GENERATOR_HPP diff --git a/include/boost/test/utils/runtime/cla/value_handler.hpp b/include/boost/test/utils/runtime/cla/value_handler.hpp new file mode 100644 index 00000000..38792602 --- /dev/null +++ b/include/boost/test/utils/runtime/cla/value_handler.hpp @@ -0,0 +1,57 @@ +// (C) Copyright Gennadiy Rozental 2005-2014. +// Use, modification, and distribution are subject to 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 : specific value handlers +// *************************************************************************** + +#ifndef BOOST_TEST_UTILS_RUNTIME_CLA_VALUE_HANDLER_HPP +#define BOOST_TEST_UTILS_RUNTIME_CLA_VALUE_HANDLER_HPP + +// Boost.Runtime.Parameter +#include + +#include + +namespace boost { + +namespace BOOST_TEST_UTILS_RUNTIME_PARAM_NAMESPACE { + +namespace cla { + +namespace rt_cla_detail { + +// ************************************************************************** // +// ************** runtime::cla::assigner ************** // +// ************************************************************************** // + +template +class assigner { +public: + // Constructor + explicit assigner( T& loc ) : m_target( loc ) {} + + // value handler implementation + void operator()( parameter const&, T& t ) { m_target = t; } + +private: + // Data members + T& m_target; +}; + +} // namespace rt_cla_detail + +} // namespace cla + +} // namespace BOOST_TEST_UTILS_RUNTIME_PARAM_NAMESPACE + +} // namespace boost + +#endif // BOOST_TEST_UTILS_RUNTIME_CLA_VALUE_HANDLER_HPP diff --git a/include/boost/test/utils/runtime/config.hpp b/include/boost/test/utils/runtime/config.hpp new file mode 100644 index 00000000..dfa9ae30 --- /dev/null +++ b/include/boost/test/utils/runtime/config.hpp @@ -0,0 +1,162 @@ +// (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 : $RCSfile$ +// +// Version : $Revision$ +// +// Description : Runtime.Param library configuration +// *************************************************************************** + +#ifndef BOOST_TEST_UTILS_RUNTIME_CONFIG_HPP +#define BOOST_TEST_UTILS_RUNTIME_CONFIG_HPP + +// Boost +#include +#ifdef BOOST_MSVC +# pragma warning(disable: 4511) // copy constructor could not be generated +# pragma warning(disable: 4512) // assignment operator could not be generated +# pragma warning(disable: 4181) // qualifier applied to reference type; ignored +# pragma warning(disable: 4675) // resolved overload was found by argument-dependent lookup +#endif + +// Boost.Test +#include +#include +#include +#include // operator<<(boost::runtime::cstring) + +// STL +#include +#include + +#ifdef __SUNPRO_CC + #include +#endif + +//____________________________________________________________________________// + +#ifndef BOOST_TEST_UTILS_RUNTIME_PARAM_CUSTOM_STRING +# ifndef BOOST_TEST_UTILS_RUNTIME_PARAM_WIDE_STRING +# define BOOST_TEST_UTILS_RUNTIME_PARAM_NAMESPACE runtime +# else +# define BOOST_TEST_UTILS_RUNTIME_PARAM_NAMESPACE wide_runtime +# endif +#endif + + + +namespace boost { + +namespace BOOST_TEST_UTILS_RUNTIME_PARAM_NAMESPACE { + +#ifndef BOOST_TEST_UTILS_RUNTIME_PARAM_CUSTOM_STRING +# ifndef BOOST_TEST_UTILS_RUNTIME_PARAM_WIDE_STRING + +typedef char char_type; +typedef std::string dstring; +typedef unit_test::const_string cstring; +typedef unit_test::literal_string literal_cstring; +typedef wrap_stringstream format_stream; + +#ifdef BOOST_CLASSIC_IOSTREAMS +typedef std::ostream out_stream; +#else +typedef std::basic_ostream out_stream; +#endif + +#ifdef BOOST_MSVC +#pragma warning(push) +#pragma warning(disable:4996) // putenv +#endif + +#if defined(__MINGW32__) +extern "C" int putenv( const char * ); +#endif + +#ifndef UNDER_CE +#if defined(__COMO__) && 0 +inline void +putenv_impl( cstring name, cstring value ) +{ + using namespace std; + // !! this may actually fail. What should we do? + setenv( name.begin(), value.begin(), 1 ); +} +#else +inline void +putenv_impl( cstring name, cstring value ) +{ + format_stream fs; + + fs << name << '=' << value; + + // !! this may actually fail. What should we do? + // const_cast is used to satisfy putenv interface + using namespace std; + putenv( const_cast( fs.str().c_str() ) ); +} +#endif +#endif + +#ifdef BOOST_MSVC +#pragma warning(pop) +#endif + +#define BOOST_TEST_UTILS_RUNTIME_PARAM_LITERAL( l ) l +#define BOOST_TEST_UTILS_RUNTIME_PARAM_CSTRING_LITERAL( l ) cstring( l, sizeof( l ) - 1 ) +#define BOOST_TEST_UTILS_RUNTIME_PARAM_GETENV getenv +#define BOOST_TEST_UTILS_RUNTIME_PARAM_PUTENV ::boost::BOOST_TEST_UTILS_RUNTIME_PARAM_NAMESPACE::putenv_impl +#define BOOST_TEST_UTILS_RUNTIME_PARAM_EXCEPTION_INHERIT_STD + +//____________________________________________________________________________// + +# else + +typedef wchar_t char_type; +typedef std::basic_string dstring; +typedef unit_test::basic_cstring cstring; +typedef const unit_test::basic_cstring literal_cstring; +typedef wrap_wstringstream format_stream; +typedef std::wostream out_stream; + +#ifndef UNDER_CE +inline void +putenv_impl( cstring name, cstring value ) +{ + format_stream fs; + + fs << name << '=' << value; + + // !! this may actually fail. What should we do? + // const_cast is used to satisfy putenv interface + using namespace std; + wputenv( const_cast( fs.str().c_str() ) ); +} +#endif + +#define BOOST_TEST_UTILS_RUNTIME_PARAM_LITERAL( l ) L ## l +#define BOOST_TEST_UTILS_RUNTIME_PARAM_CSTRING_LITERAL( l ) cstring( L ## l, sizeof( L ## l )/sizeof(wchar_t) - 1 ) +#define BOOST_TEST_UTILS_RUNTIME_PARAM_GETENV wgetenv +#define BOOST_TEST_UTILS_RUNTIME_PARAM_PUTENV putenv_impl + +# endif +#endif + +#ifdef __GNUC__ +#define BOOST_TEST_UTILS_RUNTIME_PARAM_UNNEEDED_VIRTUAL virtual +#else +#define BOOST_TEST_UTILS_RUNTIME_PARAM_UNNEEDED_VIRTUAL +#endif + +//____________________________________________________________________________// + +} // namespace BOOST_TEST_UTILS_RUNTIME_PARAM_NAMESPACE + +} // namespace boost + +#endif // BOOST_TEST_UTILS_RUNTIME_CONFIG_HPP diff --git a/include/boost/test/utils/runtime/configuration.hpp b/include/boost/test/utils/runtime/configuration.hpp new file mode 100644 index 00000000..bf731736 --- /dev/null +++ b/include/boost/test/utils/runtime/configuration.hpp @@ -0,0 +1,61 @@ +// (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 : $RCSfile$ +// +// Version : $Revision$ +// +// Description : abstract interface for the formal parameter +// *************************************************************************** + +#ifndef BOOST_TEST_UTILS_RUNTIME_CONFIGURATION_HPP +#define BOOST_TEST_UTILS_RUNTIME_CONFIGURATION_HPP + +// Boost.Runtime.Parameter +#include +#include +#include + +namespace boost { + +namespace BOOST_TEST_UTILS_RUNTIME_PARAM_NAMESPACE { + +// ************************************************************************** // +// ************** runtime::configuration ************** // +// ************************************************************************** // + +class config_source { + virtual parameter const& config_param_begin() const = 0; + virtual parameter const& config_param_end() const = 0; + +protected: + config_source() {} + ~config_source() {} +}; + +// ************************************************************************** // +// ************** runtime::configuration ************** // +// ************************************************************************** // + +template +class configuration : public StoragePolicy, public IdentificationPlicy, public ConflictResolutionPolicy { +public: + // Constructor + configuration(); + + void use( config_source const& ) + { + + } +private: +}; + +} // namespace BOOST_TEST_UTILS_RUNTIME_PARAM_NAMESPACE + +} // namespace boost + +#endif // BOOST_TEST_UTILS_RUNTIME_CONFIGURATION_HPP diff --git a/include/boost/test/utils/runtime/env/environment.cpp b/include/boost/test/utils/runtime/env/environment.cpp new file mode 100644 index 00000000..ddf47b34 --- /dev/null +++ b/include/boost/test/utils/runtime/env/environment.cpp @@ -0,0 +1,23 @@ +// (C) Copyright Gennadiy Rozental 2004-2014. +// Use, modification, and distribution are subject to 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 : implements offline model of program environment +// *************************************************************************** + +#include + +#ifdef BOOST_MSVC +# pragma warning(disable: 4127) // conditional expression is constant +# pragma warning(disable: 4701) // local environment 'result' may be used without having been initialized +#endif + +#define BOOST_TEST_UTILS_RUNTIME_PARAM_INLINE +#include diff --git a/include/boost/test/utils/runtime/env/environment.hpp b/include/boost/test/utils/runtime/env/environment.hpp new file mode 100644 index 00000000..62b2ae6d --- /dev/null +++ b/include/boost/test/utils/runtime/env/environment.hpp @@ -0,0 +1,171 @@ +// (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 : $RCSfile$ +// +// Version : $Revision$ +// +// Description : defines and implements inline model of program environment +// *************************************************************************** + +#ifndef BOOST_TEST_UTILS_RUNTIME_ENV_ENVIRONMENT_HPP +#define BOOST_TEST_UTILS_RUNTIME_ENV_ENVIRONMENT_HPP + +#ifdef UNDER_CE +#error Windows CE does not support environment variables. +#endif + +// Boost.Runtime.Parameter +#include +#include +#include +#include + +#include +#include +#include + +// Boost +#include + +namespace boost { + +namespace BOOST_TEST_UTILS_RUNTIME_PARAM_NAMESPACE { + +// ************************************************************************** // +// ************** runtime::environment implementation ************** // +// ************************************************************************** // + +namespace environment { + +namespace rt_env_detail { + +template +variable_data& +init_new_var( cstring var_name, Modifiers m = nfp::no_params ) +{ + rt_env_detail::variable_data& new_vd = new_var_record( var_name ); + + cstring str_value = sys_read_var( new_vd.m_var_name ); + + if( !str_value.is_empty() ) { + BOOST_TEST_IMPL_TRY { + boost::optional value; + + if( m.has( interpreter ) ) + m[interpreter]( str_value, value ); + else + interpret_argument_value( str_value, value, 0 ); + + if( !!value ) { + new_vd.m_value.reset( new typed_argument( new_vd ) ); + + arg_value( *new_vd.m_value ) = *value; + } + } + BOOST_TEST_IMPL_CATCHALL() { // !! could we do that + // !! should we report an error? + } + } + + if( !new_vd.m_value && m.has( default_value ) ) { + new_vd.m_value.reset( new typed_argument( new_vd ) ); + + nfp::optionally_assign( arg_value( *new_vd.m_value ), m[default_value] ); + } + + nfp::optionally_assign( new_vd.m_global_id, m, global_id ); + + return new_vd; +} + +//____________________________________________________________________________// + +} // namespace rt_env_detail + +} // namespace environment + +// ************************************************************************** // +// ************** runtime::environment ************** // +// ************************************************************************** // + +namespace environment { + + // variable access + variable_base + var( cstring var_name ); + + //________________________________________________________________________// + + template + inline variable + var( cstring var_name ) + { + rt_env_detail::variable_data* vd = rt_env_detail::find_var_record( var_name ); + + return environment::variable( !vd ? rt_env_detail::init_new_var( var_name, nfp::no_params ) : *vd ); + } + + //________________________________________________________________________// + + template + inline variable + var( cstring var_name, Modifiers const& m ) + { + rt_env_detail::variable_data* vd = rt_env_detail::find_var_record( var_name ); + + return environment::variable( !vd ? rt_env_detail::init_new_var( var_name, m ) : *vd ); + } + + //________________________________________________________________________// + + // direct variable value access + inline cstring + get( cstring var_name ) + { + return environment::var( var_name ).value(); + } + + //________________________________________________________________________// + + template + inline T const& + get( cstring var_name ) + { + return environment::var( var_name ).value(); + } + + //________________________________________________________________________// + + template + inline void + get( cstring var_name, boost::optional& res ) + { + variable const& v = environment::var( var_name ); + v.value( res ); + } + + //________________________________________________________________________// + +} // namespace environment + +namespace env = environment; + +} // namespace BOOST_TEST_UTILS_RUNTIME_PARAM_NAMESPACE + +} // namespace boost + +#ifndef BOOST_TEST_UTILS_RUNTIME_PARAM_OFFLINE + +#ifndef BOOST_TEST_UTILS_RUNTIME_PARAM_INLINE +# define BOOST_TEST_UTILS_RUNTIME_PARAM_INLINE inline +#endif +# include + +#endif + +#endif // BOOST_TEST_UTILS_RUNTIME_ENV_ENVIRONMENT_HPP diff --git a/include/boost/test/utils/runtime/env/environment.ipp b/include/boost/test/utils/runtime/env/environment.ipp new file mode 100644 index 00000000..6baf72f4 --- /dev/null +++ b/include/boost/test/utils/runtime/env/environment.ipp @@ -0,0 +1,125 @@ +// (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 : $RCSfile$ +// +// Version : $Revision$ +// +// Description : implements model of program environment +// *************************************************************************** + +#ifndef BOOST_TEST_UTILS_RUNTIME_ENV_ENVIRONMENT_IPP +#define BOOST_TEST_UTILS_RUNTIME_ENV_ENVIRONMENT_IPP + +// Boost.Runtime.Parameter +#include +#include + +#include + +// Boost.Test +#include +#include + +// STL +#include +#include + +namespace boost { + +namespace BOOST_TEST_UTILS_RUNTIME_PARAM_NAMESPACE { + +namespace environment { + +// ************************************************************************** // +// ************** runtime::environment ************** // +// ************************************************************************** // + +namespace rt_env_detail { + +typedef std::map registry; +typedef std::list keys; + +BOOST_TEST_UTILS_RUNTIME_PARAM_INLINE registry& s_registry() { static registry instance; return instance; } +BOOST_TEST_UTILS_RUNTIME_PARAM_INLINE keys& s_keys() { static keys instance; return instance; } + +BOOST_TEST_UTILS_RUNTIME_PARAM_INLINE variable_data& +new_var_record( cstring var_name ) +{ + // save the name in list of keys + s_keys().push_back( dstring() ); + dstring& key = s_keys().back(); + assign_op( key, var_name, 0 ); + + // create and return new record + variable_data& new_var_data = s_registry()[key]; + + new_var_data.m_var_name = key; + + return new_var_data; +} + +//____________________________________________________________________________// + +BOOST_TEST_UTILS_RUNTIME_PARAM_INLINE variable_data* +find_var_record( cstring var_name ) +{ + registry::iterator it = s_registry().find( var_name ); + + return it == s_registry().end() ? 0 : &(it->second); +} + +//____________________________________________________________________________// + +#ifdef BOOST_MSVC +#pragma warning(push) +#pragma warning(disable:4996) // getenv +#endif + +BOOST_TEST_UTILS_RUNTIME_PARAM_INLINE cstring +sys_read_var( cstring var_name ) +{ + using namespace std; + return BOOST_TEST_UTILS_RUNTIME_PARAM_GETENV( var_name.begin() ); +} + +#ifdef BOOST_MSVC +#pragma warning(pop) +#endif +//____________________________________________________________________________// + +BOOST_TEST_UTILS_RUNTIME_PARAM_INLINE void +sys_write_var( cstring var_name, format_stream& var_value ) +{ + BOOST_TEST_UTILS_RUNTIME_PARAM_PUTENV( var_name, cstring( var_value.str() ) ); +} + +//____________________________________________________________________________// + +} // namespace rt_env_detail + +BOOST_TEST_UTILS_RUNTIME_PARAM_INLINE variable_base +var( cstring var_name ) +{ + rt_env_detail::variable_data* vd = rt_env_detail::find_var_record( var_name ); + + BOOST_TEST_UTILS_RUNTIME_PARAM_VALIDATE_LOGIC( !!vd, + BOOST_TEST_UTILS_RUNTIME_PARAM_LITERAL( "First access to the environment variable " ) + << var_name << BOOST_TEST_UTILS_RUNTIME_PARAM_LITERAL( " should be typed" ) ); + + return variable_base( *vd ); +} + +//____________________________________________________________________________// + +} // namespace environment + +} // namespace BOOST_TEST_UTILS_RUNTIME_PARAM_NAMESPACE + +} // namespace boost + +#endif // BOOST_TEST_UTILS_RUNTIME_ENV_ENVIRONMENT_IPP_062904GER diff --git a/include/boost/test/utils/runtime/env/fetch.hpp b/include/boost/test/utils/runtime/env/fetch.hpp deleted file mode 100644 index d20ad10f..00000000 --- a/include/boost/test/utils/runtime/env/fetch.hpp +++ /dev/null @@ -1,108 +0,0 @@ -// (C) Copyright Gennadiy Rozental 2015. -// 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 : implements fetching absent parameter athuments from environment -// *************************************************************************** - -#ifndef BOOST_TEST_UTILS_RUNTIME_ENV_FETCH_HPP -#define BOOST_TEST_UTILS_RUNTIME_ENV_FETCH_HPP - -// Boost.Test Runtime parameters -#include -#include - -#include - -// C Runtime -#include - -namespace boost { -namespace runtime { -namespace env { - -namespace env_detail { - -#ifndef UNDER_CE - -#ifdef BOOST_MSVC -#pragma warning(push) -#pragma warning(disable:4996) // getenv -#endif - -inline std::pair -sys_read_var( cstring var_name ) -{ - using namespace std; - char const* res = getenv( var_name.begin() ); - - return std::make_pair( cstring(res), res != NULL ); -} - -#ifdef BOOST_MSVC -#pragma warning(pop) -#endif - -#else - -inline std::pair -sys_read_var( cstring var_name ) -{ - return std::make_pair( cstring(), false ); -} - -#endif - -//____________________________________________________________________________// - -template -inline void -fetch_absent( parameters_store const& params, runtime::arguments_store& args, ReadFunc read_func ) -{ - BOOST_TEST_FOREACH( parameters_store::storage_type::value_type const&, v, params.all() ) { - basic_param_ptr param = v.second; - - if( args.has( param->p_name ) || param->p_env_var.empty() ) - continue; - - auto value = read_func( param->p_env_var ); - - if( !value.second ) - continue; - - // Validate against unexpected empty value - BOOST_TEST_I_ASSRT( !value.first.is_empty() || param->p_has_optional_value, - format_error( param->p_name ) - << "Missing an argument value for the parameter " << param->p_name - << " in the environment." ); - - // Produce argument value - param->produce_argument( value.first, false, args ); - - } -} - -//____________________________________________________________________________// - -} // namespace env_detail - -inline void -fetch_absent( parameters_store const& params, runtime::arguments_store& args ) -{ - env_detail::fetch_absent( params, args, &env_detail::sys_read_var ); -} - -} // namespace env -} // namespace runtime -} // namespace boost - -#include - -#endif // BOOST_TEST_UTILS_RUNTIME_ENV_FETCH_HPP diff --git a/include/boost/test/utils/runtime/env/fwd.hpp b/include/boost/test/utils/runtime/env/fwd.hpp new file mode 100644 index 00000000..438795ea --- /dev/null +++ b/include/boost/test/utils/runtime/env/fwd.hpp @@ -0,0 +1,61 @@ +// (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 : $RCSfile$ +// +// Version : $Revision$ +// +// Description : environment subsystem forward declarations +// *************************************************************************** + +#ifndef BOOST_TEST_UTILS_RUNTIME_ENV_FWD_HPP +#define BOOST_TEST_UTILS_RUNTIME_ENV_FWD_HPP + +#ifdef UNDER_CE +#error Windows CE does not support environment variables. +#endif + +// Boost.Runtime.Parameter +#include + +namespace boost { + +namespace BOOST_TEST_UTILS_RUNTIME_PARAM_NAMESPACE { + +namespace environment { + +template +class variable; + +class variable_base; +variable_base var( cstring var_name ); + +template +inline variable + var( cstring var_name ); + +namespace rt_env_detail { + +struct variable_data; + +variable_data& new_var_record( cstring var_name ); +variable_data* find_var_record( cstring var_name ); + +cstring sys_read_var( cstring var_name ); +void sys_write_var( cstring var_name, format_stream& var_value ); + +} + +template class variable; + +} // namespace environment + +} // namespace BOOST_TEST_UTILS_RUNTIME_PARAM_NAMESPACE + +} // namespace boost + +#endif // BOOST_TEST_UTILS_RUNTIME_ENV_FWD_HPP diff --git a/include/boost/test/utils/runtime/env/modifier.hpp b/include/boost/test/utils/runtime/env/modifier.hpp new file mode 100644 index 00000000..536461a5 --- /dev/null +++ b/include/boost/test/utils/runtime/env/modifier.hpp @@ -0,0 +1,47 @@ +// (C) Copyright Gennadiy Rozental 2005-2014. +// Use, modification, and distribution are subject to 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 : defines variable modifiers +// *************************************************************************** + +#ifndef BOOST_TEST_UTILS_RUNTIME_ENV_MODIFIER_HPP +#define BOOST_TEST_UTILS_RUNTIME_ENV_MODIFIER_HPP + +// Boost.Runtime.Parameter +#include + +// Boost.Test +#include + +namespace boost { + +namespace BOOST_TEST_UTILS_RUNTIME_PARAM_NAMESPACE { + +namespace environment { + +// ************************************************************************** // +// ************** environment variable modifiers ************** // +// ************************************************************************** // + +namespace { + +nfp::typed_keyword global_id; +nfp::keyword default_value; +nfp::keyword interpreter; + +} // local namespace +} // namespace environment + +} // namespace BOOST_TEST_UTILS_RUNTIME_PARAM_NAMESPACE + +} // namespace boost + +#endif // BOOST_TEST_UTILS_RUNTIME_ENV_MODIFIER_HPP diff --git a/include/boost/test/utils/runtime/env/variable.hpp b/include/boost/test/utils/runtime/env/variable.hpp new file mode 100644 index 00000000..df776a61 --- /dev/null +++ b/include/boost/test/utils/runtime/env/variable.hpp @@ -0,0 +1,223 @@ +// (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 : $RCSfile$ +// +// Version : $Revision$ +// +// Description : defines model of program environment variable +// *************************************************************************** + +#ifndef BOOST_TEST_UTILS_RUNTIME_ENV_VARIABLE_HPP +#define BOOST_TEST_UTILS_RUNTIME_ENV_VARIABLE_HPP + +#ifdef UNDER_CE +#error Windows CE does not support environment variables. +#endif + +// Boost.Runtime.Parameter +#include +#include +#include +#include + +#include + +// Boost +#include + +namespace boost { + +namespace BOOST_TEST_UTILS_RUNTIME_PARAM_NAMESPACE { + +namespace environment { + +// ************************************************************************** // +// ************** runtime::environment::variable_data ************** // +// ************************************************************************** // + +namespace rt_env_detail { + +struct variable_data : public runtime::parameter { + cstring m_var_name; + dstring m_global_id; + argument_ptr m_value; +}; + +} // namespace rt_env_detail + +// ************************************************************************** // +// ************** runtime::environment::variable_base ************** // +// ************************************************************************** // + +class variable_base { +public: + explicit variable_base( rt_env_detail::variable_data& data ) : m_data( &data ) {} + + // arguments access + template + T const& value() const + { + return arg_value( *m_data->m_value ); + } + + template + void value( boost::optional& res ) const + { + if( has_value() ) + res = arg_value( *m_data->m_value ); + else + res.reset(); + } + + bool has_value() const { return !!m_data->m_value; } + cstring name() const { return m_data->m_var_name; } + +protected: + // Data members + rt_env_detail::variable_data* m_data; +} ; + +// ************************************************************************** // +// ************** runtime::environment::variable ************** // +// ************************************************************************** // + +template +class variable : public variable_base { +public: + // Constructors + explicit variable( cstring var_name ); + + template + explicit variable( cstring var_name, Modifiers const& m ); + + explicit variable( rt_env_detail::variable_data& data ) + : variable_base( data ) {} + + // other variable assignment + void operator=( variable const& v ) { m_data = v.m_data; } + + // access methods + T const& value() const { return variable_base::value(); } + +#if BOOST_WORKAROUND(__MWERKS__, BOOST_TESTED_AT(0x3206)) || \ + BOOST_WORKAROUND(__BORLANDC__, BOOST_TESTED_AT(0x0593)) + template + void value( boost::optional& res ) const { variable_base::value( res ); } +#else + using variable_base::value; +#endif + + // Value assignment + template + void operator=( V const& v ) + { + if( !has_value() ) + m_data->m_value.reset( new typed_argument( *m_data ) ); + + arg_value( *m_data->m_value ) = v; + + rt_env_detail::sys_write_var( m_data->m_var_name, format_stream().ref() << value() ); + } +}; // class variable + +//____________________________________________________________________________// + +template +inline std::basic_ostream& +operator<<( std::basic_ostream& os, variable const& v ) +{ + os << v.name() << '='; + + if( v.has_value() ) + os << v.value(); + + return os; +} + +//____________________________________________________________________________// + +template +inline bool +operator==( variable ev, V const& v ) +{ + return ev.has_value() && ev.value() == v; +} + +//____________________________________________________________________________// + +template +inline bool +operator==( V const& v, variable ev ) +{ + return ev.has_value() && ev.value() == v; +} + +//____________________________________________________________________________// + +template +inline bool +operator!=( variable ev, V const& v ) +{ + return !ev.has_value() || ev.value() != v; +} + +//____________________________________________________________________________// + +template +inline bool +operator!=( V const& v, variable ev ) +{ + return !ev.has_value() || ev.value() != v; +} + +//____________________________________________________________________________// + +} // namespace environment + +} // namespace BOOST_TEST_UTILS_RUNTIME_PARAM_NAMESPACE + +} // namespace boost + +// ************************************************************************** // +// ************************************************************************** // +// Implementation + +#include + +// ************************************************************************** // +// ************** runtime::environment::variable ************** // +// ************************************************************************** // + +namespace boost { + +namespace BOOST_TEST_UTILS_RUNTIME_PARAM_NAMESPACE { + +namespace environment { + +template +variable::variable( cstring var_name ) +: variable_base( environment::var( var_name ) ) +{} + +//____________________________________________________________________________// + +template +template +variable::variable( cstring var_name, Modifiers const& m ) +: variable_base( environment::var( var_name, m ) ) +{} + +//____________________________________________________________________________// + +} // namespace environment + +} // namespace BOOST_TEST_UTILS_RUNTIME_PARAM_NAMESPACE + +} // namespace boost + +#endif // BOOST_TEST_UTILS_RUNTIME_ENV_VARIABLE_HPP diff --git a/include/boost/test/utils/runtime/errors.hpp b/include/boost/test/utils/runtime/errors.hpp deleted file mode 100644 index 93151e6f..00000000 --- a/include/boost/test/utils/runtime/errors.hpp +++ /dev/null @@ -1,145 +0,0 @@ -// (C) Copyright Gennadiy Rozental 2005-2015. -// 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 : defines runtime parameters setup error -// *************************************************************************** - -#ifndef BOOST_TEST_UTILS_RUNTIME_INIT_ERROR_HPP -#define BOOST_TEST_UTILS_RUNTIME_INIT_ERROR_HPP - -// Boost.Test Runtime parameters -#include - -// Boost -#include -#include - -// STL -#include -#include - -#include - -namespace boost { -namespace runtime { - -// ************************************************************************** // -// ************** runtime::param_error ************** // -// ************************************************************************** // - -class param_error : public std::exception { -public: - virtual const char * what() const BOOST_NOEXCEPT_OR_NOTHROW - { - return msg.c_str(); - } - - cstring param_name; - std::string msg; - -protected: - explicit param_error( cstring param_name_ ) : param_name( param_name_) {} -}; - -//____________________________________________________________________________// - -class init_error : public param_error { -protected: - explicit init_error( cstring param_name ) : param_error( param_name ) {} -}; -class input_error : public param_error { -protected: - explicit input_error( cstring param_name ) : param_error( param_name ) {} -}; - -//____________________________________________________________________________// - -template -class specific_param_error : public Base { -protected: - explicit specific_param_error( cstring param_name ) : Base( param_name ) {} -}; - -//____________________________________________________________________________// - -template -inline Derived -operator<<(specific_param_error&& ex, char const* val) -{ - ex.msg.append( val ); - - return reinterpret_cast(ex); -} - -//____________________________________________________________________________// - -template -inline Derived -operator<<(specific_param_error&& ex, T const& val) -{ - ex.msg.append( lexical_cast( val ) ); - - return reinterpret_cast(ex); -} - -//____________________________________________________________________________// - -// ************************************************************************** // -// ************** specific exception types ************** // -// ************************************************************************** // - -#define SPECIFIC_EX_TYPE( type, base ) \ -class type : public specific_param_error { \ -public: \ - explicit type( cstring param_name = cstring() ) \ - : specific_param_error( param_name ) \ - {} \ -} \ -/**/ - -SPECIFIC_EX_TYPE( invalid_cla_id, init_error ); -SPECIFIC_EX_TYPE( duplicate_param, init_error ); -SPECIFIC_EX_TYPE( conflicting_param, init_error ); -SPECIFIC_EX_TYPE( unknown_param, init_error ); -SPECIFIC_EX_TYPE( access_to_missing_argument, init_error ); -SPECIFIC_EX_TYPE( arg_type_mismatch, init_error ); -SPECIFIC_EX_TYPE( invalid_param_spec, init_error ); - -SPECIFIC_EX_TYPE( format_error, input_error ); -SPECIFIC_EX_TYPE( duplicate_arg, input_error ); -SPECIFIC_EX_TYPE( missing_req_arg, input_error ); - -#undef SPECIFIC_EX_TYPE - -class ambiguous_param : public specific_param_error { -public: - explicit ambiguous_param( std::vector&& amb_candidates ) - : specific_param_error( "" ) - , m_amb_candidates( std::move( amb_candidates ) ) {} - - std::vector m_amb_candidates; -}; - -class unrecognized_param : public specific_param_error { -public: - explicit unrecognized_param( std::vector&& type_candidates ) - : specific_param_error( "" ) - , m_typo_candidates( std::move( type_candidates ) ) {} - - std::vector m_typo_candidates; -}; - -} // namespace runtime -} // namespace boost - -#include - -#endif // BOOST_TEST_UTILS_RUNTIME_INIT_ERROR_HPP diff --git a/include/boost/test/utils/runtime/file/config_file.cpp b/include/boost/test/utils/runtime/file/config_file.cpp new file mode 100644 index 00000000..1e13d66e --- /dev/null +++ b/include/boost/test/utils/runtime/file/config_file.cpp @@ -0,0 +1,249 @@ +// (C) Copyright Gennadiy Rozental 2005-2014. +// Use, modification, and distribution are subject to 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 : implements models configuration file, it's parameter and parameter namespaces +// *************************************************************************** + +// Boost.Runtime.Parameter +#include + +#include +#include + +// Boost.Test +#include +#include +#include +#include + +namespace boost { + +namespace BOOST_TEST_UTILS_RUNTIME_PARAM_NAMESPACE { + +namespace file { + +// ************************************************************************** // +// ************** runtime::file::parameter ************** // +// ************************************************************************** // + +parameter::parameter( cstring name, cstring value, param_namespace const& parent ) +: m_parent( parent ) +{ + assign_op( p_name.value, name, 0 ); + assign_op( p_value.value, value, 0 ); +} + +//____________________________________________________________________________// + +std::ostream& +operator<<( std::ostream& os, parameter const& p ) +{ + p.m_parent.print_full_name( os ); + + return os << p.p_name << " = \"" << p.p_value << "\""; +} + +//____________________________________________________________________________// + +// ************************************************************************** // +// ************** runtime::file::param_namespace ************** // +// ************************************************************************** // + +param_namespace::param_namespace( cstring name, param_namespace const* parent ) +: p_parent( parent ) +{ + assign_op( p_name.value, name, 0 ); +} + +//____________________________________________________________________________// + +void +param_namespace::insert_param( cstring param_name, cstring param_value ) +{ + BOOST_TEST_FOREACH( parameter const&, p, m_parameters ) + BOOST_TEST_UTILS_RUNTIME_PARAM_VALIDATE_LOGIC( p.p_name != param_name, + BOOST_TEST_UTILS_RUNTIME_PARAM_LITERAL( "Duplicate parameter " ) << param_name ); + + m_parameters.push_back( parameter( param_name, param_value, *this ) ); +} + +//____________________________________________________________________________// + +param_namespace& +param_namespace::subnamespace( cstring namespace_name ) +{ + BOOST_TEST_FOREACH( param_namespace&, subns, m_subnamespaces ) + if( subns.p_name == namespace_name ) + return subns; + + m_subnamespaces.push_back( param_namespace( namespace_name, this ) ); + + return m_subnamespaces.back(); +} + +//____________________________________________________________________________// + +void +param_namespace::clear() +{ + m_parameters.clear(); + m_subnamespaces.clear(); +} + +//____________________________________________________________________________// + +void +param_namespace::print_full_name( std::ostream& os ) const +{ + if( !p_parent ) + return; + + p_parent.get()->print_full_name( os ); + + os << p_name << "::"; +} + +//____________________________________________________________________________// + +boost::optional +get_param_value( param_namespace const& where_from, + cstring name_part1, + cstring name_part2, + cstring name_part3, + cstring name_part4, + cstring name_part5 ) +{ + if( name_part2.is_empty() ) { + boost::optional res; + + BOOST_TEST_FOREACH( parameter const&, p, where_from ) { + if( p.p_name == name_part1 ) { + res = cstring( p.p_value ); + break; + } + } + + return res; + } + + param_namespace const* sns = get_param_subns( where_from, name_part1 ); + + return sns ? get_param_value( *sns, name_part2, name_part3, name_part4, name_part5 ) + : boost::optional(); +} + +//____________________________________________________________________________// + +cstring +get_requ_param_value( param_namespace const& where_from, + cstring name_part1, + cstring name_part2, + cstring name_part3, + cstring name_part4, + cstring name_part5 ) +{ + boost::optional v = get_param_value( where_from, name_part1, name_part2, name_part3, name_part4, name_part5 ); + +#define APPEND_PART( part ) (part.is_empty() ? "" : "::") << (part.is_empty() ? cstring() : part) + BOOST_TEST_UTILS_RUNTIME_PARAM_VALIDATE_LOGIC( !!v, BOOST_TEST_UTILS_RUNTIME_PARAM_LITERAL( "Required parameter " ) + << name_part1 + << APPEND_PART( name_part2 ) + << APPEND_PART( name_part3 ) + << APPEND_PART( name_part4 ) + << APPEND_PART( name_part5 ) + << BOOST_TEST_UTILS_RUNTIME_PARAM_LITERAL( " value is missing" ) ); +#undef APPEND_PART + + return *v; +} + +//____________________________________________________________________________// + +param_namespace const* +get_param_subns( param_namespace const& where_from, cstring namespace_name ) +{ + param_namespace::sub_ns_const_iterator it = where_from.sub_ns_begin(); + param_namespace::sub_ns_const_iterator end = where_from.sub_ns_end(); + + while( it != end ) { + if( it->p_name == namespace_name ) + return &*it; + + ++it; + } + + return 0; +} + +//____________________________________________________________________________// + +void +param_namespace::load_impl( config_file_iterator cf_it, + cstring value_marker, cstring value_delimeter, cstring namespace_delimeter ) +{ + using namespace unit_test; + + while( cf_it != config_file_iterator() ) { + string_token_iterator ti( *cf_it, (max_tokens = 2,kept_delimeters = dt_none, dropped_delimeters = value_delimeter) ); + + cstring param_name = *ti; + cstring param_value = *(++ti); + + param_value.trim( value_marker ); + + param_namespace* targ_ns = this; + + while( !param_name.is_empty() ) { + cstring::size_type pos = param_name.find( namespace_delimeter ); + cstring subname( param_name.begin(), pos == cstring::npos ? param_name.size() : pos ); + + if( subname.size() == param_name.size() ) { + targ_ns->insert_param( param_name, param_value ); + break; + } + else { + targ_ns = &targ_ns->subnamespace( subname ); + + param_name.trim_left( subname.size() + namespace_delimeter.size() ); + } + } + ++cf_it; + } +} + +//____________________________________________________________________________// + +// ************************************************************************** // +// ************** runtime::file::config_file ************** // +// ************************************************************************** // + +config_file::config_file() +: param_namespace( cstring() ) +{ +} + +//____________________________________________________________________________// + +config_file::config_file( cstring file_name ) +: param_namespace( cstring() ) +{ + load( file_name ); +} + +//____________________________________________________________________________// + +} // namespace file + +} // namespace BOOST_TEST_UTILS_RUNTIME_PARAM_NAMESPACE + +} // namespace boost + +// EOF diff --git a/include/boost/test/utils/runtime/file/config_file.hpp b/include/boost/test/utils/runtime/file/config_file.hpp new file mode 100644 index 00000000..e7baf08b --- /dev/null +++ b/include/boost/test/utils/runtime/file/config_file.hpp @@ -0,0 +1,182 @@ +// (C) Copyright Gennadiy Rozental 2005-2014. +// Use, modification, and distribution are subject to 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 : defines models configuration file, it's parameter and parameter namespaces +// *************************************************************************** + +#ifndef BOOST_TEST_UTILS_RUNTIME_FILE_CONFIG_FILE_HPP +#define BOOST_TEST_UTILS_RUNTIME_FILE_CONFIG_FILE_HPP + +// Boost.Runtime.Parameter +#include + +#include + +// Boost.Test +#include +#include + +// Boost +#include + +// STL +#include + +namespace boost { + +namespace BOOST_TEST_UTILS_RUNTIME_PARAM_NAMESPACE { + +namespace file { + +// ************************************************************************** // +// ************** runtime::file::parameter ************** // +// ************************************************************************** // + +class param_namespace; + +class parameter { +public: + // Constructor + parameter( cstring name, cstring value, param_namespace const& parent ); + + BOOST_READONLY_PROPERTY( dstring, (parameter)) p_name; + BOOST_READONLY_PROPERTY( dstring, (parameter)) p_value; + + friend std::ostream& operator<<( std::ostream& os, parameter const& ); + +private: + // Data members + param_namespace const& m_parent; +}; + +// ************************************************************************** // +// ************** runtime::file::modifiers ************** // +// ************************************************************************** // + +namespace { +nfp::typed_keyword value_marker; +nfp::typed_keyword value_delimeter; +nfp::typed_keyword namespace_delimeter; +} // local namespace + +// ************************************************************************** // +// ************** runtime::file::param_namespace ************** // +// ************************************************************************** // + +class param_namespace { +public: + typedef std::list::iterator iterator; + typedef std::list::const_iterator const_iterator; + typedef std::list::iterator sub_ns_iterator; + typedef std::list::const_iterator sub_ns_const_iterator; + + // Public properties + BOOST_READONLY_PROPERTY( dstring, (param_namespace)) p_name; + unit_test::readonly_property p_parent; + + void load( config_file_iterator cf_it ) { load( cf_it, nfp::no_params ); } + template + void load( config_file_iterator cf_it, Modifier const& m ) + { + cstring vm = m.has( value_marker ) ? m[value_marker] : BOOST_TEST_UTILS_RUNTIME_PARAM_CSTRING_LITERAL( "\"" ); + cstring vd = m.has( value_delimeter ) ? m[value_delimeter] : BOOST_TEST_UTILS_RUNTIME_PARAM_CSTRING_LITERAL( "= \t\n\r" ); + cstring nd = m.has( namespace_delimeter ) ? m[namespace_delimeter] : BOOST_TEST_UTILS_RUNTIME_PARAM_CSTRING_LITERAL( "::" ); + + load_impl( cf_it, vm, vd, nd ); + } + void load( cstring file_name ) + { + load( file_name, nfp::no_params ); + } + template + void load( cstring file_name, Modifier const& m ) + { + config_file_iterator cfi( file_name, m ); + + load( cfi, m ); + } + + void insert_param( cstring param_name, cstring param_value ); + param_namespace& subnamespace( cstring namespace_name ); // find and insert if not present + void clear(); + + iterator begin() { return m_parameters.begin(); } + const_iterator begin() const { return m_parameters.begin(); } + + iterator end() { return m_parameters.end(); } + const_iterator end() const { return m_parameters.end(); } + + sub_ns_iterator sub_ns_begin() { return m_subnamespaces.begin(); } + sub_ns_const_iterator sub_ns_begin() const { return m_subnamespaces.begin(); } + + sub_ns_iterator sub_ns_end() { return m_subnamespaces.end(); } + sub_ns_const_iterator sub_ns_end() const { return m_subnamespaces.end(); } + + void print_full_name( std::ostream& os ) const; + +protected: + explicit param_namespace( cstring name, param_namespace const* parent = 0 ); + +private: + void load_impl( config_file_iterator cf_it, + cstring value_marker_, cstring value_delimeter_, cstring namespace_delimeter_ ); + + // Data members + std::list m_parameters; + std::list m_subnamespaces; +}; + +//____________________________________________________________________________// + +boost::optional +get_param_value( param_namespace const& where_from, + cstring name_part1, + cstring name_part2 = cstring(), + cstring name_part3 = cstring(), + cstring name_part4 = cstring(), + cstring name_part5 = cstring() ); + +//____________________________________________________________________________// + +cstring +get_requ_param_value( param_namespace const& where_from, + cstring name_part1, + cstring name_part2 = cstring(), + cstring name_part3 = cstring(), + cstring name_part4 = cstring(), + cstring name_part5 = cstring() ); + +//____________________________________________________________________________// + +param_namespace const* +get_param_subns( param_namespace const& where_from, + cstring namespace_name ); + +//____________________________________________________________________________// + +// ************************************************************************** // +// ************** runtime::file::config_file ************** // +// ************************************************************************** // + +class config_file : public param_namespace { +public: + // Constructor + config_file(); + config_file( cstring file_name ); +}; + +} // namespace file + +} // namespace BOOST_TEST_UTILS_RUNTIME_PARAM_NAMESPACE + +} // namespace boost + +#endif // BOOST_TEST_UTILS_RUNTIME_FILE_CONFIG_FILE_HPP_010105GER diff --git a/include/boost/test/utils/runtime/file/config_file_iterator.cpp b/include/boost/test/utils/runtime/file/config_file_iterator.cpp new file mode 100644 index 00000000..5d6cbdf7 --- /dev/null +++ b/include/boost/test/utils/runtime/file/config_file_iterator.cpp @@ -0,0 +1,685 @@ +// (C) Copyright Gennadiy Rozental 2005-2014. +// Use, modification, and distribution are subject to 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 : flexible configuration file iterator implementation +// *************************************************************************** + +// Boost.Runtime.Parameter +#include + +#include +#include + +#ifndef UNDER_CE +#include +#endif + + +// Boost +#include +#include +#include + +// Boost.Test +#include +#include +#include +#include + +// STL +#include +#include +#include +#include +#include +#include +#include + +namespace boost { + +namespace BOOST_TEST_UTILS_RUNTIME_PARAM_NAMESPACE { + +namespace file { + +// ************************************************************************** // +// ************** symbol_to_value_map ************** // +// ************************************************************************** // + +template +struct symbol_to_value_map : std::map { + template + void add( cstring name, ParamType const& value ) + { + using namespace unit_test; + + m_name_store.push_back( dstring() ); + + assign_op( m_name_store.back(), name, 0 ); + assign_op( (*this)[m_name_store.back()], value, 0 ); + } + void remove( cstring name ) + { + std::list::iterator it = std::find( m_name_store.begin(), m_name_store.end(), name ); + + m_name_store.erase( it ); + + this->erase( name ); + } + +private: + std::list m_name_store; +}; + +// ************************************************************************** // +// ************** symbol_table_t ************** // +// ************************************************************************** // + +typedef symbol_to_value_map symbol_table_t; + +// ************************************************************************** // +// ************** command_handler_map ************** // +// ************************************************************************** // + +typedef symbol_to_value_map command_handler_map; + +// ************************************************************************** // +// ************** is_valid_identifier ************** // +// ************************************************************************** // + +static bool +is_valid_identifier( cstring const& source ) +{ + if( source.is_empty() ) + return false; + + cstring::const_iterator it = source.begin(); + + if( !std::isalpha( *it ) ) + return false; + + while( ++it < source.end() ) { + if( !std::isalnum( *it ) && *it != BOOST_TEST_UTILS_RUNTIME_PARAM_LITERAL( '_' ) && *it != BOOST_TEST_UTILS_RUNTIME_PARAM_LITERAL( '-' ) ) + return false; + } + + return true; +} + +// ************************************************************************** // +// ************** include_level ************** // +// ************************************************************************** // + +struct include_level; +typedef std::auto_ptr include_level_ptr; + +struct include_level : noncopyable +{ + // Constructor + explicit include_level( cstring file_name, cstring path_separators, include_level* parent = 0 ); + + // Data members + std::ifstream m_stream; + location m_curr_location; + include_level_ptr m_parent; +}; + +//____________________________________________________________________________// + +include_level::include_level( cstring file_name, cstring path_separators, include_level* parent_ ) +: m_parent( parent_ ) +{ + if( file_name.is_empty() ) + return; + + assign_op( m_curr_location.first, file_name, 0 ); + m_curr_location.second = 0; + + m_stream.open( m_curr_location.first.c_str() ); + + if( !m_stream.is_open() && !!m_parent.get() ) { + cstring parent_path = m_parent->m_curr_location.first; + cstring::iterator it = unit_test::find_last_of( parent_path.begin(), parent_path.end(), + path_separators.begin(), + path_separators.end() ); + + if( it != parent_path.end() ) { + assign_op( m_curr_location.first, cstring( parent_path.begin(), it+1 ), 0 ); + m_curr_location.first.append( file_name.begin(), file_name.end() ); + m_stream.clear(); + m_stream.open( m_curr_location.first.c_str() ); + } + } + + BOOST_TEST_UTILS_RUNTIME_PARAM_VALIDATE_LOGIC( m_stream.is_open(), BOOST_TEST_UTILS_RUNTIME_PARAM_LITERAL( "can't open file " ) << file_name ); +} + +//____________________________________________________________________________// + +// ************************************************************************** // +// ************** config_file_iterator::Impl ************** // +// ************************************************************************** // + +struct config_file_iterator::Impl : noncopyable { + // Constructor + Impl(); + + bool get_next_line( cstring& next_line ); + + void process_command_line( cstring line ); + void process_include( cstring line ); + void process_define( cstring line ); + void process_undef( cstring line ); + void process_ifdef( cstring line ); + void process_ifndef( cstring line ); + void process_else( cstring line ); + void process_endif( cstring line ); + + boost::optional + get_macro_value( cstring macro_name, bool ignore_missing = true ); + void substitute_macros( cstring& where ); + + bool is_active_line() { return m_inactive_ifdef_level == 0; } + + static bool match_front( cstring str, cstring pattern ) + { + return str.size() >= pattern.size() && str.substr( 0, pattern.size() ) == pattern; + } + static bool match_back( cstring str, cstring pattern ) + { + return str.size() >= pattern.size() && str.substr( str.size() - pattern.size() ) == pattern; + } + + // Configurable parameters + dstring m_path_separators; + char_type m_line_delimeter; + dstring m_sl_comment_delimeter; + dstring m_command_delimeter; + dstring m_line_beak; + dstring m_macro_ref_begin; + dstring m_macro_ref_end; + + dstring m_include_kw; + dstring m_define_kw; + dstring m_undef_kw; + dstring m_ifdef_kw; + dstring m_ifndef_kw; + dstring m_else_kw; + dstring m_endif_kw; + + std::size_t m_buffer_size; + + bool m_trim_trailing_spaces; + bool m_trim_leading_spaces; + bool m_skip_empty_lines; + bool m_detect_missing_macro; + + // Data members + dstring m_post_subst_line; + scoped_array m_buffer; + include_level_ptr m_curr_level; + symbol_table_t m_symbols_table; + std::vector m_conditional_states; + std::size_t m_inactive_ifdef_level; + command_handler_map m_command_handler_map; +}; + +//____________________________________________________________________________// + +config_file_iterator::Impl::Impl() +: m_path_separators( BOOST_TEST_UTILS_RUNTIME_PARAM_LITERAL( "/\\" ) ) +, m_line_delimeter( BOOST_TEST_UTILS_RUNTIME_PARAM_LITERAL( '\n' ) ) +, m_sl_comment_delimeter( BOOST_TEST_UTILS_RUNTIME_PARAM_LITERAL( "#" ) ) +, m_command_delimeter( BOOST_TEST_UTILS_RUNTIME_PARAM_LITERAL( "$" ) ) +, m_line_beak( BOOST_TEST_UTILS_RUNTIME_PARAM_LITERAL( "\\" ) ) +, m_macro_ref_begin( BOOST_TEST_UTILS_RUNTIME_PARAM_LITERAL( "$" ) ) +, m_macro_ref_end( BOOST_TEST_UTILS_RUNTIME_PARAM_LITERAL( "$" ) ) + +, m_include_kw( BOOST_TEST_UTILS_RUNTIME_PARAM_LITERAL( "include" ) ) +, m_define_kw( BOOST_TEST_UTILS_RUNTIME_PARAM_LITERAL( "define" ) ) +, m_undef_kw( BOOST_TEST_UTILS_RUNTIME_PARAM_LITERAL( "undef" ) ) +, m_ifdef_kw( BOOST_TEST_UTILS_RUNTIME_PARAM_LITERAL( "ifdef" ) ) +, m_ifndef_kw( BOOST_TEST_UTILS_RUNTIME_PARAM_LITERAL( "ifndef" ) ) +, m_else_kw( BOOST_TEST_UTILS_RUNTIME_PARAM_LITERAL( "else" ) ) +, m_endif_kw( BOOST_TEST_UTILS_RUNTIME_PARAM_LITERAL( "endif" ) ) + +, m_buffer_size( 8192 ) + +, m_trim_trailing_spaces( true ) +, m_trim_leading_spaces( false ) +, m_skip_empty_lines( true ) +, m_detect_missing_macro( true ) + +, m_inactive_ifdef_level( 0 ) +{} + +//____________________________________________________________________________// + +bool +config_file_iterator::Impl::get_next_line( cstring& line ) +{ + bool broken_line = false; + + line.clear(); + + while( !m_curr_level->m_stream.eof() || !!m_curr_level->m_parent.get() ) { + // 10. Switch to upper include level if current one is finished + // 20. Read/append next file line + // 30. Increment line number + // 40. Remove comments + // 50. Remove trailing and leading spaces + // 60. Skip empty string + // 70. Concatenate broken lines if needed. Put the result into line + // 80. If line is not completed, try to finish it by reading the next line + // 90. Process command line + // 100. Substitute macros references with their definitions + // 110. Next line found. + + if( m_curr_level->m_stream.eof() ) { // 10 // + m_curr_level = m_curr_level->m_parent; + continue; + } + + std::ifstream& input = m_curr_level->m_stream; + char_type* buffer_insert_pos = broken_line ? m_buffer.get() + line.size() : m_buffer.get(); + + input.getline( buffer_insert_pos, (std::streamsize)(m_buffer_size - line.size()), // 20 // + m_line_delimeter ); + + cstring next_line( buffer_insert_pos, + input.gcount() > 0 + ? buffer_insert_pos + (input.eof() ? input.gcount() : (input.gcount()-1)) + : buffer_insert_pos ); + + + m_curr_level->m_curr_location.second++; // 30 // + + cstring::size_type comment_pos = next_line.find( m_sl_comment_delimeter ); + if( comment_pos != cstring::npos ) + next_line.trim_right( next_line.begin()+comment_pos ); // 40 // + + if( m_trim_trailing_spaces ) // 50 // + next_line.trim_right(); + if( m_trim_leading_spaces && !broken_line ) + next_line.trim_left(); + + if( next_line.is_empty() ) { // 60 // + if( m_skip_empty_lines ) + continue; + else + next_line.assign( buffer_insert_pos, buffer_insert_pos ); + } + + line = broken_line ? cstring( line.begin(), next_line.end() ) : next_line; // 70 // + + broken_line = match_back( line, m_line_beak ); + if( broken_line ) { // 80 // + line.trim_right( 1 ); + continue; + } + + if( match_front( line, m_command_delimeter ) ) { // 90 // + process_command_line( line ); + continue; + } + + if( !is_active_line() ) + continue; + + substitute_macros( line ); // 100 // + + return true; // 110 // + } + + BOOST_TEST_UTILS_RUNTIME_PARAM_VALIDATE_LOGIC( !broken_line, BOOST_TEST_UTILS_RUNTIME_PARAM_LITERAL( "broken line is not completed" ) ); + BOOST_TEST_UTILS_RUNTIME_PARAM_VALIDATE_LOGIC( m_conditional_states.size() == 0, + BOOST_TEST_UTILS_RUNTIME_PARAM_LITERAL( "matching endif command is missing" ) ); + + return false; +} + +//____________________________________________________________________________// + +boost::optional +config_file_iterator::Impl::get_macro_value( cstring macro_name, bool ignore_missing ) +{ + symbol_table_t::const_iterator it = m_symbols_table.find( macro_name ); + + if( it == m_symbols_table.end() ) { + boost::optional macro_value; // !! variable actually may have different type + + #ifndef UNDER_CE + env::get( macro_name, macro_value ); + #endif + + BOOST_TEST_UTILS_RUNTIME_PARAM_VALIDATE_LOGIC( macro_value || ignore_missing || !m_detect_missing_macro, + BOOST_TEST_UTILS_RUNTIME_PARAM_LITERAL( "Unknown macro \"" ) << macro_name << BOOST_TEST_UTILS_RUNTIME_PARAM_LITERAL( "\"" ) ); + + if( !macro_value ) { + if( !ignore_missing ) + macro_value = cstring(); + } + else + m_symbols_table.add( macro_name, *macro_value ); + + return macro_value; + } + + return boost::optional( cstring( it->second ) ); +} + +//____________________________________________________________________________// + +void +config_file_iterator::Impl::process_command_line( cstring line ) +{ + line.trim_left( m_command_delimeter.size() ); + + unit_test::string_token_iterator tit( line, unit_test::max_tokens = 2 ); + + command_handler_map::const_iterator it = m_command_handler_map.find( *tit ); + + BOOST_TEST_UTILS_RUNTIME_PARAM_VALIDATE_LOGIC( it != m_command_handler_map.end(), BOOST_TEST_UTILS_RUNTIME_PARAM_LITERAL( "Invalid command " ) << *tit ); + + ++tit; + + (it->second)( *tit ); +} + +//____________________________________________________________________________// + +void +config_file_iterator::Impl::process_include( cstring line ) +{ + using namespace unit_test; + + if( !is_active_line() ) + return; + + string_token_iterator tit( line, kept_delimeters = dt_none ); + + BOOST_TEST_UTILS_RUNTIME_PARAM_VALIDATE_LOGIC( tit != string_token_iterator(), + BOOST_TEST_UTILS_RUNTIME_PARAM_LITERAL( "include file name missing" ) ); + + cstring include_file_name = *tit; + + BOOST_TEST_UTILS_RUNTIME_PARAM_VALIDATE_LOGIC( ++tit == string_token_iterator(), + BOOST_TEST_UTILS_RUNTIME_PARAM_LITERAL( "unexpected tokens at the end of include command" ) ); + + substitute_macros( include_file_name ); + + m_curr_level.reset( new include_level( include_file_name, m_path_separators, m_curr_level.release() ) ); +} + +//____________________________________________________________________________// + +void +config_file_iterator::Impl::process_define( cstring line ) +{ + using namespace unit_test; + + if( !is_active_line() ) + return; + + string_token_iterator tit( line, (kept_delimeters = dt_none, max_tokens = 2 )); + + cstring macro_name = *tit; + BOOST_TEST_UTILS_RUNTIME_PARAM_VALIDATE_LOGIC( is_valid_identifier( macro_name ), + BOOST_TEST_UTILS_RUNTIME_PARAM_LITERAL( "invalid macro name" ) ); + + cstring macro_value = *(++tit); + substitute_macros( macro_value ); + + m_symbols_table.add( macro_name, macro_value ); +} + +//____________________________________________________________________________// + +void +config_file_iterator::Impl::process_undef( cstring line ) +{ + if( !is_active_line() ) + return; + + cstring macro_name = line; + BOOST_TEST_UTILS_RUNTIME_PARAM_VALIDATE_LOGIC( is_valid_identifier( macro_name ), + BOOST_TEST_UTILS_RUNTIME_PARAM_LITERAL( "invalid macro name" ) ); + + m_symbols_table.remove( macro_name ); +} + +//____________________________________________________________________________// + +void +config_file_iterator::Impl::process_ifdef( cstring line ) +{ + m_conditional_states.push_back( true ); + if( !is_active_line() ) + return; + + cstring macro_name = line; + BOOST_TEST_UTILS_RUNTIME_PARAM_VALIDATE_LOGIC( is_valid_identifier( macro_name ), + BOOST_TEST_UTILS_RUNTIME_PARAM_LITERAL( "invalid macro name" ) ); + + if( !get_macro_value( macro_name ) ) + m_inactive_ifdef_level = m_conditional_states.size(); +} + +//____________________________________________________________________________// + +void +config_file_iterator::Impl::process_ifndef( cstring line ) +{ + m_conditional_states.push_back( true ); + if( !is_active_line() ) + return; + + cstring macro_name = line; + BOOST_TEST_UTILS_RUNTIME_PARAM_VALIDATE_LOGIC( is_valid_identifier( macro_name ), + BOOST_TEST_UTILS_RUNTIME_PARAM_LITERAL( "invalid macro name" ) ); + + if( get_macro_value( macro_name ) ) + m_inactive_ifdef_level = m_conditional_states.size(); +} + +//____________________________________________________________________________// + +void +config_file_iterator::Impl::process_else( cstring line ) +{ + BOOST_TEST_UTILS_RUNTIME_PARAM_VALIDATE_LOGIC( m_conditional_states.size() > 0 && m_conditional_states.back(), + BOOST_TEST_UTILS_RUNTIME_PARAM_LITERAL( "else without matching if" ) ); + + m_inactive_ifdef_level = m_conditional_states.size() == m_inactive_ifdef_level ? 0 : m_conditional_states.size(); + + BOOST_TEST_UTILS_RUNTIME_PARAM_VALIDATE_LOGIC( line.is_empty(), BOOST_TEST_UTILS_RUNTIME_PARAM_LITERAL( "unexpected tokens at the end of else command" ) ); +} + +//____________________________________________________________________________// + +void +config_file_iterator::Impl::process_endif( cstring line ) +{ + BOOST_TEST_UTILS_RUNTIME_PARAM_VALIDATE_LOGIC( m_conditional_states.size() > 0, BOOST_TEST_UTILS_RUNTIME_PARAM_LITERAL( "endif without matching if" ) ); + + if( m_conditional_states.size() == m_inactive_ifdef_level ) + m_inactive_ifdef_level = 0; + + m_conditional_states.pop_back(); + BOOST_TEST_UTILS_RUNTIME_PARAM_VALIDATE_LOGIC( line.is_empty(), BOOST_TEST_UTILS_RUNTIME_PARAM_LITERAL( "unexpected tokens at the end of endif command" ) ); +} + +//____________________________________________________________________________// + +void +config_file_iterator::Impl::substitute_macros( cstring& where ) +{ + m_post_subst_line.clear(); + cstring::size_type pos; + + while( (pos = where.find( m_macro_ref_begin )) != cstring::npos ) { + m_post_subst_line.append( where.begin(), pos ); + + where.trim_left( where.begin() + pos + m_macro_ref_begin.size() ); + + pos = where.find( m_macro_ref_end ); + + BOOST_TEST_UTILS_RUNTIME_PARAM_VALIDATE_LOGIC( pos != cstring::npos, BOOST_TEST_UTILS_RUNTIME_PARAM_LITERAL( "incomplete macro reference" ) ); + + cstring value = *get_macro_value( where.substr( 0, pos ), false ); + m_post_subst_line.append( value.begin(), value.size() ); + + where.trim_left( where.begin() + pos + m_macro_ref_end.size() ); + } + + if( !m_post_subst_line.empty() ) { + m_post_subst_line.append( where.begin(), where.size() ); + where = m_post_subst_line; + } +} + +//____________________________________________________________________________// + +// ************************************************************************** // +// ************** runtime::file::config_file_iterator ************** // +// ************************************************************************** // + +void +config_file_iterator::construct() +{ + m_pimpl.reset( new Impl ); +} + +//____________________________________________________________________________// + +void +config_file_iterator::load( cstring file_name ) +{ + m_pimpl->m_curr_level.reset( new include_level( file_name, m_pimpl->m_path_separators ) ); + m_pimpl->m_buffer.reset( new char[m_pimpl->m_buffer_size] ); + + register_command_handler( m_pimpl->m_include_kw, boost::bind( &Impl::process_include, m_pimpl.get(), _1 ) ); + register_command_handler( m_pimpl->m_define_kw, boost::bind( &Impl::process_define, m_pimpl.get(), _1 ) ); + register_command_handler( m_pimpl->m_undef_kw, boost::bind( &Impl::process_undef, m_pimpl.get(), _1 ) ); + register_command_handler( m_pimpl->m_ifdef_kw, boost::bind( &Impl::process_ifdef, m_pimpl.get(), _1 ) ); + register_command_handler( m_pimpl->m_ifndef_kw, boost::bind( &Impl::process_ifndef, m_pimpl.get(), _1 ) ); + register_command_handler( m_pimpl->m_else_kw, boost::bind( &Impl::process_else, m_pimpl.get(), _1 ) ); + register_command_handler( m_pimpl->m_endif_kw, boost::bind( &Impl::process_endif, m_pimpl.get(), _1 ) ); + + init(); +} + +//____________________________________________________________________________// + +location const& +config_file_iterator::curr_location() +{ + return m_pimpl->m_curr_level->m_curr_location; +} + +//____________________________________________________________________________// + +void +config_file_iterator::register_command_handler( cstring command_kw, command_handler const& ch ) +{ + m_pimpl->m_command_handler_map.add( command_kw, ch ); +} + +//____________________________________________________________________________// + +bool +config_file_iterator::get() +{ + return m_pimpl->get_next_line( m_value ); +} + +//____________________________________________________________________________// + +void +config_file_iterator::set_parameter( rtti::id_t id, cstring value ) +{ + BOOST_RTTI_SWITCH( id ) { + BOOST_RTTI_CASE( cfg_detail::path_separators_t ) + assign_op( m_pimpl->m_path_separators , value, 0 ); + BOOST_RTTI_CASE( cfg_detail::sl_comment_delimeter_t ) + assign_op( m_pimpl->m_sl_comment_delimeter , value, 0 ); + BOOST_RTTI_CASE( cfg_detail::command_delimeter_t ) + assign_op( m_pimpl->m_command_delimeter , value, 0 ); + BOOST_RTTI_CASE( cfg_detail::line_beak_t ) + assign_op( m_pimpl->m_line_beak , value, 0 ); + BOOST_RTTI_CASE( cfg_detail::macro_ref_begin_t ) + assign_op( m_pimpl->m_macro_ref_begin , value, 0 ); + BOOST_RTTI_CASE( cfg_detail::macro_ref_end_t ) + assign_op( m_pimpl->m_macro_ref_end , value, 0 ); + BOOST_RTTI_CASE( cfg_detail::include_kw_t ) + assign_op( m_pimpl->m_include_kw , value, 0 ); + BOOST_RTTI_CASE( cfg_detail::define_kw_t ) + assign_op( m_pimpl->m_define_kw , value, 0 ); + BOOST_RTTI_CASE( cfg_detail::undef_kw_t ) + assign_op( m_pimpl->m_undef_kw , value, 0 ); + BOOST_RTTI_CASE( cfg_detail::ifdef_kw_t ) + assign_op( m_pimpl->m_ifdef_kw , value, 0 ); + BOOST_RTTI_CASE( cfg_detail::ifndef_kw_t ) + assign_op( m_pimpl->m_ifndef_kw , value, 0 ); + BOOST_RTTI_CASE( cfg_detail::else_kw_t ) + assign_op( m_pimpl->m_else_kw , value, 0 ); + BOOST_RTTI_CASE( cfg_detail::endif_kw_t ) + assign_op( m_pimpl->m_endif_kw , value, 0 ); + } +} + +//____________________________________________________________________________// + +void +config_file_iterator::set_parameter( rtti::id_t id, bool value ) +{ + BOOST_RTTI_SWITCH( id ) { + BOOST_RTTI_CASE( cfg_detail::trim_leading_spaces_t ) + m_pimpl->m_trim_leading_spaces = value; + BOOST_RTTI_CASE( cfg_detail::trim_trailing_spaces_t ) + m_pimpl->m_trim_trailing_spaces = value; + BOOST_RTTI_CASE( cfg_detail::skip_empty_lines_t ) + m_pimpl->m_skip_empty_lines = value; + BOOST_RTTI_CASE( cfg_detail::detect_missing_macro_t ) + m_pimpl->m_detect_missing_macro = value; + } +} + +//____________________________________________________________________________// + +void +config_file_iterator::set_parameter( rtti::id_t id, char_type value ) +{ + BOOST_RTTI_SWITCH( id ) { + BOOST_RTTI_CASE( cfg_detail::line_delimeter_t ) + m_pimpl->m_line_delimeter = value; + } +} + +//____________________________________________________________________________// + +void +config_file_iterator::set_parameter( rtti::id_t id, std::size_t value ) +{ + BOOST_RTTI_SWITCH( id ) { + BOOST_RTTI_CASE( cfg_detail::buffer_size_t ) + m_pimpl->m_buffer_size = value; + } +} + +//____________________________________________________________________________// + +} // namespace file + +} // namespace BOOST_TEST_UTILS_RUNTIME_PARAM_NAMESPACE + +} // namespace boost + +// EOF diff --git a/include/boost/test/utils/runtime/file/config_file_iterator.hpp b/include/boost/test/utils/runtime/file/config_file_iterator.hpp new file mode 100644 index 00000000..6c6273fc --- /dev/null +++ b/include/boost/test/utils/runtime/file/config_file_iterator.hpp @@ -0,0 +1,166 @@ +// (C) Copyright Gennadiy Rozental 2005-2014. +// Use, modification, and distribution are subject to 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 : flexible configuration file iterator definition +// *************************************************************************** + +#ifndef BOOST_TEST_UTILS_RUNTIME_FILE_CONFIG_FILE_ITERATOR_HPP +#define BOOST_TEST_UTILS_RUNTIME_FILE_CONFIG_FILE_ITERATOR_HPP + +// Boost.Runtime.Parameter +#include + +#include + +// Boost.Test +#include +#include + +// Boost +#include +#include + +namespace boost { + +namespace BOOST_TEST_UTILS_RUNTIME_PARAM_NAMESPACE { + +namespace file { + +// Public typedef +typedef std::pair location; + +// ************************************************************************** // +// ************** modifiers ************** // +// ************************************************************************** // + +namespace cfg_detail { + struct path_separators_t; + struct line_delimeter_t; + struct sl_comment_delimeter_t; + struct command_delimeter_t; + struct line_beak_t; + struct macro_ref_begin_t; + struct macro_ref_end_t; + struct include_kw_t; + struct define_kw_t; + struct undef_kw_t; + struct ifdef_kw_t; + struct ifndef_kw_t; + struct else_kw_t; + struct endif_kw_t; + + struct buffer_size_t; + + struct trim_leading_spaces_t; + struct trim_trailing_spaces_t; + struct skip_empty_lines_t; + struct detect_missing_macro_t; +} // namespace cfg_detail + +namespace { + +nfp::typed_keyword path_separators; +nfp::typed_keyword line_delimeter; +nfp::typed_keyword single_line_comment_delimeter; +nfp::typed_keyword command_delimeter; +nfp::typed_keyword line_beak; +nfp::typed_keyword macro_ref_begin; +nfp::typed_keyword macro_ref_end; +nfp::typed_keyword include_kw; +nfp::typed_keyword define_kw; +nfp::typed_keyword undef_kw; +nfp::typed_keyword ifdef_kw; +nfp::typed_keyword ifndef_kw; +nfp::typed_keyword else_kw; +nfp::typed_keyword endif_kw; + +nfp::typed_keyword buffer_size; + +nfp::typed_keyword trim_leading_spaces; +nfp::typed_keyword trim_trailing_spaces; +nfp::typed_keyword skip_empty_lines; +nfp::typed_keyword detect_missing_macro; + +} // local namespace + +// ************************************************************************** // +// ************** runtime::file::config_file_iterator ************** // +// ************************************************************************** // + +class config_file_iterator : public unit_test::input_iterator_facade { + typedef unit_test::input_iterator_facade base; +public: + // Public typedefs + typedef boost::function command_handler; + + // Constructors + config_file_iterator() {} + explicit config_file_iterator( cstring file_name ) + { + construct(); + load( file_name ); + } + template + config_file_iterator( cstring file_name, Modifiers const& m ) + { + construct(); + m.apply_to( *this ); + load( file_name ); + } + config_file_iterator( config_file_iterator const& rhs ) + : base( rhs ) + , m_pimpl( rhs.m_pimpl ) + { + rhs.m_valid = false; + } + + void operator=( config_file_iterator const& rhs ) + { + if( this == &rhs ) + return; + + (base&)(*this) = rhs; + m_pimpl = rhs.m_pimpl; + rhs.m_valid = false; + } // Assignment + + + // Access methods + location const& curr_location(); + void register_command_handler( cstring command_kw, command_handler const& ); + + // Parameters setters + void set_parameter( rtti::id_t, cstring ); + void set_parameter( rtti::id_t, bool ); + void set_parameter( rtti::id_t, char_type ); + void set_parameter( rtti::id_t, std::size_t ); + +private: + friend class unit_test::input_iterator_core_access; + + void construct(); + void load( cstring file_name ); + + // increment implementation + bool get(); + + // Data members + struct Impl; + shared_ptr m_pimpl; +}; + +} // namespace file + +} // namespace BOOST_TEST_UTILS_RUNTIME_PARAM_NAMESPACE + +} // namespace boost + +#endif // BOOST_TEST_UTILS_RUNTIME_FILE_CONFIG_FILE_ITERATOR_HPP diff --git a/include/boost/test/utils/runtime/finalize.hpp b/include/boost/test/utils/runtime/finalize.hpp deleted file mode 100644 index fa728145..00000000 --- a/include/boost/test/utils/runtime/finalize.hpp +++ /dev/null @@ -1,56 +0,0 @@ -// (C) Copyright Gennadiy Rozental 2015. -// 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 : runtime parameters initialization final step -// *************************************************************************** - -#ifndef BOOST_TEST_UTILS_RUNTIME_FINALIZE_HPP -#define BOOST_TEST_UTILS_RUNTIME_FINALIZE_HPP - -// Boost.Test Runtime parameters -#include -#include - -// Boost.Test -#include - -#include - -namespace boost { -namespace runtime { - -inline void -finalize_arguments( parameters_store const& params, runtime::arguments_store& args ) -{ - BOOST_TEST_FOREACH( parameters_store::storage_type::value_type const&, v, params.all() ) { - basic_param_ptr param = v.second; - - if( !args.has( param->p_name ) ) { - if( param->p_has_default_value ) - param->produce_default( args ); - - if( !args.has( param->p_name ) ) { - BOOST_TEST_I_ASSRT( param->p_optional, - missing_req_arg( param->p_name ) << "Missing argument for required parameter " << param->p_name << "." ); - } - } - - if( args.has( param->p_name ) && !!param->p_callback ) - param->p_callback( param->p_name ); - } -} - -} // namespace runtime -} // namespace boost - -#include - -#endif // BOOST_TEST_UTILS_RUNTIME_FINALIZE_HPP diff --git a/include/boost/test/utils/runtime/fwd.hpp b/include/boost/test/utils/runtime/fwd.hpp index 3039d046..2647184c 100644 --- a/include/boost/test/utils/runtime/fwd.hpp +++ b/include/boost/test/utils/runtime/fwd.hpp @@ -1,4 +1,4 @@ -// (C) Copyright Gennadiy Rozental 2005-2015. +// (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) @@ -9,37 +9,33 @@ // // Version : $Revision$ // -// Description : runtime parameters forward declaration +// Description : global framework level forward declaration // *************************************************************************** #ifndef BOOST_TEST_UTILS_RUNTIME_FWD_HPP #define BOOST_TEST_UTILS_RUNTIME_FWD_HPP -// Boost.Test -#include -#include -#include // operator<<(boost::runtime::cstring) +// Boost.Runtime.Parameter +#include // Boost #include -// STL -#include - namespace boost { -namespace runtime { -typedef unit_test::const_string cstring; +namespace BOOST_TEST_UTILS_RUNTIME_PARAM_NAMESPACE { + +class parameter; class argument; typedef shared_ptr argument_ptr; +typedef shared_ptr const_argument_ptr; +template class value_interpreter; template class typed_argument; -class basic_param; -typedef shared_ptr basic_param_ptr; +} // namespace BOOST_TEST_UTILS_RUNTIME_PARAM_NAMESPACE -} // namespace runtime } // namespace boost #endif // BOOST_TEST_UTILS_RUNTIME_FWD_HPP diff --git a/include/boost/test/utils/runtime/interpret_argument_value.hpp b/include/boost/test/utils/runtime/interpret_argument_value.hpp new file mode 100644 index 00000000..016caa01 --- /dev/null +++ b/include/boost/test/utils/runtime/interpret_argument_value.hpp @@ -0,0 +1,163 @@ +// (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 : $RCSfile$ +// +// Version : $Revision$ +// +// Description : default algorithms for string to specific type convertions +// *************************************************************************** + +#ifndef BOOST_TEST_UTILS_RUNTIME_INTERPRET_ARGUMENT_VALUE_HPP +#define BOOST_TEST_UTILS_RUNTIME_INTERPRET_ARGUMENT_VALUE_HPP + +// Boost.Runtime.Parameter +#include +#include + +// Boost.Test +#include +#include + +// Boost +#include +#include + +// STL +// !! could we eliminate these includes? +#include + +namespace boost { + +namespace BOOST_TEST_UTILS_RUNTIME_PARAM_NAMESPACE { + +// ************************************************************************** // +// ************** runtime::interpret_argument_value ************** // +// ************************************************************************** // +// returns true if source is used false otherwise + +// generic case +template +struct interpret_argument_value_impl { + static bool _( cstring source, boost::optional& res ) + { + BOOST_TEST_UTILS_RUNTIME_PARAM_TRACE( "In interpret_argument_value_impl<" << typeid(T).name() << ">" ); + + res = lexical_cast( source ); + + BOOST_TEST_UTILS_RUNTIME_PARAM_TRACE( "String " << source << " is interpreted as " << *res ); + return true; + } +}; + + +//____________________________________________________________________________// + +// dstring case +template<> +struct interpret_argument_value_impl { + static bool _( cstring source, boost::optional& res ) + { + BOOST_TEST_UTILS_RUNTIME_PARAM_TRACE( "In interpret_argument_value_impl" ); + + res = dstring(); + assign_op( *res, source, 0 ); + + return true; + } +}; + +//____________________________________________________________________________// + +// cstring case +template<> +struct interpret_argument_value_impl { + static bool _( cstring source, boost::optional& res ) + { + BOOST_TEST_UTILS_RUNTIME_PARAM_TRACE( "In interpret_argument_value_impl" ); + + res = source; + + return true; + } +}; + +//____________________________________________________________________________// + +// specialization for type bool +template<> +struct interpret_argument_value_impl { + static bool _( cstring source, boost::optional& res ) + { + BOOST_TEST_UTILS_RUNTIME_PARAM_TRACE( "In interpret_argument_value_impl" ); + + static literal_cstring YES( BOOST_TEST_UTILS_RUNTIME_PARAM_CSTRING_LITERAL( "YES" ) ); + static literal_cstring Y( BOOST_TEST_UTILS_RUNTIME_PARAM_CSTRING_LITERAL( "Y" ) ); + static literal_cstring NO( BOOST_TEST_UTILS_RUNTIME_PARAM_CSTRING_LITERAL( "NO" ) ); + static literal_cstring N( BOOST_TEST_UTILS_RUNTIME_PARAM_CSTRING_LITERAL( "N" ) ); + static literal_cstring one( BOOST_TEST_UTILS_RUNTIME_PARAM_CSTRING_LITERAL( "1" ) ); + static literal_cstring zero( BOOST_TEST_UTILS_RUNTIME_PARAM_CSTRING_LITERAL( "0" ) ); + + source.trim(); + + if( case_ins_eq( source, YES ) || case_ins_eq( source, Y ) || case_ins_eq( source, one ) ) { + res = true; + return true; + } + else if( case_ins_eq( source, NO ) || case_ins_eq( source, N ) || case_ins_eq( source, zero ) ) { + res = false; + return true; + } + else { + res = true; + return source.is_empty(); + } + } +}; + +//____________________________________________________________________________// + +template +inline bool +interpret_argument_value( cstring source, boost::optional& res, long ) +{ + return interpret_argument_value_impl::_( source, res ); +} + +//____________________________________________________________________________// + +// specialization for list of values +template +inline bool +interpret_argument_value( cstring source, boost::optional >& res, int ) +{ + BOOST_TEST_UTILS_RUNTIME_PARAM_TRACE( "In interpret_argument_value>" ); + + res = std::list(); + + while( !source.is_empty() ) { + // !! should we use token_iterator + cstring::iterator single_value_end = std::find( source.begin(), source.end(), BOOST_TEST_UTILS_RUNTIME_PARAM_LITERAL( ',' ) ); + + boost::optional value; + interpret_argument_value( cstring( source.begin(), single_value_end ), value, 0 ); + + res->push_back( *value ); + + source.trim_left( single_value_end + 1 ); + } + + return true; +} + +//____________________________________________________________________________// + +} // namespace BOOST_TEST_UTILS_RUNTIME_PARAM_NAMESPACE + +} // namespace boost + +#endif // BOOST_TEST_UTILS_RUNTIME_INTERPRET_ARGUMENT_VALUE_HPP diff --git a/include/boost/test/utils/runtime/modifier.hpp b/include/boost/test/utils/runtime/modifier.hpp deleted file mode 100644 index 6e02ceb1..00000000 --- a/include/boost/test/utils/runtime/modifier.hpp +++ /dev/null @@ -1,58 +0,0 @@ -// (C) Copyright Gennadiy Rozental 2005-2015. -// Use, modification, and distribution are subject to 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 : parameter modifiers -// *************************************************************************** - -#ifndef BOOST_TEST_UTILS_RUNTIME_MODIFIER_HPP -#define BOOST_TEST_UTILS_RUNTIME_MODIFIER_HPP - -// Boost.Test Runtime parameters -#include - -// Boost.Test -#include - -#include - -namespace boost { -namespace runtime { - -// ************************************************************************** // -// ************** environment variable modifiers ************** // -// ************************************************************************** // - -namespace { - -nfp::typed_keyword description; -nfp::typed_keyword help; -nfp::typed_keyword env_var; -nfp::typed_keyword end_of_params; -nfp::typed_keyword negation_prefix; -nfp::typed_keyword value_hint; - -template -using enum_values = unit_test::ut_detail::static_constant< - nfp::typed_keyword>, struct enum_values_t> ->; - -nfp::keyword optional_value; -nfp::keyword default_value; -nfp::keyword callback; - -} // local namespace - -} // namespace runtime -} // namespace boost - -#include - -#endif // BOOST_TEST_UTILS_RUNTIME_MODIFIER_HPP diff --git a/include/boost/test/utils/runtime/parameter.hpp b/include/boost/test/utils/runtime/parameter.hpp index e48b4ff5..2dd4ba72 100644 --- a/include/boost/test/utils/runtime/parameter.hpp +++ b/include/boost/test/utils/runtime/parameter.hpp @@ -1,4 +1,4 @@ -// (C) Copyright Gennadiy Rozental 2015. +// (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) @@ -9,442 +9,30 @@ // // Version : $Revision$ // -// Description : formal parameter definition +// Description : abstract interface for the formal parameter // *************************************************************************** #ifndef BOOST_TEST_UTILS_RUNTIME_PARAMETER_HPP #define BOOST_TEST_UTILS_RUNTIME_PARAMETER_HPP -// Boost.Test Runtime parameters -#include -#include -#include -#include - -// Boost.Test -#include -#include - -// Boost -#include - -// STL -#include - -#include +// Boost.Runtime.Parameter +#include namespace boost { -namespace runtime { -// ************************************************************************** // -// ************** runtime::parameter_cla_id ************** // -// ************************************************************************** // -// set of attributes identifying the parameter in the command line - -struct parameter_cla_id { - parameter_cla_id( cstring prefix, cstring tag, cstring value_separator, bool negatable ) - : m_prefix( prefix.begin(), prefix.size() ) - , m_tag( tag.begin(), tag.size() ) - , m_value_separator( value_separator.begin(), value_separator.size() ) - , m_negatable( negatable ) - { - - BOOST_TEST_I_ASSRT( std::all_of( m_prefix.begin(), m_prefix.end(), valid_prefix_char ), - invalid_cla_id() << "Parameter " << m_tag - << " has invalid characters in prefix." ); - - BOOST_TEST_I_ASSRT( std::all_of( m_tag.begin(), m_tag.end(), valid_name_char ), - invalid_cla_id() << "Parameter " << m_tag - << " has invalid characters in name." ); - - BOOST_TEST_I_ASSRT( std::all_of( m_value_separator.begin(), m_value_separator.end(), valid_separator_char ), - invalid_cla_id() << "Parameter " << m_tag - << " has invalid characters in value separator." ); - } - - static bool valid_prefix_char( char c ) - { - return c == '-' || c == '/' ; - } - static bool valid_separator_char( char c ) - { - return c == '=' || c == ':' || c == ' ' || c == '\0'; - } - static bool valid_name_char( char c ) - { - return std::isalnum( c ) || c == '+' || c == '_' || c == '?'; - } - - std::string m_prefix; - std::string m_tag; - std::string m_value_separator; - bool m_negatable; -}; - -typedef std::vector param_cla_ids; - -// ************************************************************************** // -// ************** runtime::basic_param ************** // -// ************************************************************************** // - -cstring const help_prefix("////"); - -class basic_param { - typedef function callback_type; - typedef unit_test::readwrite_property bool_property; - -protected: - /// Constructor with modifiers - template - basic_param( cstring name, bool is_optional, bool is_repeatable, Modifiers const& m ) - : p_name( name.begin(), name.end() ) - , p_description( nfp::opt_get( m, description, std::string{} ) ) - , p_help( nfp::opt_get( m, runtime::help, std::string{} ) ) - , p_env_var( nfp::opt_get( m, env_var, std::string{} ) ) - , p_value_hint( nfp::opt_get( m, value_hint, std::string{} ) ) - , p_optional( is_optional ) - , p_repeatable( is_repeatable ) - , p_has_optional_value( m.has( optional_value ) ) - , p_has_default_value( m.has( default_value ) || is_repeatable ) - , p_callback( nfp::opt_get( m, callback, callback_type{} ) ) - { - add_cla_id( help_prefix, name, ":" ); - } - -public: - virtual ~basic_param() {} - - // Pubic properties - std::string const p_name; - std::string const p_description; - std::string const p_help; - std::string const p_env_var; - std::string const p_value_hint; - bool const p_optional; - bool const p_repeatable; - bool_property p_has_optional_value; - bool_property p_has_default_value; - callback_type const p_callback; - - /// interface for cloning typed parameters - virtual basic_param_ptr clone() const = 0; - - /// Access methods - param_cla_ids const& cla_ids() const { return m_cla_ids; } - void add_cla_id( cstring prefix, cstring tag, cstring value_separator ) - { - add_cla_id_impl( prefix, tag, value_separator, false, true ); - } - - /// interface for producing argument values for this parameter - virtual void produce_argument( cstring token, bool negative_form, arguments_store& store ) const = 0; - virtual void produce_default( arguments_store& store ) const = 0; - - /// interfaces for help message reporting - virtual void usage( std::ostream& ostr, cstring negation_prefix ) - { - ostr << "Parameter: " << p_name << '\n'; - if( !p_description.empty() ) - 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; - if( id.m_negatable ) - cla_name_help( ostr, id.m_tag, negation_prefix ); - else - cla_name_help( ostr, id.m_tag, "" ); - - bool optional_value = false; - - if( p_has_optional_value ) { - optional_value = true; - ostr << '['; - } - - if( id.m_value_separator.empty() ) - ostr << ' '; - else { - ostr << id.m_value_separator; - } - - value_help( ostr ); - - if( optional_value ) - ostr << ']'; - - ostr << '\n'; - } - if( !p_env_var.empty() ) - ostr << " Environment variable: " << p_env_var << '\n'; - } - - virtual void help( std::ostream& ostr, cstring negation_prefix ) - { - usage( ostr, negation_prefix ); - - if( !p_help.empty() ) - ostr << '\n' << p_help << '\n'; - } - -protected: - void add_cla_id_impl( cstring prefix, - cstring tag, - cstring value_separator, - bool negatable, - bool validate_value_separator ) - { - BOOST_TEST_I_ASSRT( !tag.is_empty(), - invalid_cla_id() << "Parameter can't have an empty name." ); - - BOOST_TEST_I_ASSRT( !prefix.is_empty(), - invalid_cla_id() << "Parameter " << tag - << " can't have an empty prefix." ); - - BOOST_TEST_I_ASSRT( !value_separator.is_empty(), - invalid_cla_id() << "Parameter " << tag - << " can't have an empty value separator." ); - - // We trim value separator from all the spaces, so token end will indicate separator - value_separator.trim(); - BOOST_TEST_I_ASSRT( !validate_value_separator || !value_separator.is_empty() || !p_has_optional_value, - invalid_cla_id() << "Parameter " << tag - << " with optional value attribute can't use space as value separator." ); - - m_cla_ids.push_back( parameter_cla_id( prefix, tag, value_separator, negatable ) ); - } - -private: - /// interface for usage/help customization - virtual void cla_name_help( std::ostream& ostr, cstring cla_tag, cstring negation_prefix ) const - { - ostr << cla_tag; - } - virtual void value_help( std::ostream& ostr ) const - { - if( p_value_hint.empty() ) - ostr << ""; - else - ostr << p_value_hint; - } - - // Data members - param_cla_ids m_cla_ids; -}; +namespace BOOST_TEST_UTILS_RUNTIME_PARAM_NAMESPACE { // ************************************************************************** // // ************** runtime::parameter ************** // // ************************************************************************** // -enum args_amount { - OPTIONAL_PARAM, // 0-1 - REQUIRED_PARAM, // exactly 1 - REPEATABLE_PARAM // 0-N -}; - -//____________________________________________________________________________// - -template -class parameter : public basic_param { +class parameter { public: - /// Constructor with modifiers - template - parameter( cstring name, Modifiers const& m = nfp::no_params ) - : basic_param( name, a != runtime::REQUIRED_PARAM, a == runtime::REPEATABLE_PARAM, m ) - , m_arg_factory( m ) - { - BOOST_TEST_I_ASSRT( !m.has( default_value ) || a == runtime::OPTIONAL_PARAM, - invalid_param_spec() << "Parameter " << name - << " is not optional and can't have default_value." ); - - BOOST_TEST_I_ASSRT( !m.has( optional_value ) || !this->p_repeatable, - invalid_param_spec() << "Parameter " << name - << " is repeatable and can't have optional_value." ); - } - -private: - virtual basic_param_ptr clone() const - { - return basic_param_ptr( new parameter( *this ) ); - } - virtual void produce_argument( cstring token, bool , arguments_store& store ) const - { - m_arg_factory.produce_argument( token, this->p_name, store ); - } - virtual void produce_default( arguments_store& store ) const - { - if( !this->p_has_default_value ) - return; - - m_arg_factory.produce_default( this->p_name, store ); - } - - // Data members - typedef argument_factory factory_t; - factory_t m_arg_factory; + virtual ~parameter() {} }; -//____________________________________________________________________________// +} // namespace BOOST_TEST_UTILS_RUNTIME_PARAM_NAMESPACE -class option : public basic_param { -public: - /// Constructor with modifiers - template - option( cstring name, Modifiers const& m = nfp::no_params ) - : basic_param( name, true, false, nfp::opt_append( nfp::opt_append( m, optional_value = true), default_value = false) ) - , m_arg_factory( nfp::opt_append( nfp::opt_append( m, optional_value = true), default_value = false) ) - { - } - - void add_cla_id( cstring prefix, cstring tag, cstring value_separator, bool negatable = false ) - { - add_cla_id_impl( prefix, tag, value_separator, negatable, false ); - } - -private: - virtual basic_param_ptr clone() const - { - return basic_param_ptr( new option( *this ) ); - } - - virtual void produce_argument( cstring token, bool negative_form, arguments_store& store ) const - { - if( token.empty() ) - store.set( p_name, !negative_form ); - else { - BOOST_TEST_I_ASSRT( !negative_form, - format_error( p_name ) << "Can't set value to negative form of the argument." ); - - m_arg_factory.produce_argument( token, p_name, store ); - } - } - - virtual void produce_default( arguments_store& store ) const - { - m_arg_factory.produce_default( p_name, store ); - } - virtual void cla_name_help( std::ostream& ostr, cstring cla_tag, cstring negation_prefix ) const - { - if( negation_prefix.is_empty() ) - ostr << cla_tag; - else - ostr << '[' << negation_prefix << ']' << cla_tag; - } - virtual void value_help( std::ostream& ostr ) const - { - if( p_value_hint.empty() ) - ostr << ""; - else - ostr << p_value_hint; - } - - // Data members - typedef argument_factory factory_t; - factory_t m_arg_factory; -}; - -//____________________________________________________________________________// - -template -class enum_parameter : public parameter { - typedef parameter base; -public: - /// Constructor with modifiers - template - enum_parameter( cstring name, Modifiers const& m = nfp::no_params ) - : base( name, m ) - { - auto const& values = m[enum_values::value]; - auto it = values.begin(); - while( it != values.end() ) { - m_valid_names.push_back( it->first ); - ++it; - } - } - -private: - virtual basic_param_ptr clone() const - { - return basic_param_ptr( new enum_parameter( *this ) ); - } - - virtual void value_help( std::ostream& ostr ) const - { - if( this->p_value_hint.empty() ) { - ostr << "<"; - bool first = true; - BOOST_TEST_FOREACH( cstring, name, m_valid_names ) { - if( first ) - first = false; - else - ostr << '|'; - ostr << name; - } - ostr << ">"; - } - else - ostr << this->p_value_hint; - } - - // Data members - std::vector m_valid_names; -}; - -// ************************************************************************** // -// ************** runtime::parameters_store ************** // -// ************************************************************************** // - -class parameters_store { - struct lg_compare { - bool operator()( cstring lh, cstring rh ) const - { - return std::lexicographical_compare(lh.begin(), lh.end(), - rh.begin(), rh.end()); - } - }; -public: - - typedef std::map storage_type; - - /// Adds parameter into the persistent store - void add( basic_param const& in ) - { - basic_param_ptr p = in.clone(); - - BOOST_TEST_I_ASSRT( m_parameters.insert( std::make_pair( cstring(p->p_name), p ) ).second, - duplicate_param() << "Parameter " << p->p_name << " is duplicate." ); - } - - /// Returns true if there is no parameters registered - bool is_empty() const { return m_parameters.empty(); } - /// Returns map of all the registered parameter - storage_type const& all() const { return m_parameters; } - /// Returns true if parameter with psecified name is registered - bool has( cstring name ) const - { - return m_parameters.find( name ) != m_parameters.end(); - } - /// Returns map of all the registered parameter - basic_param_ptr get( cstring name ) const - { - auto const& found = m_parameters.find( name ); - BOOST_TEST_I_ASSRT( found != m_parameters.end(), - unknown_param() << "Parameter " << name << " is unknown." ); - - return found->second; - } - -private: - // Data members - storage_type m_parameters; -}; - -} // namespace runtime } // namespace boost -#include - #endif // BOOST_TEST_UTILS_RUNTIME_PARAMETER_HPP diff --git a/include/boost/test/utils/runtime/trace.hpp b/include/boost/test/utils/runtime/trace.hpp new file mode 100644 index 00000000..17a169b2 --- /dev/null +++ b/include/boost/test/utils/runtime/trace.hpp @@ -0,0 +1,30 @@ +// (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 : $RCSfile$ +// +// Version : $Revision$ +// +// Description : optional internal tracing +// *************************************************************************** + +#ifndef BOOST_TEST_UTILS_RUNTIME_TRACE_HPP +#define BOOST_TEST_UTILS_RUNTIME_TRACE_HPP + +// Boost.Runtime.Parameter +#include + +#ifdef BOOST_TEST_UTILS_RUNTIME_PARAM_DEBUG + +#include + +# define BOOST_TEST_UTILS_RUNTIME_PARAM_TRACE( str ) std::cerr << str << std::endl +#else +# define BOOST_TEST_UTILS_RUNTIME_PARAM_TRACE( str ) +#endif + +#endif // BOOST_TEST_UTILS_RUNTIME_TRACE_HPP diff --git a/include/boost/test/utils/runtime/validation.hpp b/include/boost/test/utils/runtime/validation.hpp new file mode 100644 index 00000000..54163dc6 --- /dev/null +++ b/include/boost/test/utils/runtime/validation.hpp @@ -0,0 +1,85 @@ +// (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 : $RCSfile$ +// +// Version : $Revision$ +// +// Description : defines exceptions and validation tools +// *************************************************************************** + +#ifndef BOOST_TEST_UTILS_RUNTIME_VALIDATION_HPP +#define BOOST_TEST_UTILS_RUNTIME_VALIDATION_HPP + +// Boost.Runtime.Parameter +#include + +// Boost.Test +#include +#include + +// Boost +#include + +// STL +#ifdef BOOST_TEST_UTILS_RUNTIME_PARAM_EXCEPTION_INHERIT_STD +#include +#endif + +namespace boost { + +namespace BOOST_TEST_UTILS_RUNTIME_PARAM_NAMESPACE { + +// ************************************************************************** // +// ************** runtime::logic_error ************** // +// ************************************************************************** // + +class logic_error +#ifdef BOOST_TEST_UTILS_RUNTIME_PARAM_EXCEPTION_INHERIT_STD +: public std::exception +#endif +{ + typedef shared_ptr dstring_ptr; +public: + // Constructor // !! could we eliminate shared_ptr + explicit logic_error( cstring msg ) : m_msg( new dstring( msg.begin(), msg.size() ) ) {} + ~logic_error() BOOST_NOEXCEPT_OR_NOTHROW + {} + + dstring const& msg() const { return *m_msg; } + virtual char_type const* what() const BOOST_NOEXCEPT_OR_NOTHROW + { return m_msg->c_str(); } + +private: + dstring_ptr m_msg; +}; + +// ************************************************************************** // +// ************** runtime::report_logic_error ************** // +// ************************************************************************** // + +inline void +report_logic_error( format_stream& msg ) +{ + BOOST_TEST_IMPL_THROW( BOOST_TEST_UTILS_RUNTIME_PARAM_NAMESPACE::logic_error( msg.str() ) ); +} + +//____________________________________________________________________________// + +#define BOOST_TEST_UTILS_RUNTIME_PARAM_REPORT_LOGIC_ERROR( msg ) \ + boost::BOOST_TEST_UTILS_RUNTIME_PARAM_NAMESPACE::report_logic_error( format_stream().ref() << msg ) + +#define BOOST_TEST_UTILS_RUNTIME_PARAM_VALIDATE_LOGIC( b, msg ) \ + if( b ) {} else BOOST_TEST_UTILS_RUNTIME_PARAM_REPORT_LOGIC_ERROR( msg ) + +//____________________________________________________________________________// + +} // namespace BOOST_TEST_UTILS_RUNTIME_PARAM_NAMESPACE + +} // namespace boost + +#endif // BOOST_TEST_UTILS_RUNTIME_VALIDATION_HPP diff --git a/include/boost/test/utils/xml_printer.hpp b/include/boost/test/utils/xml_printer.hpp index a534c6ae..8552a173 100644 --- a/include/boost/test/utils/xml_printer.hpp +++ b/include/boost/test/utils/xml_printer.hpp @@ -17,6 +17,7 @@ // Boost.Test #include +#include #include #include #include @@ -41,19 +42,21 @@ namespace unit_test { inline void print_escaped( std::ostream& where_to, const_string value ) { - static std::map const char_type{{ - {'<' , "lt"}, - {'>' , "gt"}, - {'&' , "amp"}, - {'\'', "apos"}, - {'"' , "quot"} - }}; + static fixed_mapping char_type( + '<' , "lt", + '>' , "gt", + '&' , "amp", + '\'', "apos" , + '"' , "quot", + + 0 + ); BOOST_TEST_FOREACH( char, c, value ) { - auto found_ref = char_type.find( c ); + char const* ref = char_type[c]; - if( found_ref != char_type.end() ) - where_to << '&' << found_ref->second << ';'; + if( ref ) + where_to << '&' << ref << ';'; else where_to << c; } diff --git a/test/Jamfile.v2 b/test/Jamfile.v2 index 9ca41053..d688b3c2 100644 --- a/test/Jamfile.v2 +++ b/test/Jamfile.v2 @@ -15,15 +15,12 @@ project #_________________________________________________________________________________________________# -# lib gcov : : gcov : ; - rule boost.test-self-test ( test-rule : test-suite : test-name : usage-variant ? : pattern_file * : source_files * : extra-libs ? : extra-options ? ) { source_files ?= $(test-suite)/$(test-name).cpp ; usage-variant ?= boost_unit_test_framework/static ; return [ $(test-rule) $(source_files) ../build//$(usage-variant) $(extra-libs) -# gcov : #args : $(pattern_file) : # Activating -pedantic finds more gotchas @@ -32,14 +29,13 @@ rule boost.test-self-test ( test-rule : test-suite : test-name : usage-variant ? gcc:-pedantic gcc:-Wno-long-long gcc:-std=c++11 -# gcc:-E -# gcc:-fno-exceptions -# gcc:-DBOOST_NO_EXCEPTION -# gcc:--coverage clang:-Wno-c99-extensions clang:-std=c++11 # clang:-Wconversion # clang:-Wno-sign-conversion +# gcc:-E +# gcc:-fno-exceptions +# gcc:-DBOOST_NO_EXCEPTION # clang:-fno-exceptions # clang:-DBOOST_NO_EXCEPTION all @@ -80,9 +76,12 @@ test-suite "utils-ts" [ boost.test-self-test run : utils-ts : algorithm-test ] [ boost.test-self-test run : utils-ts : basic_cstring-test ] [ boost.test-self-test run : utils-ts : class_properties-test ] +# [ boost.test-self-test run : utils-ts : config_file-test ] +# [ boost.test-self-test run : utils-ts : config_file_iterator-test ] + [ boost.test-self-test run : utils-ts : fixed_mapping-test ] [ boost.test-self-test run : utils-ts : foreach-test ] - [ boost.test-self-test run : utils-ts : named_params-test ] - [ boost.test-self-test run : utils-ts : runtime-param-test ] + [ boost.test-self-test run : utils-ts : ifstream_line_iterator-test : : inputs/ifstream_line_iterator.tst1 + inputs/ifstream_line_iterator.tst2 ] [ boost.test-self-test run : utils-ts : token_iterator-test ] ; diff --git a/test/execution_monitor-ts/errors-handling-test.cpp b/test/execution_monitor-ts/errors-handling-test.cpp index 0f8b60c3..17e0ec1f 100644 --- a/test/execution_monitor-ts/errors-handling-test.cpp +++ b/test/execution_monitor-ts/errors-handling-test.cpp @@ -185,11 +185,10 @@ BOOST_AUTO_TEST_CASE( test_errors_handling ) framework::run( test ); unit_test_log.set_stream( std::cout ); - unit_test_log.set_format( runtime_config::get( runtime_config::LOG_FORMAT ) ); - - log_level ll = runtime_config::get( runtime_config::LOG_LEVEL ); - unit_test_log.set_threshold_level( ll != invalid_log_level? ll : log_all_errors ); - + unit_test_log.set_format( runtime_config::log_format() ); + unit_test_log.set_threshold_level( runtime_config::log_level() != invalid_log_level + ? runtime_config::log_level() + : log_all_errors ); BOOST_CHECK( test_output.match_pattern() ); } } diff --git a/test/framework-ts/result-report-test.cpp b/test/framework-ts/result-report-test.cpp index 790b65d6..776b8142 100644 --- a/test/framework-ts/result-report-test.cpp +++ b/test/framework-ts/result-report-test.cpp @@ -100,8 +100,7 @@ struct guard { ~guard() { results_reporter::set_stream( std::cerr ); - results_reporter::set_format( runtime_config::get( - runtime_config::REPORT_FORMAT ) ); + results_reporter::set_format( runtime_config::report_format() ); } }; diff --git a/test/gen_coverage.sh b/test/gen_coverage.sh deleted file mode 100755 index 566d7e67..00000000 --- a/test/gen_coverage.sh +++ /dev/null @@ -1,21 +0,0 @@ -#!/bin/sh - -which lcov 1>/dev/null 2>&1 -if [ $? != 0 ] -then - echo "You need to have lcov installed in order to generate the test coverage report" - exit 1 -fi - -bjam toolset=gcc-4.9.2 clean -bjam toolset=gcc-4.9.2 runtime-param-test - -# Generate html report -lcov --base-directory . --directory ../../../bin.v2/libs/test/test/runtime-param-test.test/gcc-4.9.2/debug/utils-ts -c -o runtime-param-test.info -lcov --remove runtime-param-test.info "/usr*" -o runtime-param-test.info # remove output for external libraries -lcov --remove runtime-param-test.info "boost" "/boost/c*" "/boost/d*" "/boost/e*" "/boost/f*" "/boost/l*" "/boost/m*" "/boost/s*" -o runtime-param-test.info # remove output for other boost libs -rm -rf ./coverage -genhtml -o ./coverage -t "runtime-param-test coverage" --num-spaces 4 runtime-param-test.info - -#Clean up -rm *.info \ No newline at end of file diff --git a/test/inputs/ifstream_line_iterator.tst1 b/test/inputs/ifstream_line_iterator.tst1 new file mode 100644 index 00000000..89910754 --- /dev/null +++ b/test/inputs/ifstream_line_iterator.tst1 @@ -0,0 +1,4 @@ +acv ffg + + +1 \ No newline at end of file diff --git a/test/inputs/ifstream_line_iterator.tst2 b/test/inputs/ifstream_line_iterator.tst2 new file mode 100644 index 00000000..ce33489b --- /dev/null +++ b/test/inputs/ifstream_line_iterator.tst2 @@ -0,0 +1,4 @@ +{ abc d } +{ d + dsfg +} diff --git a/test/usage-variants-ts/single-header-test.cpp b/test/usage-variants-ts/single-header-test.cpp index 2e9dfaeb..6ccb83dd 100644 --- a/test/usage-variants-ts/single-header-test.cpp +++ b/test/usage-variants-ts/single-header-test.cpp @@ -15,7 +15,6 @@ // Boost.Test #define BOOST_TEST_MODULE single header test #include -using namespace boost::unit_test; BOOST_AUTO_TEST_CASE( test ) { diff --git a/test/utils-ts/config_file-test.cpp b/test/utils-ts/config_file-test.cpp new file mode 100644 index 00000000..de8aa07d --- /dev/null +++ b/test/utils-ts/config_file-test.cpp @@ -0,0 +1,253 @@ +// (C) Copyright Gennadiy Rozental 2001-2015. +// 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 : basic_cstring unit test +// ***************************************************************************** + +// Boost.Test +#define BOOST_TEST_MAIN +#include +namespace utf = boost::unit_test; + +// Boost.Runtime.Parameter +#include +#include + +namespace rt = boost::runtime; +namespace rtf = boost::runtime::file; + +//____________________________________________________________________________// + +BOOST_AUTO_TEST_CASE( basic_load_test ) +{ + rtf::config_file cf( "test_files/cfg_file_tst1.cfg" ); + + BOOST_TEST( rtf::get_requ_param_value( cf, "par1" ) == "ABC " ); + + BOOST_TEST( rtf::get_requ_param_value( cf, "NS1", "par1" ) == "12" ); + BOOST_TEST( rtf::get_requ_param_value( cf, "NS2", "NS3", "par1" ) == "OFF" ); + BOOST_TEST( rtf::get_requ_param_value( cf, "NS2", "NS4", "par1" ) == "ON" ); + BOOST_TEST( rtf::get_requ_param_value( cf, "NS2", "NS4", "NS5", "par1" ) == "1 2 3" ); + + BOOST_TEST( !rtf::get_param_value( cf, "par1 " ) ); + BOOST_TEST( !rtf::get_param_value( cf, "par2" ) ); + BOOST_TEST( !rtf::get_param_value( cf, "NS2", "par1" ) ); + + BOOST_CHECK_THROW( rtf::get_requ_param_value( cf, "par1 " ), rt::logic_error ); + BOOST_CHECK_THROW( rtf::get_requ_param_value( cf, "par2" ), rt::logic_error ); + BOOST_CHECK_THROW( rtf::get_requ_param_value( cf, "NS2", "par1" ), rt::logic_error ); +} + +//____________________________________________________________________________// + +BOOST_AUTO_TEST_CASE( multiple_load ) +{ + rtf::config_file cf; + + cf.load( "test_files/cfg_file_tst3.cfg" ); + cf.load( "test_files/cfg_file_tst4.cfg" ); + + BOOST_TEST( rtf::get_requ_param_value( cf, "par1" ) == "1" ); + BOOST_TEST( rtf::get_requ_param_value( cf, "NS", "par2" ) == "1 2" ); +} + +//____________________________________________________________________________// + +BOOST_AUTO_TEST_CASE( custom_value_marker ) +{ + rtf::config_file cf; + + cf.load( "test_files/cfg_file_tst2.cfg", rtf::value_marker = "|" ); + + BOOST_TEST( rtf::get_requ_param_value( cf, "par1" ) == "\"Simple text \"" ); +} + +//____________________________________________________________________________// + +BOOST_AUTO_TEST_CASE( custom_value_delimeter ) +{ + rtf::config_file cf; + + cf.load( "test_files/cfg_file_tst5.cfg", rtf::value_delimeter = "=> " ); + cf.load( "test_files/cfg_file_tst6.cfg", rtf::value_delimeter = " " ); + + BOOST_TEST( rtf::get_requ_param_value( cf, "par1" ) == "1" ); + BOOST_TEST( rtf::get_requ_param_value( cf, "NS", "par2" ) == "2" ); +} + +//____________________________________________________________________________// + +BOOST_AUTO_TEST_CASE( custom_ns_delimeter ) +{ + rtf::config_file cf; + + cf.load( "test_files/cfg_file_tst7.cfg", (rtf::namespace_delimeter = "/",rtf::value_delimeter = " ") ); + + BOOST_TEST( rtf::get_requ_param_value( cf, "NS1", "NS2", "par" ) == "1" ); +} + +//____________________________________________________________________________// + +void test_aliases() +{ + global_param_namespace.clear(); + + config_file_iterator cfi1( "test_files/par_hdl_tst1.cfg" ); + BOOST_TEST( global_param_namespace.load_parameters( cfi1 ) ); + + config_file_iterator cfi2( "test_files/par_alias1.cfg" ); + BOOST_TEST( global_param_namespace.load_aliases( cfi2 ) ); + + BOOST_CHECK_EQUAL( rtf::get_param_value( "par1" ), "ABC" ); + BOOST_CHECK_EQUAL( rtf::get_param_value( "par2" ), "12" ); + BOOST_CHECK_EQUAL( rtf::get_param_value( "par3" ), "OFF" ); + BOOST_CHECK_EQUAL( rtf::get_param_value( "par4" ), "ON" ); + BOOST_CHECK_EQUAL( rtf::get_param_value( "par5" ), "OFF" ); +} + +//____________________________________________________________________________// + +void test_validations() +{ + BOOST_CHECK_THROW( global_param_namespace.insert_param( "PAR-AM" ), fnd_runtime_exception ); + BOOST_CHECK_THROW( global_param_namespace.insert_param( "p^" ), fnd_runtime_exception ); + BOOST_CHECK_THROW( global_param_namespace.insert_namespace( "ns#1" ), fnd_runtime_exception ); + BOOST_CHECK_THROW( global_param_namespace.insert_namespace( "ns 1" ), fnd_runtime_exception ); + BOOST_CHECK_THROW( global_param_namespace.insert_namespace( "ns-1" ), fnd_runtime_exception ); + + config_file_iterator cfi1( "test_files/par_hdl_tst2.cfg" ); + BOOST_TEST( !global_param_namespace.load_parameters( cfi1 ) ); + + config_file_iterator cfi2( "test_files/par_alias2.cfg" ); + BOOST_TEST( !global_param_namespace.load_aliases( cfi2 ) ); + + config_file_iterator cfi3( "test_files/par_alias3.cfg" ); + BOOST_TEST( !global_param_namespace.load_aliases( cfi3 ) ); +} + +//____________________________________________________________________________// + +#define QUOTE_N_END( string ) "\"" string "\"\n" +void test_io() +{ + global_param_namespace.clear(); + + config_file_iterator cfi1( "test_files/par_hdl_tst1.cfg" ); + BOOST_TEST( global_param_namespace.load_parameters( cfi1 ) ); + + config_file_iterator cfi2( "test_files/par_alias1.cfg" ); + BOOST_TEST( global_param_namespace.load_aliases( cfi2 ) ); + + output_test_stream ots; + + ots << global_param_namespace; + + BOOST_TEST( ots.is_equal( + "par1 " QUOTE_N_END( "ABC" ) + "par2 " QUOTE_N_END( "12" ) + "par3 " QUOTE_N_END( "OFF" ) + "par5 " QUOTE_N_END( "OFF" ) + "par4 " QUOTE_N_END( "ON" ) + "NS1::par1 " QUOTE_N_END( "12" ) + "NS2::NS3::par1 " QUOTE_N_END( "OFF" ) + "NS2::NS4::par1 " QUOTE_N_END( "ON" ) + "NS2::NS4::NS5::par1 " QUOTE_N_END( "1 2 3" ) + + ) ); +} + +//____________________________________________________________________________// + +void +test_multipart_value() +{ + { + param_namespace pn( "", NULL ); + BOOST_TEST( !pn.load_parameters( "test_files/test_multipart_value1.cfg" ) ); + } + + { + param_namespace pn( "", NULL ); + BOOST_TEST( pn.load_parameters( "test_files/test_multipart_value2.cfg" ) ); + + BOOST_TEST( rtf::get_param_value( "a", pn ) == "" ); + } + + + { + param_namespace pn( "", NULL ); + BOOST_TEST( !pn.load_parameters( "test_files/test_multipart_value3.cfg" ) ); + } + + { + param_namespace pn( "", NULL ); + BOOST_TEST( pn.load_parameters( "test_files/test_multipart_value4.cfg" ) ); + + BOOST_TEST( rtf::get_param_value( "a", pn ) == "\"" ); + } + + { + param_namespace pn( "", NULL ); + BOOST_TEST( !pn.load_parameters( "test_files/test_multipart_value5.cfg" ) ); + } + + { + param_namespace pn( "", NULL ); + BOOST_TEST( !pn.load_parameters( "test_files/test_multipart_value6.cfg" ) ); + } + + + { + param_namespace pn( "", NULL ); + BOOST_TEST( !pn.load_parameters( "test_files/test_multipart_value7.cfg" ) ); + } + + { + param_namespace pn( "", NULL ); + BOOST_TEST( pn.load_parameters( "test_files/test_multipart_value8.cfg" ) ); + + BOOST_TEST( rtf::get_param_value( "a", pn ) == "abcdef" ); + } + + { + param_namespace pn( "", NULL ); + BOOST_TEST( pn.load_parameters( "test_files/test_multipart_value9.cfg" ) ); + + BOOST_TEST( rtf::get_param_value( "a", pn ) == "abcdef123" ); + } + + { + param_namespace pn( "", NULL ); + BOOST_TEST( !pn.load_parameters( "test_files/test_multipart_value10.cfg" ) ); + } + + { + param_namespace pn( "", NULL ); + BOOST_TEST( !pn.load_parameters( "test_files/test_multipart_value11.cfg" ) ); + } + + { + param_namespace pn( "", NULL ); + BOOST_TEST( !pn.load_parameters( "test_files/test_multipart_value12.cfg" ) ); + } + + { + param_namespace pn( "", NULL ); + BOOST_TEST( pn.load_parameters( "test_files/test_multipart_value13.cfg" ) ); + + const_string pattern( "\"abc\"" ); + BOOST_TEST( rtf::get_param_value( "a", pn ) == pattern ); + } +} + +//____________________________________________________________________________// + +// EOF diff --git a/test/utils-ts/config_file_iterator-test.cpp b/test/utils-ts/config_file_iterator-test.cpp new file mode 100644 index 00000000..987c69f5 --- /dev/null +++ b/test/utils-ts/config_file_iterator-test.cpp @@ -0,0 +1,314 @@ +// (C) Copyright Gennadiy Rozental 2001-2015. +// 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 : config_file_iterator unit test +// ***************************************************************************** + +// Boost.Test +#define BOOST_TEST_MODULE config_file_iterator unit test +#include +namespace utf = boost::unit_test; + +// Boost.Runtime.Parameter +#include +#include + +namespace rt = boost::runtime; +namespace file = boost::runtime::file; +namespace env = boost::runtime::environment; + +BOOST_TEST_DONT_PRINT_LOG_VALUE(file::config_file_iterator) + +//____________________________________________________________________________// + +BOOST_AUTO_TEST_CASE( test_constructor ) +{ + { + file::config_file_iterator cfi( NULL ); + + BOOST_TEST( cfi == file::config_file_iterator() ); + } + + { + file::config_file_iterator cfi( "" ); + + BOOST_TEST( cfi == file::config_file_iterator() ); + } + + { + rt::cstring cs( "" ); + file::config_file_iterator cfi( cs ); + + BOOST_TEST( cfi == file::config_file_iterator() ); + } + + { + std::string ds; + file::config_file_iterator cfi( ds ); + + BOOST_TEST( cfi == file::config_file_iterator() ); + } + + { + BOOST_CHECK_THROW( file::config_file_iterator( "!@#%#$%#$^#$^" ), rt::logic_error ); + } + + { + file::config_file_iterator cfi( "test_files/test_constructor.cfg" ); + + BOOST_TEST( cfi != file::config_file_iterator() ); + BOOST_TEST( *cfi == "{ abc d }" ); + + cfi = cfi; + + BOOST_TEST( cfi != file::config_file_iterator() ); + BOOST_TEST( *cfi == "{ abc d }" ); + + file::config_file_iterator cfi1( cfi ); + + BOOST_TEST( cfi == file::config_file_iterator() ); + BOOST_TEST( *cfi1 == "{ abc d }" ); + + ++cfi1; + BOOST_TEST( *cfi1 == "{ d" ); + + cfi = cfi1; + BOOST_TEST( cfi != file::config_file_iterator() ); + BOOST_TEST( *cfi == "{ d" ); + + ++cfi; + BOOST_TEST( *cfi == " dsfg" ); + } +} + +//____________________________________________________________________________// + +BOOST_AUTO_TEST_CASE( test_comments_and_blanks ) +{ + file::config_file_iterator cfi( "test_files/test_comments_and_blanks.cfg" ); + + BOOST_TEST( cfi != file::config_file_iterator() ); + BOOST_TEST( *cfi == "1" ); ++cfi; + BOOST_TEST( *cfi == "2" ); ++cfi; + BOOST_TEST( *cfi == "4" ); ++cfi; + BOOST_TEST( *cfi == "3" ); ++cfi; + BOOST_TEST( cfi == file::config_file_iterator() ); +} + +//____________________________________________________________________________// + +BOOST_AUTO_TEST_CASE( test_broken_line ) +{ + BOOST_CHECK_THROW( file::config_file_iterator( "test_files/test_incomplete_broken_line.cfg" ), rt::logic_error ); + + { + file::config_file_iterator cfi( "test_files/test_broken_line.cfg" ); + + BOOST_TEST( cfi != file::config_file_iterator() ); + BOOST_TEST( *cfi == "qwerty" ); ++cfi; + BOOST_TEST( *cfi == "123 \\11" ); ++cfi; + BOOST_TEST( *cfi == " 23" ); ++cfi; + BOOST_TEST( *cfi == "xcv \\ dfgsd" ); ++cfi; + BOOST_TEST( *cfi == "qwe" ); ++cfi; + BOOST_TEST( cfi != file::config_file_iterator() ); + BOOST_TEST( *cfi == "1 \t23" ); ++cfi; + BOOST_TEST( *cfi == "34 34" ); ++cfi; + BOOST_TEST( *cfi == "a b c d e f" ); ++cfi; + BOOST_TEST( *cfi == "as sa" ); ++cfi; + BOOST_TEST( *cfi == "aswe" ); ++cfi; + BOOST_TEST( cfi == file::config_file_iterator() ); + } + + { + file::config_file_iterator cfi( "test_files/test_broken_line.cfg", file::trim_leading_spaces ); + + BOOST_TEST( cfi != file::config_file_iterator() ); + BOOST_TEST( *cfi == "qwerty" ); ++cfi; + BOOST_TEST( *cfi == "123 \\11" ); ++cfi; + BOOST_TEST( *cfi == "23" ); ++cfi; + BOOST_TEST( *cfi == "xcv \\ dfgsd" ); ++cfi; + BOOST_TEST( *cfi == "qwe" ); ++cfi; + BOOST_TEST( cfi != file::config_file_iterator() ); + BOOST_TEST( *cfi == "1 \t23" ); ++cfi; + BOOST_TEST( *cfi == "34 34" ); ++cfi; + BOOST_TEST( *cfi == "a b c d e f" ); ++cfi; + BOOST_TEST( *cfi == "as sa" ); ++cfi; + BOOST_TEST( *cfi == "aswe" ); ++cfi; + BOOST_TEST( cfi == file::config_file_iterator() ); + } + + { + file::config_file_iterator cfi( "test_files/test_broken_line.cfg", (!file::trim_leading_spaces,!file::trim_trailing_spaces)); + + BOOST_TEST( cfi != file::config_file_iterator() ); + BOOST_TEST( *cfi == "qwerty" ); ++cfi; + BOOST_TEST( *cfi == "123 \\11" ); ++cfi; + BOOST_TEST( *cfi == " 23" ); ++cfi; + BOOST_TEST( *cfi == "xcv \\ dfgsd" ); ++cfi; + BOOST_TEST( *cfi == "qwe" ); ++cfi; + BOOST_TEST( cfi != file::config_file_iterator() ); + BOOST_TEST( *cfi == "1 " ); ++cfi; + BOOST_TEST( *cfi == "\t23" ); ++cfi; + BOOST_TEST( *cfi == "34 \\ " ); ++cfi; + BOOST_TEST( *cfi == "34" ); ++cfi; + BOOST_TEST( *cfi == "a b c d e f " ); ++cfi; + BOOST_TEST( *cfi == "as \\ " ); ++cfi; + BOOST_TEST( *cfi == "sa" ); ++cfi; + BOOST_TEST( *cfi == "aswe" ); ++cfi; + BOOST_TEST( cfi == file::config_file_iterator() ); + } + + { + file::config_file_iterator cfi( "test_files/test_broken_line.cfg", !file::skip_empty_lines ); + + BOOST_TEST( cfi != file::config_file_iterator() ); + BOOST_TEST( *cfi == "qwerty" ); ++cfi; + BOOST_TEST( *cfi == "" ); ++cfi; + BOOST_TEST( *cfi == "123 \\11" ); ++cfi; + BOOST_TEST( *cfi == "" ); ++cfi; + BOOST_TEST( *cfi == "" ); ++cfi; + BOOST_TEST( *cfi == " 23" ); ++cfi; + BOOST_TEST( *cfi == "" ); ++cfi; + BOOST_TEST( *cfi == "xcv \\ dfgsd" ); ++cfi; + BOOST_TEST( *cfi == "qwe" ); ++cfi; + BOOST_TEST( cfi != file::config_file_iterator() ); + BOOST_TEST( *cfi == "" ); ++cfi; + BOOST_TEST( *cfi == "1 " ); ++cfi; + BOOST_TEST( *cfi == "\t23" ); ++cfi; + BOOST_TEST( *cfi == "" ); ++cfi; + BOOST_TEST( *cfi == "34 34" ); ++cfi; + BOOST_TEST( *cfi == "" ); ++cfi; + BOOST_TEST( *cfi == "a b c d e f" ); ++cfi; + BOOST_TEST( *cfi == "" ); ++cfi; + BOOST_TEST( *cfi == "as " ); ++cfi; + BOOST_TEST( *cfi == "sa" ); ++cfi; + BOOST_TEST( *cfi == "" ); ++cfi; + BOOST_TEST( *cfi == "as" ); ++cfi; + BOOST_TEST( *cfi == "we" ); ++cfi; + BOOST_TEST( *cfi == "" ); ++cfi; + BOOST_TEST( cfi == file::config_file_iterator() ); + } +} + +//____________________________________________________________________________// + +BOOST_AUTO_TEST_CASE( test_include ) +{ + { + file::config_file_iterator cfi( "test_files/test_include1.cfg" ); + BOOST_TEST( cfi != file::config_file_iterator() ); + BOOST_TEST( *cfi == "a" ); ++cfi; + BOOST_TEST( *cfi == "c" ); ++cfi; + BOOST_TEST( *cfi == "b" ); ++cfi; + BOOST_TEST( cfi == file::config_file_iterator() ); + } + + { + file::config_file_iterator cfi( "test_files/test_include2.cfg" ); + BOOST_TEST( cfi != file::config_file_iterator() ); + BOOST_TEST( *cfi == "1" ); ++cfi; + BOOST_TEST( *cfi == "a" ); ++cfi; + BOOST_TEST( *cfi == "c" ); ++cfi; + BOOST_TEST( *cfi == "b" ); ++cfi; + BOOST_TEST( *cfi == "2" ); ++cfi; + BOOST_TEST( cfi == file::config_file_iterator() ); + } + + { + file::config_file_iterator cfi( "test_files/test_include3.cfg" ); + BOOST_TEST( cfi != file::config_file_iterator() ); + BOOST_TEST( *cfi == "c" ); ++cfi; + BOOST_TEST( *cfi == "c" ); ++cfi; + BOOST_TEST( cfi == file::config_file_iterator() ); + } +} + +//____________________________________________________________________________// + +env::variable<> TEST_MACRO( "TEST_MACRO", env::default_value = "test_value" ); + +BOOST_AUTO_TEST_CASE( test_define ) +{ + file::config_file_iterator cfi( "test_files/test_define.cfg" ); + BOOST_TEST( cfi != file::config_file_iterator() ); + BOOST_TEST( *cfi == "a123123" ); ++cfi; + BOOST_TEST( *cfi == "11232" ); ++cfi; + BOOST_TEST( *cfi == "a test_value=11" ); ++cfi; + BOOST_TEST( *cfi == "1abc2" ); ++cfi; + BOOST_TEST( cfi == file::config_file_iterator() ); +} + +//____________________________________________________________________________// + +BOOST_AUTO_TEST_CASE( test_macro_subst ) +{ + BOOST_CHECK_THROW( file::config_file_iterator( "test_files/test_macro_subst1.cfg" ), rt::logic_error ); + BOOST_CHECK_THROW( file::config_file_iterator( "test_files/test_macro_subst3.cfg" ), rt::logic_error ); + + { + file::config_file_iterator cfi( "test_files/test_macro_subst1.cfg", !file::detect_missing_macro ); + BOOST_TEST( cfi != file::config_file_iterator() ); + BOOST_TEST( *cfi == "a" ); ++cfi; + BOOST_TEST( cfi == file::config_file_iterator() ); + } + + { + file::config_file_iterator cfi( "test_files/test_macro_subst2.cfg" ); + BOOST_TEST( cfi != file::config_file_iterator() ); + BOOST_TEST( *cfi == "atest_value" ); ++cfi; + BOOST_TEST( cfi == file::config_file_iterator() ); + } + + { + file::config_file_iterator cfi( "test_files/test_macro_subst4.cfg" ); + BOOST_TEST( cfi != file::config_file_iterator() ); + BOOST_TEST( *cfi == "abb" ); ++cfi; + BOOST_TEST( cfi == file::config_file_iterator() ); + } +} + +//____________________________________________________________________________// + +BOOST_AUTO_TEST_CASE( test_undef ) +{ + { + file::config_file_iterator cfi( "test_files/test_undef.cfg", !file::detect_missing_macro ); + BOOST_TEST( cfi != file::config_file_iterator() ); + BOOST_TEST( *cfi == "1123" ); ++cfi; + BOOST_TEST( *cfi == "1" ); ++cfi; + BOOST_TEST( cfi == file::config_file_iterator() ); + } +} + +//____________________________________________________________________________// + +BOOST_AUTO_TEST_CASE( test_ifdef ) +{ + { + file::config_file_iterator cfi( "test_files/test_ifdef.cfg" ); + BOOST_TEST( cfi != file::config_file_iterator() ); + BOOST_TEST( *cfi == "1" ); ++cfi; + BOOST_TEST( *cfi == "2" ); ++cfi; + BOOST_TEST( *cfi == "1" ); ++cfi; + BOOST_TEST( *cfi == "1abc" ); ++cfi; + BOOST_TEST( *cfi == "a" ); ++cfi; + BOOST_TEST( cfi == file::config_file_iterator() ); + } + + BOOST_CHECK_THROW( file::config_file_iterator( "test_files/test_ifdef1.cfg" ), rt::logic_error ); + BOOST_CHECK_THROW( file::config_file_iterator( "test_files/test_ifdef2.cfg" ), rt::logic_error ); + BOOST_CHECK_THROW( file::config_file_iterator( "test_files/test_ifdef3.cfg" ), rt::logic_error ); + BOOST_CHECK_THROW( file::config_file_iterator( "test_files/test_ifdef4.cfg" ), rt::logic_error ); +} + +//____________________________________________________________________________// + +// EOF diff --git a/test/utils-ts/fixed_mapping-test.cpp b/test/utils-ts/fixed_mapping-test.cpp new file mode 100644 index 00000000..62b4fd9b --- /dev/null +++ b/test/utils-ts/fixed_mapping-test.cpp @@ -0,0 +1,81 @@ +// (C) Copyright Gennadiy Rozental 2001-2015. +// 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 : fixed_mapping unit test +// ***************************************************************************** + +// Boost.Test +#define BOOST_TEST_MODULE class fixed_mapping unit test +#include + +#include +#include +#include + +namespace utf = boost::unit_test; +namespace tt = boost::test_tools; +using utf::const_string; + +//____________________________________________________________________________// + +BOOST_AUTO_TEST_CASE( test_default_compare ) +{ + utf::fixed_mapping test_mapping( + "Key1", 1, + "Key2", 2, + "QWE" , 3, + "ASD" , 4, + "aws" , 5, + "dfg" , 6, + "dgt" , 7, + "ght" , 8, + + 0 + ); + + BOOST_TEST( test_mapping[ "Key1" ] == 1 ); + BOOST_TEST( test_mapping[ "Key2" ] == 2 ); + BOOST_TEST( test_mapping[ "QWE" ] == 3 ); + BOOST_TEST( test_mapping[ "ASD" ] == 4 ); + BOOST_TEST( test_mapping[ "aws" ] == 5 ); + BOOST_TEST( test_mapping[ "dfg" ] == 6 ); + BOOST_TEST( test_mapping[ "dgt" ] == 7 ); + BOOST_TEST( test_mapping[ "ght" ] == 8 ); + BOOST_TEST( test_mapping[ "bla" ] == 0 ); +} + +//____________________________________________________________________________// + +BOOST_AUTO_TEST_CASE( test_custom_compare ) +{ + utf::fixed_mapping > test_mapping( + "Key1", 1, + "Key2", 2, + "QWE" , 3, + "ASD" , 4, + + 0 + ); + + BOOST_TEST( test_mapping[ "Key1" ] == 1 ); + BOOST_TEST( test_mapping[ "Key2" ] == 2 ); + BOOST_TEST( test_mapping[ "QWE" ] == 3 ); + BOOST_TEST( test_mapping[ "ASD" ] == 4 ); + BOOST_TEST( test_mapping[ "kEy1" ] == 1 ); + BOOST_TEST( test_mapping[ "key2" ] == 2 ); + BOOST_TEST( test_mapping[ "qwE" ] == 3 ); + BOOST_TEST( test_mapping[ "aSd" ] == 4 ); + BOOST_TEST( test_mapping[ "bla" ] == 0 ); +} + +//____________________________________________________________________________// + +// EOF diff --git a/test/utils-ts/ifstream_line_iterator-test.cpp b/test/utils-ts/ifstream_line_iterator-test.cpp new file mode 100644 index 00000000..cacb0e36 --- /dev/null +++ b/test/utils-ts/ifstream_line_iterator-test.cpp @@ -0,0 +1,76 @@ +// (C) Copyright Gennadiy Rozental 2001-2015. +// 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 : ifstream_line_iterator unit test +// ***************************************************************************** + +// Boost.Test +#define BOOST_TEST_MODULE ifstream_line_iterator unit test +#include + +#include + +namespace ut = boost::unit_test; + +static ut::ifstream_line_iterator eoi; + +BOOST_TEST_DONT_PRINT_LOG_VALUE( ut::ifstream_line_iterator ) + +//____________________________________________________________________________// + +BOOST_AUTO_TEST_CASE( test_default_delimeter ) +{ + ut::ifstream_line_iterator it( ut::framework::master_test_suite().argc <= 1 + ? "./test_files/ifstream_line_iterator.tst1" + : ut::framework::master_test_suite().argv[1] ); + + BOOST_CHECK( it != eoi ); + + BOOST_TEST( *it == "acv ffg" ); + ++it; + + BOOST_TEST( *it == "" ); + ++it; + + BOOST_TEST( *it == " " ); + ++it; + + BOOST_TEST( *it == "1" ); + ++it; + + BOOST_CHECK( it == eoi ); +} + +//____________________________________________________________________________// + +BOOST_AUTO_TEST_CASE( test_custom_delimeter ) +{ + ut::ifstream_line_iterator it( ut::framework::master_test_suite().argc <= 2 + ? "./test_files/ifstream_line_iterator.tst2" + : ut::framework::master_test_suite().argv[2], '}' ); + + BOOST_CHECK( it != eoi ); + + BOOST_TEST( *it == "{ abc d " ); + ++it; + + BOOST_TEST( *it == "\n{ d \n dsfg\n" ); + ++it; + + BOOST_TEST( *it == "\n" ); + ++it; + + BOOST_CHECK( it == eoi ); +} + +//____________________________________________________________________________// + +// EOF diff --git a/test/utils-ts/named_params-test.cpp b/test/utils-ts/named_params-test.cpp deleted file mode 100644 index af8e71ca..00000000 --- a/test/utils-ts/named_params-test.cpp +++ /dev/null @@ -1,526 +0,0 @@ -// (C) Copyright Gennadiy Rozental 2001-2015. -// 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 for named function parameters framework -// ***************************************************************************** - -// Boost.Test -#define BOOST_TEST_MODULE Named function parameters test -#include -#include -namespace utf = boost::unit_test; -namespace nfp = boost::nfp; - -namespace test_single_int_parameter { - -nfp::typed_keyword k1; -nfp::typed_keyword k2; - -template -void dotest0( Params const& p ) -{ - BOOST_TEST_REQUIRE( p.has(k1) ); - BOOST_TEST( p[k1] == 7 ); -} - -template -void dotest1( Params const& p ) -{ - BOOST_TEST_REQUIRE( !p.has(k1) ); -} - -BOOST_AUTO_TEST_CASE( test_single_int_parameter ) -{ - dotest0( k1=7 ); - dotest1( k2=7 ); -} - -} // test_single_int_parameter - -//____________________________________________________________________________// - -namespace test_single_string_parameter { - -nfp::typed_keyword k1; -nfp::typed_keyword k2; - -template -void dotest0( Params const& p ) -{ - BOOST_TEST_REQUIRE( p.has(k1) ); - BOOST_TEST( p[k1] == "abc" ); -} - -template -void dotest1( Params const& p ) -{ - BOOST_TEST_REQUIRE( !p.has(k1) ); -} - -BOOST_AUTO_TEST_CASE( test_single_string_parameter ) -{ - dotest0( k1="abc" ); - dotest1( k2="cba" ); -} - -} // test_single_string_parameter - -//____________________________________________________________________________// - -namespace test_single_bool_parameter { - -nfp::typed_keyword k1; -nfp::typed_keyword k2; - -template -void dotest0( Params const& p ) -{ - BOOST_TEST_REQUIRE( p.has(k1) ); - BOOST_TEST( p[k1] ); -} - -template -void dotest1( Params const& p ) -{ - BOOST_TEST_REQUIRE( p.has(k1) ); - BOOST_TEST( !p[k1] ); -} - -template -void dotest2( Params const& p ) -{ - BOOST_TEST_REQUIRE( !p.has(k1) ); -} - -BOOST_AUTO_TEST_CASE( test_single_bool_parameter ) -{ - dotest0( k1 ); - dotest1( !k1 ); - dotest2( k2 ); -} - -} // test_single_bool_parameter - -//____________________________________________________________________________// - -namespace test_parameter_combination { - -nfp::typed_keyword k1; -nfp::typed_keyword k2; -nfp::typed_keyword k3; - -template -void dotest0( Params const& p ) -{ - BOOST_TEST_REQUIRE( p.has(k1) ); - BOOST_TEST_REQUIRE( p.has(k2) ); - BOOST_TEST_REQUIRE( !p.has(k3) ); - BOOST_TEST( p[k1] == 6 ); - BOOST_TEST( p[k2] == "123" ); -} - -template -void dotest1( Params const& p ) -{ - BOOST_TEST_REQUIRE( p.has(k1) ); - BOOST_TEST_REQUIRE( !p.has(k2) ); - BOOST_TEST_REQUIRE( p.has(k3) ); - BOOST_TEST( p[k1] == 6 ); - BOOST_TEST( p[k3] ); -} - -template -void dotest2( Params const& p ) -{ - BOOST_TEST_REQUIRE( p.has(k1) ); - BOOST_TEST_REQUIRE( p.has(k2) ); - BOOST_TEST_REQUIRE( p.has(k3) ); - BOOST_TEST( p[k1] == 5 ); - BOOST_TEST( p[k2] == "1q" ); - BOOST_TEST( !p[k3] ); -} - -BOOST_AUTO_TEST_CASE( test_parameter_combination ) -{ - dotest0(( k1=6, k2="123" )); - dotest1(( k3, k1=6 )); - dotest2(( k2 = "1q", !k3, k1=5 )); -} - -} // test_parameter_combination - -//____________________________________________________________________________// - -namespace test_const_arg { - -nfp::typed_keyword k1; -nfp::typed_keyword k2; - -template -void dotest0( Params const& p ) -{ - BOOST_TEST_REQUIRE( p.has(k1) ); - BOOST_TEST_REQUIRE( p.has(k2) ); - BOOST_TEST( p[k1] == 3 ); - BOOST_TEST( p[k2] == "123" ); -} - -BOOST_AUTO_TEST_CASE( test_const_arg ) -{ - int const val = 3; - dotest0(( k1=val, k2="123" )); -} - -} // test_const_arg - -//____________________________________________________________________________// - -namespace test_mutable_arg { - -nfp::typed_keyword k1; -nfp::typed_keyword k2; - -template -void dotest0( Params&& p ) -{ - BOOST_TEST_REQUIRE( p.has(k1) ); - BOOST_TEST( p[k1] == 2 ); - BOOST_TEST( p[k2] == "qwe" ); - p[k1] += 2; - BOOST_TEST( p[k1] == 4 ); - p[k2] = "asd"; -} - -BOOST_AUTO_TEST_CASE( test_mutable_arg ) -{ - int val = 2; - std::string str = "qwe"; - dotest0(( k1=val, k2=str )); - BOOST_TEST( val == 4 ); - BOOST_TEST( str == "asd" ); -} - -} // test_mutable_arg - -//____________________________________________________________________________// - -namespace test_noncopyable_arg { - -struct NC { - NC( int v ) : val( v ) {} - int val; - - NC( NC const& ) = delete; - NC( NC&& ) = delete; - void operator=( NC const& ) = delete; - void operator=( NC&& ) = delete; -}; - -nfp::typed_keyword k1; - -template -void dotest0( Params const& p ) -{ - BOOST_TEST_REQUIRE( p.has(k1) ); - BOOST_TEST( p[k1].val == 9 ); -} - -BOOST_AUTO_TEST_CASE( test_noncopyable_arg ) -{ - dotest0(( k1=NC{ 9 } )); -} - -} // test_noncopyable_arg - -//____________________________________________________________________________// - -namespace test_required_arg { - -nfp::typed_keyword k1; -nfp::typed_keyword k2; - -template -void dotest0( Params const& p ) -{ -// won't compile BOOST_TEST_REQUIRE( p.has(k1) ); - BOOST_TEST( p[k1] == 11 ); - BOOST_TEST( p[k2] == 10 ); -} - -BOOST_AUTO_TEST_CASE( test_required_arg ) -{ - dotest0(( k1=11, k2=10 )); -// won't compile dotest0(( k1=11 )); -} - -} // test_required_arg - -//____________________________________________________________________________// - -namespace test_argument_erasure { - -nfp::typed_keyword k1; -nfp::typed_keyword k2; -nfp::typed_keyword k3; - -template -void dotest0_in( Params const& p ) -{ - BOOST_TEST_REQUIRE( !p.has(k1) ); - BOOST_TEST_REQUIRE( p.has(k2) ); - BOOST_TEST_REQUIRE( p.has(k3) ); - BOOST_TEST( p[k2] == 12 ); - BOOST_TEST( p[k3] <= 0 ); -} - -template -void dotest0( Params const& p ) -{ - BOOST_TEST_REQUIRE( p.has(k1) ); - BOOST_TEST_REQUIRE( p.has(k2) ); - BOOST_TEST_REQUIRE( p.has(k3) ); - - p.erase(k1); - - dotest0_in( p ); -} - -template -void dotest1_in( Params const& p ) -{ - BOOST_TEST_REQUIRE( !p.has(k1) ); - BOOST_TEST_REQUIRE( !p.has(k2) ); - BOOST_TEST_REQUIRE( p.has(k3) ); - BOOST_TEST( p[k3] <= 0 ); -} - -template -void dotest1( Params const& p ) -{ - p.erase(k1); - p.erase(k2); - - dotest1_in( p ); -} - -BOOST_AUTO_TEST_CASE( test_argument_erasure ) -{ - dotest0(( k1=7, k2=12, k3=0 )); - dotest0(( k2=12, k1=7, k3=-1 )); - dotest0(( k3=-2, k2=12, k1=7 )); - - dotest1(( k1=7, k2=12, k3=0 )); -} - -} // test_argument_erasure - -//____________________________________________________________________________// - -namespace test_polymorphic_arg { - -nfp::keyword k1; - -template -void dotest0( Params const& p, T const& arg ) -{ - BOOST_TEST_REQUIRE( p.has(k1) ); - BOOST_TEST( p[k1] == arg ); -} - -BOOST_AUTO_TEST_CASE( test_polymorphic_arg ) -{ - dotest0( k1=11, 11 ); - dotest0( k1=std::string("qwe"), "qwe" ); -} - -} // test_polymorphic_arg - -//____________________________________________________________________________// - -namespace test_optional_assign { - -nfp::typed_keyword k1; -nfp::typed_keyword k2; - -template -void dotest0( Params const& p, T& targ ) -{ - nfp::opt_assign( targ, p, k1 ); -} - -BOOST_AUTO_TEST_CASE( test_optional_assign ) -{ - int value = 0; - dotest0( k1=11, value ); - BOOST_TEST( value == 11 ); - - dotest0( k2=12, value ); - BOOST_TEST( value == 11 ); -} - -} // test_optional_assign - -//____________________________________________________________________________// - -namespace test_optional_get { - -nfp::typed_keyword k1; -nfp::typed_keyword k2; - -template -void dotest0( Params const& p, T& targ ) -{ - targ = nfp::opt_get( p, k1, T{} ); -} - -BOOST_AUTO_TEST_CASE( test_optional_get ) -{ - int value = 0; - dotest0( k1=11, value ); - BOOST_TEST( value == 11 ); - - dotest0( k2=12, value ); - BOOST_TEST( value == 0 ); -} - -} // namespace test_optional_get - -//____________________________________________________________________________// - -namespace test_is_named_param_pack { - -nfp::typed_keyword k1; -nfp::typed_keyword k2; - -template -void dotest0( Params const& ) -{ - BOOST_TEST( nfp::is_named_param_pack::value ); -} - -BOOST_AUTO_TEST_CASE( test_is_named_param_pack ) -{ - dotest0( k1=11 ); - dotest0(( k1=11, k2=10 )); - - BOOST_TEST( !nfp::is_named_param_pack::value ); - BOOST_TEST( !nfp::is_named_param_pack::value ); - BOOST_TEST( !nfp::is_named_param_pack::value ); - typedef nfp::typed_keyword kw_t; - BOOST_TEST( !nfp::is_named_param_pack::value ); -} - -} // test_is_named_param_pack - -//____________________________________________________________________________// - -namespace test_param_type { - -nfp::typed_keyword k1; -nfp::typed_keyword k2; -nfp::keyword k3; -nfp::keyword k4; - -template -void dotest0( Params const&, KW const& ) -{ - typedef boost::is_same::type,T> check; - BOOST_TEST( check::value ); -} - -BOOST_AUTO_TEST_CASE( test_param_type ) -{ - dotest0(( k1=11, k2, k3="abc" ), k1 ); - dotest0(( k1=11, k2, k3="abc" ), k2 ); - dotest0(( k1=11, !k2, k3="abc" ), k2 ); - dotest0(( k1=11, k2, k3=1.2 ), k3 ); - dotest0(( k1=11, k2, k3="abc" ), k4 ); - int const c = 1; - dotest0(( k4=&c, k3=1.2 ), k4 ); -} - -} // test_param_type - -//____________________________________________________________________________// - -namespace test_has_param { - -nfp::typed_keyword k1; -nfp::typed_keyword k2; -nfp::keyword k3; -nfp::typed_keyword k4; - -template -void dotest0( Params const&, KW const&, bool exp ) -{ - BOOST_TEST( (nfp::has_param::value) == exp ); -} - -BOOST_AUTO_TEST_CASE( test_has_param ) -{ - dotest0(( k1=11, k2, k3="abc" ), k1, true ); - dotest0(( k1=11, !k2, k3="abc" ), k2, true ); - dotest0(( k2, k1=11, k3="abc" ), k2, true ); - dotest0(( k1=11, k2, k3="abc" ), k3, true ); - dotest0(( k1=11, k2, k3="abc" ), k4, false ); -} - -} // test_has_param - -//____________________________________________________________________________// - -namespace test_optional_append { - -nfp::typed_keyword k1; -nfp::typed_keyword k2; - -template -void dotest0( Params const& p, int exp ) -{ - BOOST_TEST_REQUIRE( p.has(k1) ); - BOOST_TEST( p[k1] == exp ); -} - -template -void dotest0_fwd( Params const& p, NP const& np, int exp ) -{ - dotest0( nfp::opt_append( p, np ), exp ); -} - -BOOST_AUTO_TEST_CASE( test_optional_append ) -{ - dotest0_fwd( k1=11, k2=10, 11 ); - dotest0_fwd( k2=10, k1=11, 11 ); - dotest0_fwd( (k1=9,k2=10), k1=11, 9 ); - dotest0_fwd( (k2=10,k1=9), k1=11, 9 ); -} - -} // test_optional_append - -//____________________________________________________________________________// - -namespace test_no_params { - -nfp::typed_keyword k1; - -template -void dotest0( bool exp, Params const& p = nfp::no_params ) -{ - BOOST_TEST_REQUIRE( p.has(k1) == exp ); -} - -BOOST_AUTO_TEST_CASE( test_no_params ) -{ - dotest0( false ); - dotest0( true, k1=11 ); -} - -} // test_no_params diff --git a/test/utils-ts/runtime-param-test.cpp b/test/utils-ts/runtime-param-test.cpp deleted file mode 100644 index 0ced633e..00000000 --- a/test/utils-ts/runtime-param-test.cpp +++ /dev/null @@ -1,1178 +0,0 @@ -// (C) Copyright Gennadiy Rozental 2015. -// 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 for runtime parameter framework -// *************************************************************************** - -// Boost.Test -#define BOOST_TEST_MODULE Boost.Test CLA parser test -#include -#include -#include -#include -#include -#include -namespace utf = boost::unit_test; -namespace rt = boost::runtime; - -#include - -BOOST_AUTO_TEST_SUITE( test_argv_traverser ) - -BOOST_AUTO_TEST_CASE( test_construction ) -{ - char const* argv1[] = { "test.exe" }; - rt::cla::argv_traverser tr1( sizeof(argv1)/sizeof(char const*), argv1 ); - - BOOST_TEST( tr1.eoi() ); - - char const* argv2[] = { "test.exe", "--abc=1" }; - rt::cla::argv_traverser tr2( sizeof(argv2)/sizeof(char const*), argv2 ); - - BOOST_TEST( !tr2.eoi() ); - - char const* argv3[] = { "test.exe", "" }; - rt::cla::argv_traverser tr3( sizeof(argv3)/sizeof(char const*), argv3 ); - - BOOST_TEST( !tr3.eoi() ); -} - -//____________________________________________________________________________// - -BOOST_AUTO_TEST_CASE( test_get_char ) -{ - char const* argv1[] = { "test.exe", "ab c", "de", "" }; - rt::cla::argv_traverser tr1( sizeof(argv1)/sizeof(char const*), argv1 ); - - BOOST_TEST( tr1.get_char() == 'a' ); - BOOST_TEST( tr1.get_char() == 'b' ); - BOOST_TEST( tr1.get_char() == ' ' ); - BOOST_TEST( tr1.get_char() == 'c' ); - BOOST_TEST( tr1.get_char() == rt::cla::END_OF_TOKEN ); - BOOST_TEST( tr1.get_char() == 'd' ); - BOOST_TEST( tr1.get_char() == 'e' ); - BOOST_TEST( !tr1.eoi() ); - BOOST_TEST( tr1.get_char() == rt::cla::END_OF_TOKEN ); - BOOST_TEST( !tr1.eoi() ); - BOOST_TEST( tr1.get_char() == rt::cla::END_OF_TOKEN ); - BOOST_TEST( tr1.eoi() ); - BOOST_TEST( tr1.get_char() == rt::cla::END_OF_TOKEN ); -} - -//____________________________________________________________________________// - -BOOST_AUTO_TEST_CASE( test_get_token ) -{ - char const* argv1[] = { "test.exe", "abc", "zxcvb", "as kl", "--ooo=111", "a", "" }; - rt::cla::argv_traverser tr1( sizeof(argv1)/sizeof(char const*), argv1 ); - - BOOST_TEST( tr1.get_token() == "abc" ); - BOOST_TEST( tr1.get_char() == 'z' ); - BOOST_TEST( tr1.get_token() == "xcvb" ); - BOOST_TEST( tr1.get_token() == "as kl" ); - BOOST_TEST( tr1.get_char() == '-' ); - BOOST_TEST( tr1.get_token() == "-ooo=111" ); - BOOST_TEST( tr1.get_char() == 'a' ); - BOOST_TEST( !tr1.eoi() ); - BOOST_TEST( tr1.get_token() == rt::cstring() ); - BOOST_TEST( !tr1.eoi() ); - BOOST_TEST( tr1.get_token() == rt::cstring() ); - BOOST_TEST( tr1.eoi() ); - BOOST_TEST( tr1.get_token() == rt::cstring() ); -} - -//____________________________________________________________________________// - -BOOST_AUTO_TEST_CASE( test_remainder ) -{ - char const* argv[] = { "test.exe", "abcjkl", "zx vb" }; - rt::cla::argv_traverser tr( sizeof(argv)/sizeof(char const*), argv ); - - int new_argc = tr.remainder(); - - BOOST_TEST( new_argc == 3 ); - BOOST_TEST( argv[0] == "test.exe" ); - BOOST_TEST( argv[1] == "abcjkl" ); - BOOST_TEST( argv[2] == "zx vb" ); - - tr.get_char(); - new_argc = tr.remainder(); - - BOOST_TEST( new_argc == 3 ); - BOOST_TEST( argv[0] == "test.exe" ); - BOOST_TEST( argv[1] == "bcjkl" ); - BOOST_TEST( argv[2] == "zx vb" ); - - tr.get_token(); - new_argc = tr.remainder(); - - BOOST_TEST( new_argc == 2 ); - BOOST_TEST( argv[0] == "test.exe" ); - BOOST_TEST( argv[1] == "zx vb" ); - - tr.skip( 2 ); - new_argc = tr.remainder(); - - BOOST_TEST( new_argc == 2 ); - BOOST_TEST( argv[0] == "test.exe" ); - BOOST_TEST( argv[1] == " vb" ); - - tr.skip( 3 ); - new_argc = tr.remainder(); - - BOOST_TEST( new_argc == 1 ); - BOOST_TEST( argv[0] == "test.exe" ); -} - -BOOST_AUTO_TEST_SUITE_END() - -//____________________________________________________________________________// -//____________________________________________________________________________// -//____________________________________________________________________________// - -BOOST_AUTO_TEST_SUITE( test_parameter_specification, - * utf::depends_on("test_argv_traverser") ) - -BOOST_AUTO_TEST_CASE( test_param_construction ) -{ - rt::parameter p1( "P1" ); - - BOOST_TEST( p1.p_name == "P1" ); - BOOST_TEST( p1.p_description == "" ); - BOOST_TEST( p1.p_env_var == "" ); - BOOST_TEST( p1.p_optional ); - BOOST_TEST( !p1.p_repeatable ); - BOOST_TEST( !p1.p_has_optional_value ); - - rt::parameter p2( "P2", ( - rt::description = "123", - rt::env_var = "E2" - )); - - BOOST_TEST( p2.p_name == "P2" ); - BOOST_TEST( p2.p_description == "123" ); - BOOST_TEST( p2.p_env_var == "E2" ); - BOOST_TEST( !p2.p_optional ); - BOOST_TEST( !p2.p_repeatable ); - BOOST_TEST( !p2.p_has_optional_value ); - - rt::parameter p4( "P4", ( - rt::description = "123", - rt::env_var = "E4" - )); - - BOOST_TEST( p4.p_name == "P4" ); - BOOST_TEST( p4.p_description == "123" ); - BOOST_TEST( p4.p_env_var == "E4" ); - BOOST_TEST( p4.p_optional ); - BOOST_TEST( p4.p_repeatable ); - BOOST_TEST( !p4.p_has_optional_value ); - - rt::option p5( "P5", ( - rt::description = "bool arg", - rt::env_var = "E5" - )); - p5.add_cla_id( "-", "b", " " ); - - BOOST_TEST( p5.p_name == "P5" ); - BOOST_TEST( p5.p_description == "bool arg" ); - BOOST_TEST( p5.p_env_var == "E5" ); - BOOST_TEST( p5.p_optional ); - BOOST_TEST( !p5.p_repeatable ); - BOOST_TEST( p5.p_has_optional_value ); - - rt::option p6( "P6", ( - rt::description = "option with true default", - rt::env_var = "E6", - rt::default_value = true - )); - p6.add_cla_id( "-", "b", " " ); - - BOOST_TEST( p6.p_name == "P6" ); - BOOST_TEST( p6.p_description == "option with true default" ); - BOOST_TEST( p6.p_env_var == "E6" ); - BOOST_TEST( p6.p_optional ); - BOOST_TEST( !p6.p_repeatable ); - BOOST_TEST( p6.p_has_optional_value ); - - rt::parameter p3( "P3" ); - p3.add_cla_id( "/", "P3", ":" ); - p3.add_cla_id( "-", "p+p_p", " " ); - - BOOST_TEST( p3.cla_ids().size() == 3U ); - BOOST_TEST( p3.cla_ids()[1].m_prefix == "/" ); - BOOST_TEST( p3.cla_ids()[1].m_tag == "P3" ); - BOOST_TEST( p3.cla_ids()[1].m_value_separator == ":" ); - BOOST_TEST( p3.cla_ids()[2].m_prefix == "-" ); - BOOST_TEST( p3.cla_ids()[2].m_tag == "p+p_p" ); - BOOST_TEST( p3.cla_ids()[2].m_value_separator == "" ); - - BOOST_CHECK_THROW( p3.add_cla_id( "^", "p", " " ), rt::invalid_cla_id ); - BOOST_CHECK_THROW( p3.add_cla_id( " ", "p", " " ), rt::invalid_cla_id ); - BOOST_CHECK_THROW( p3.add_cla_id( "", "p", " " ), rt::invalid_cla_id ); - BOOST_CHECK_THROW( p3.add_cla_id( "-", "-abc", " " ), rt::invalid_cla_id ); - BOOST_CHECK_THROW( p3.add_cla_id( "-", "b c", " " ), rt::invalid_cla_id ); - BOOST_CHECK_THROW( p3.add_cla_id( "-", "", " " ), rt::invalid_cla_id ); - BOOST_CHECK_THROW( p3.add_cla_id( "-", "a", "-" ), rt::invalid_cla_id ); - BOOST_CHECK_THROW( p3.add_cla_id( "-", "a", "/" ), rt::invalid_cla_id ); - BOOST_CHECK_THROW( p3.add_cla_id( "-", "a", "" ), rt::invalid_cla_id ); - - rt::parameter p7( "P7", rt::optional_value = 1); - BOOST_CHECK_THROW( p7.add_cla_id( "-", "a", " " ), rt::invalid_cla_id ); - - BOOST_CHECK_THROW( (rt::parameter( "P", rt::default_value = 1)), rt::invalid_param_spec ); - BOOST_CHECK_THROW( (rt::parameter( "P", rt::default_value = std::vector{1})), rt::invalid_param_spec ); - BOOST_CHECK_THROW( (rt::parameter( "P", rt::optional_value = std::vector{1})), rt::invalid_param_spec ); - - enum EnumType { V1, V2 }; - rt::enum_parameter p8( "P8", ( - rt::enum_values::value = { - {"V1", V1}, - {"V2", V2}}, - rt::default_value = V1 - )); - - BOOST_TEST( p8.p_optional ); - BOOST_TEST( !p8.p_repeatable ); - BOOST_TEST( !p8.p_has_optional_value ); - BOOST_TEST( p8.p_has_default_value ); -} - -//____________________________________________________________________________// - -BOOST_AUTO_TEST_CASE( test_params_store ) -{ - rt::parameter p1( "P1" ); - rt::parameter p2( "P2" ); - rt::parameter p3( "P1" ); - - rt::parameters_store S; - - BOOST_TEST( S.is_empty() ); - - S.add( p1 ); - S.add( p2 ); - - BOOST_CHECK_THROW( S.add( p3 ), rt::duplicate_param ); - BOOST_TEST( !S.is_empty() ); - BOOST_TEST( S.all().size() == 2U ); - BOOST_TEST( S.get("P1")->p_name == "P1" ); - BOOST_TEST( S.get("P2")->p_name == "P2" ); - BOOST_CHECK_THROW( S.get("P3"), rt::unknown_param ); -} - -BOOST_AUTO_TEST_SUITE_END() - -//____________________________________________________________________________// -//____________________________________________________________________________// -//____________________________________________________________________________// - -BOOST_AUTO_TEST_CASE( test_param_trie_construction, - * utf::depends_on("test_parameter_specification") ) -{ - // make sure this does not crash - rt::parameters_store store; - rt::cla::parser parser( store ); - - rt::parameters_store store1; - - rt::parameter p1( "P1" ); - p1.add_cla_id( "--", "param_one", " " ); - p1.add_cla_id( "-", "p1", " " ); - store1.add( p1 ); - - rt::parameter p2( "P2" ); - p2.add_cla_id( "--", "param_two", " " ); - p2.add_cla_id( "-", "p2", " " ); - store1.add( p2 ); - - rt::parameter p3( "P3" ); - p3.add_cla_id( "--", "another_", " " ); - p3.add_cla_id( "/", "p3", " " ); - store1.add( p3 ); - - rt::parameter p4( "P4" ); - p4.add_cla_id( "-", "param_one", " " ); - store1.add( p4 ); - - rt::cla::parser parser1( store1 ); - - rt::parameters_store store2; - - rt::parameter p5( "P5" ); - p5.add_cla_id( "-", "paramA", " " ); - store2.add( p5 ); - - rt::parameter p6( "P6" ); - p6.add_cla_id( "-", "paramA", " " ); - store2.add( p6 ); - - BOOST_CHECK_THROW( rt::cla::parser parser( store2 ), rt::conflicting_param ); - - rt::parameters_store store3; - - rt::parameter p7( "P7" ); - p7.add_cla_id( "-", "paramA", " " ); - store3.add( p7 ); - - rt::parameter p8( "P8" ); - p8.add_cla_id( "-", "param", " " ); - store3.add( p8 ); - - BOOST_CHECK_THROW( rt::cla::parser parser( store3 ), rt::conflicting_param ); - - rt::parameters_store store4; - - rt::parameter p9( "P9" ); - p9.add_cla_id( "-", "param", " " ); - store4.add( p9 ); - - rt::parameter p10( "P10" ); - p10.add_cla_id( "-", "paramA", " " ); - store4.add( p10 ); - - BOOST_CHECK_THROW( rt::cla::parser parser( store4 ), rt::conflicting_param ); -} - -//____________________________________________________________________________// -//____________________________________________________________________________// -//____________________________________________________________________________// - -BOOST_AUTO_TEST_CASE( test_arguments_store ) -{ - rt::arguments_store store; - - BOOST_TEST( store.size() == 0U ); - BOOST_TEST( !store.has( "P1" ) ); - BOOST_TEST( !store.has( "P2" ) ); - BOOST_TEST( !store.has( "P3" ) ); - BOOST_TEST( !store.has( "P4" ) ); - BOOST_TEST( !store.has( "P5" ) ); - - store.set( "P1", 10 ); - store.set( "P2", std::string("abc") ); - store.set( "P3", rt::cstring("abc") ); - store.set( "P4", true ); - store.set( "P5", std::vector( 1, 12 ) ); - - BOOST_TEST( store.has( "P1" ) ); - BOOST_TEST( store.has( "P2" ) ); - BOOST_TEST( store.has( "P3" ) ); - BOOST_TEST( store.has( "P4" ) ); - BOOST_TEST( store.has( "P5" ) ); - BOOST_TEST( store.size() == 5U ); - - BOOST_TEST( store.get( "P1" ) == 10 ); - BOOST_TEST( store.get( "P2" ) == "abc" ); - BOOST_TEST( store.get( "P3" ) == "abc" ); - BOOST_TEST( store.get( "P4" ) == true); - BOOST_TEST( store.get>( "P5" ) == std::vector( 1, 12 ) ); - - store.set( "P1", 20 ); - BOOST_TEST( store.get( "P1" ) == 20 ); - - BOOST_CHECK_THROW( store.get( "P0" ), rt::access_to_missing_argument ); - BOOST_CHECK_THROW( store.get( "P1" ), rt::arg_type_mismatch ); -} - -//____________________________________________________________________________// -//____________________________________________________________________________// -//____________________________________________________________________________// - -BOOST_AUTO_TEST_SUITE( test_cla_parsing, - * utf::depends_on("test_argv_traverser") - * utf::depends_on("test_parameter_specification") - * utf::depends_on("test_arguments_store") ) - -BOOST_AUTO_TEST_CASE( test_basic_parsing ) -{ - rt::parameters_store params_store; - - rt::parameter p1( "P1" ); - p1.add_cla_id( "--", "param_one", "=" ); - p1.add_cla_id( "-", "p1", " " ); - params_store.add( p1 ); - - rt::parameter p2( "P2" ); - p2.add_cla_id( "--", "param_two", "=" ); - p2.add_cla_id( "-", "p2", " " ); - params_store.add( p2 ); - - rt::cla::parser parser( params_store ); - - char const* argv1[] = { "test.exe" }; - rt::arguments_store args_store1; - - parser.parse( sizeof(argv1)/sizeof(char const*), (char**)argv1, args_store1 ); - - BOOST_TEST( args_store1.size() == 0U ); - - char const* argv2[] = { "test.exe", "--param_one=abc" }; - rt::arguments_store args_store2; - - parser.parse( sizeof(argv2)/sizeof(char const*), (char**)argv2, args_store2 ); - - BOOST_TEST( args_store2.size() == 1U ); - BOOST_TEST( args_store2.has( "P1" ) ); - BOOST_TEST( args_store2.get( "P1" ) == "abc" ); - - char const* argv3[] = { "test.exe", "--param_two=12" }; - rt::arguments_store args_store3; - - parser.parse( sizeof(argv3)/sizeof(char const*), (char**)argv3, args_store3 ); - - BOOST_TEST( args_store3.size() == 1U ); - BOOST_TEST( args_store3.has( "P2" ) ); - BOOST_TEST( args_store3.get( "P2" ) == "12" ); - - char const* argv4[] = { "test.exe", "-p1", "aaa", "-p2", "37" }; - rt::arguments_store args_store4; - - parser.parse( sizeof(argv4)/sizeof(char const*), (char**)argv4, args_store4 ); - - BOOST_TEST( args_store4.size() == 2U ); - BOOST_TEST( args_store4.has( "P1" ) ); - BOOST_TEST( args_store4.get( "P1" ) == "aaa" ); - BOOST_TEST( args_store4.has( "P2" ) ); - BOOST_TEST( args_store4.get( "P2" ) == "37" ); -} - -//____________________________________________________________________________// - -BOOST_AUTO_TEST_CASE( test_typed_argument_parsing ) -{ - rt::parameters_store params_store; - - rt::parameter p1( "P1" ); - p1.add_cla_id( "--", "param_one", "=" ); - p1.add_cla_id( "-", "p1", " " ); - params_store.add( p1 ); - - rt::parameter p2( "P2" ); - p2.add_cla_id( "--", "param_two", "=" ); - p2.add_cla_id( "-", "p2", " " ); - params_store.add( p2 ); - - rt::option p3( "P3" ); - p3.add_cla_id( "--", "third", "=" ); - p3.add_cla_id( "-", "p3", " " ); - params_store.add( p3 ); - - rt::parameter p4( "P4" ); - p4.add_cla_id( "--", "another", "=" ); - p4.add_cla_id( "-", "p4", " " ); - params_store.add( p4 ); - - rt::cla::parser parser( params_store ); - - char const* argv1[] = { "test.exe", "--another=some thing", "-p1", "1.2", "-p2", "37", "--third=Y" }; - rt::arguments_store args_store1; - - parser.parse( sizeof(argv1)/sizeof(char const*), (char**)argv1, args_store1 ); - - BOOST_TEST( args_store1.size() == 4U ); - BOOST_TEST( args_store1.has( "P1" ) ); - BOOST_TEST( args_store1.get( "P1" ) == 1.2 ); - BOOST_TEST( args_store1.has( "P2" ) ); - BOOST_TEST( args_store1.get( "P2" ) == 37 ); - BOOST_TEST( args_store1.has( "P3" ) ); - BOOST_TEST( args_store1.get( "P3" ) ); - BOOST_TEST( args_store1.has( "P4" ) ); - BOOST_TEST( args_store1.get( "P4" ) == "some thing" ); - - char const* argv2[] = { "test.exe", "-p3" }; - rt::arguments_store args_store2; - - parser.parse( sizeof(argv2)/sizeof(char const*), (char**)argv2, args_store2 ); - BOOST_TEST( args_store2.size() == 1U ); - BOOST_TEST( args_store2.has( "P3" ) ); - BOOST_TEST( args_store2.get( "P3" ) ); -} - -//____________________________________________________________________________// - -BOOST_AUTO_TEST_CASE( test_parameter_name_guessing ) -{ - rt::parameters_store params_store; - - rt::parameter p1( "P1" ); - p1.add_cla_id( "--", "param_one", "=" ); - p1.add_cla_id( "-", "one", " " ); - params_store.add( p1 ); - - rt::parameter p2( "P2" ); - p2.add_cla_id( "--", "param_two", "=" ); - p2.add_cla_id( "-", "two", " " ); - params_store.add( p2 ); - - rt::cla::parser parser( params_store ); - - char const* argv1[] = { "test.exe", "--param_o=1", "-t", "2" }; - rt::arguments_store args_store1; - - parser.parse( sizeof(argv1)/sizeof(char const*), (char**)argv1, args_store1 ); - - BOOST_TEST( args_store1.size() == 2U ); - BOOST_TEST( args_store1.has( "P1" ) ); - BOOST_TEST( args_store1.has( "P2" ) ); -} - -//____________________________________________________________________________// - -BOOST_AUTO_TEST_CASE( test_repeatable_parameters ) -{ - rt::parameters_store params_store; - - rt::parameter p1( "P1" ); - p1.add_cla_id( "--", "param_one", "=" ); - p1.add_cla_id( "-", "one", " " ); - params_store.add( p1 ); - - rt::cla::parser parser( params_store ); - rt::arguments_store args_store; - - char const* argv[] = { "test.exe", "-one", "1", "-one", "2" }; - parser.parse( sizeof(argv)/sizeof(char const*), (char**)argv, args_store ); - - BOOST_TEST( args_store.size() == 1U ); - BOOST_TEST( args_store.has( "P1" ) ); - - std::vector P1_expected{1, 2}; - BOOST_TEST( args_store.get>( "P1" ) == P1_expected ); -} - -//____________________________________________________________________________// - -BOOST_AUTO_TEST_CASE( test_parameter_with_optional_value ) -{ - rt::parameters_store params_store; - - rt::parameter p1( "P1", rt::optional_value = 5 ); - p1.add_cla_id( "--", "param_one", "=" ); - params_store.add( p1 ); - - rt::cla::parser parser( params_store ); - - rt::arguments_store args_store1; - char const* argv1[] = { "test.exe", "--param_one=1" }; - parser.parse( sizeof(argv1)/sizeof(char const*), (char**)argv1, args_store1 ); - - BOOST_TEST( args_store1.size() == 1U ); - BOOST_TEST( args_store1.has( "P1" ) ); - BOOST_TEST( args_store1.get( "P1" ) == 1 ); - - rt::arguments_store args_store2; - char const* argv2[] = { "test.exe", "--param_one" }; - parser.parse( sizeof(argv2)/sizeof(char const*), (char**)argv2, args_store2 ); - - BOOST_TEST( args_store2.size() == 1U ); - BOOST_TEST( args_store2.has( "P1" ) ); - BOOST_TEST( args_store2.get( "P1" ) == 5 ); -} - -//____________________________________________________________________________// - -BOOST_AUTO_TEST_CASE( test_validations ) -{ - rt::parameters_store params_store; - - rt::parameter p1( "P1" ); - p1.add_cla_id( "--", "param_one", "=" ); - p1.add_cla_id( "-", "one", " " ); - params_store.add( p1 ); - - rt::parameter p2( "P2" ); - p2.add_cla_id( "--", "param_two", "=" ); - p2.add_cla_id( "-", "two", " " ); - params_store.add( p2 ); - - rt::option p3( "P3" ); - p3.add_cla_id( "--", "option", "=" ); - params_store.add( p3 ); - - rt::cla::parser parser( params_store ); - rt::arguments_store args_store; - - { - char const* argv[] = { "test.exe", "param_one=1" }; - BOOST_CHECK_THROW( parser.parse( sizeof(argv)/sizeof(char const*), (char**)argv, args_store ), rt::format_error ); - } - - { - char const* argv[] = { "test.exe", "/param_one=1" }; - BOOST_CHECK_THROW( parser.parse( sizeof(argv)/sizeof(char const*), (char**)argv, args_store ), rt::format_error ); - } - - { - char const* argv[] = { "test.exe", "---param_one=1" }; - BOOST_CHECK_THROW( parser.parse( sizeof(argv)/sizeof(char const*), (char**)argv, args_store ), rt::format_error ); - } - - { - char const* argv[] = { "test.exe", "--=1" }; - BOOST_CHECK_THROW( parser.parse( sizeof(argv)/sizeof(char const*), (char**)argv, args_store ), rt::format_error ); - } - - { - char const* argv[] = { "test.exe", "--param_one:1" }; - BOOST_CHECK_THROW( parser.parse( sizeof(argv)/sizeof(char const*), (char**)argv, args_store ), rt::format_error ); - } - - { - char const* argv[] = { "test.exe", "--param_one=" }; - BOOST_CHECK_THROW( parser.parse( sizeof(argv)/sizeof(char const*), (char**)argv, args_store ), rt::format_error ); - } - - { - char const* argv[] = { "test.exe", "--param_one=1", "--param_one=2" }; - BOOST_CHECK_THROW( parser.parse( sizeof(argv)/sizeof(char const*), (char**)argv, args_store ), rt::duplicate_arg ); - } - - { - char const* argv[] = { "test.exe", "--param=1" }; - BOOST_CHECK_THROW( parser.parse( sizeof(argv)/sizeof(char const*), (char**)argv, args_store ), rt::ambiguous_param ); - } - - { - char const* argv[] = { "test.exe", "=1" }; - BOOST_CHECK_THROW( parser.parse( sizeof(argv)/sizeof(char const*), (char**)argv, args_store ), rt::format_error ); - } - - { - char const* argv[] = { "test.exe", "--opt=Yeah" }; - BOOST_CHECK_THROW( parser.parse( sizeof(argv)/sizeof(char const*), (char**)argv, args_store ), rt::format_error ); - } -} - -//____________________________________________________________________________// - -BOOST_AUTO_TEST_CASE( test_unrecognized_param_suggestions ) -{ - rt::parameters_store params_store; - - rt::parameter p1( "P1" ); - p1.add_cla_id( "--", "param_one", "=" ); - p1.add_cla_id( "-", "p1", " " ); - params_store.add( p1 ); - - rt::parameter p2( "P2" ); - p2.add_cla_id( "--", "param_two", "=" ); - params_store.add( p2 ); - - rt::parameter p3( "P3" ); - p3.add_cla_id( "--", "param_three", "=" ); - params_store.add( p3 ); - - rt::cla::parser parser( params_store ); - rt::arguments_store args_store; - - { - char const* argv[] = { "test.exe", "--laram_one=1" }; - BOOST_CHECK_EXCEPTION( parser.parse( sizeof(argv)/sizeof(char const*), (char**)argv, args_store ), - rt::unrecognized_param, - []( rt::unrecognized_param const& ex ) -> bool { - return ex.m_typo_candidates == std::vector{"param_one"}; - }); - } - - { - char const* argv[] = { "test.exe", "--paran_one=1" }; - BOOST_CHECK_EXCEPTION( parser.parse( sizeof(argv)/sizeof(char const*), (char**)argv, args_store ), - rt::unrecognized_param, - []( rt::unrecognized_param const& ex ) -> bool { - return ex.m_typo_candidates == std::vector{"param_one"}; - }); - } - - { - char const* argv[] = { "test.exe", "--param_onw=1" }; - BOOST_CHECK_EXCEPTION( parser.parse( sizeof(argv)/sizeof(char const*), (char**)argv, args_store ), - rt::unrecognized_param, - []( rt::unrecognized_param const& ex ) -> bool { - return ex.m_typo_candidates == std::vector{"param_one"}; - }); - } - - { - char const* argv[] = { "test.exe", "--param_to=1" }; - BOOST_CHECK_EXCEPTION( parser.parse( sizeof(argv)/sizeof(char const*), (char**)argv, args_store ), - rt::unrecognized_param, - ([]( rt::unrecognized_param const& ex ) -> bool { - return ex.m_typo_candidates == std::vector{"param_three", "param_two"}; - })); - } - - { - char const* argv[] = { "test.exe", "--paramtwo=1" }; - BOOST_CHECK_EXCEPTION( parser.parse( sizeof(argv)/sizeof(char const*), (char**)argv, args_store ), - rt::unrecognized_param, - ([]( rt::unrecognized_param const& ex ) -> bool { - return ex.m_typo_candidates == std::vector{"param_two"}; - })); - } - - { - char const* argv[] = { "test.exe", "--parum_=1" }; - BOOST_CHECK_EXCEPTION( parser.parse( sizeof(argv)/sizeof(char const*), (char**)argv, args_store ), - rt::unrecognized_param, - ([]( rt::unrecognized_param const& ex ) -> bool { - return ex.m_typo_candidates == std::vector{}; - })); - } - - { - char const* argv[] = { "test.exe", "--param__one=1" }; - BOOST_CHECK_EXCEPTION( parser.parse( sizeof(argv)/sizeof(char const*), (char**)argv, args_store ), - rt::unrecognized_param, - ([]( rt::unrecognized_param const& ex ) -> bool { - return ex.m_typo_candidates == std::vector{"param_one"}; - })); - } - - { - char const* argv[] = { "test.exe", "--param_twoo=1" }; - BOOST_CHECK_EXCEPTION( parser.parse( sizeof(argv)/sizeof(char const*), (char**)argv, args_store ), - rt::unrecognized_param, - ([]( rt::unrecognized_param const& ex ) -> bool { - return ex.m_typo_candidates == std::vector{"param_two"}; - })); - } -} - -//____________________________________________________________________________// - -BOOST_AUTO_TEST_CASE( test_end_of_params ) -{ - rt::parameters_store params_store; - - rt::parameter p1( "P1" ); - p1.add_cla_id( "--", "param_one", "=" ); - p1.add_cla_id( "-", "p1", " " ); - params_store.add( p1 ); - - rt::parameter p2( "P2" ); - p2.add_cla_id( "--", "param_two", "=" ); - params_store.add( p2 ); - - BOOST_CHECK_THROW( rt::cla::parser parser( params_store, rt::end_of_params = "==" ), rt::invalid_cla_id ); - - rt::cla::parser parser( params_store, rt::end_of_params = "--" ); - - { - rt::arguments_store args_store; - char const* argv[] = { "test.exe", "--param_one=1", "--", "/abc" }; - int new_argc = parser.parse( sizeof(argv)/sizeof(char const*), (char**)argv, args_store ); - - BOOST_TEST( args_store.size() == 1U ); - BOOST_TEST( args_store.has( "P1" ) ); - BOOST_TEST( args_store.get( "P1" ) == 1 ); - BOOST_TEST( new_argc == 2 ); - } - - { - rt::arguments_store args_store; - char const* argv[] = { "test.exe", "-p1", "1", "--", "--param_two=2" }; - int new_argc = parser.parse( sizeof(argv)/sizeof(char const*), (char**)argv, args_store ); - - BOOST_TEST( args_store.size() == 1U ); - BOOST_TEST( args_store.has( "P1" ) ); - BOOST_TEST( !args_store.has( "P2" ) ); - BOOST_TEST( args_store.get( "P1" ) == 1 ); - BOOST_TEST( new_argc == 2 ); - } -} - -//____________________________________________________________________________// - -BOOST_AUTO_TEST_CASE( test_negation_prefix ) -{ - rt::parameters_store params_store; - - rt::parameter p1( "P1" ); - p1.add_cla_id( "--", "param_one", "=" ); - p1.add_cla_id( "-", "p1", " " ); - params_store.add( p1 ); - - rt::option p2( "P2" ); - p2.add_cla_id( "--", "param_two", "=", true ); - p2.add_cla_id( "-", "p2", " ", true ); - p2.add_cla_id( "-", "p3", " " ); - params_store.add( p2 ); - - BOOST_CHECK_THROW( rt::cla::parser parser( params_store, rt::negation_prefix = "no:" ), rt::invalid_cla_id ); - - rt::cla::parser parser( params_store, rt::negation_prefix = "no_" ); - - { - rt::arguments_store args_store; - char const* argv[] = { "test.exe", "--no_param_two" }; - parser.parse( sizeof(argv)/sizeof(char const*), (char**)argv, args_store ); - - BOOST_TEST( args_store.size() == 1U ); - BOOST_TEST( args_store.has( "P2" ) ); - BOOST_TEST( args_store.get( "P2" ) == false ); - } - - { - rt::arguments_store args_store; - char const* argv[] = { "test.exe", "-no_p2" }; - parser.parse( sizeof(argv)/sizeof(char const*), (char**)argv, args_store ); - - BOOST_TEST( args_store.size() == 1U ); - BOOST_TEST( args_store.has( "P2" ) ); - BOOST_TEST( args_store.get( "P2" ) == false ); - } - - { - rt::arguments_store args_store; - char const* argv[] = { "test.exe", "--no_param_one" }; - BOOST_CHECK_THROW( parser.parse( sizeof(argv)/sizeof(char const*), (char**)argv, args_store ), rt::format_error ); - } - - { - rt::arguments_store args_store; - char const* argv[] = { "test.exe", "--no_param_two=Y" }; - BOOST_CHECK_THROW( parser.parse( sizeof(argv)/sizeof(char const*), (char**)argv, args_store ), rt::format_error ); - } - - { - rt::arguments_store args_store; - char const* argv[] = { "test.exe", "-no_p3" }; - BOOST_CHECK_THROW( parser.parse( sizeof(argv)/sizeof(char const*), (char**)argv, args_store ), rt::format_error ); - } -} - -//____________________________________________________________________________// - -BOOST_AUTO_TEST_CASE( test_enum_parameter ) -{ - rt::parameters_store params_store; - - enum EnumType { V1, V2, V3 }; - rt::enum_parameter p1( "P1", ( - rt::enum_values::value = { - {"V1", V1}, - {"V2", V2}}, - rt::default_value = V3 - )); - - p1.add_cla_id( "--", "param_one", "=" ); - params_store.add( p1 ); - - rt::enum_parameter p2( "P2", ( - rt::enum_values::value = { - {"V1", V1}, - {"V2", V2}, - {"V2alt", V2}, - {"V3", V3}} - )); - p2.add_cla_id( "--", "param_two", " " ); - params_store.add( p2 ); - - rt::cla::parser parser( params_store ); - - { - rt::arguments_store args_store; - char const* argv[] = { "test.exe", "--param_one=V1" }; - parser.parse( sizeof(argv)/sizeof(char const*), (char**)argv, args_store ); - BOOST_TEST( args_store.has( "P1" ) ); - BOOST_TEST( args_store.get( "P1" ) == V1 ); - } - - { - rt::arguments_store args_store; - char const* argv[] = { "test.exe", "--param_one=V2" }; - parser.parse( sizeof(argv)/sizeof(char const*), (char**)argv, args_store ); - rt::finalize_arguments( params_store, args_store ); - BOOST_TEST( args_store.has( "P1" ) ); - BOOST_TEST( args_store.get( "P1" ) == V2 ); - } - - { - rt::arguments_store args_store; - char const* argv[] = { "test.exe" }; - parser.parse( sizeof(argv)/sizeof(char const*), (char**)argv, args_store ); - rt::finalize_arguments( params_store, args_store ); - BOOST_TEST( args_store.has( "P1" ) ); - BOOST_TEST( args_store.get( "P1" ) == V3 ); - } - - { - rt::arguments_store args_store; - char const* argv[] = { "test.exe", "--param_one=V3" }; - BOOST_CHECK_THROW( parser.parse( sizeof(argv)/sizeof(char const*), (char**)argv, args_store ), rt::format_error ); - } - - { - rt::arguments_store args_store; - char const* argv[] = { "test.exe", "--param_two", "V2alt", "--param_two", "V1", "--param_two", "V3" }; - parser.parse( sizeof(argv)/sizeof(char const*), (char**)argv, args_store ); - rt::finalize_arguments( params_store, args_store ); - BOOST_TEST( args_store.has( "P2" ) ); - BOOST_TEST( args_store.get>( "P2" ) == (std::vector{V2, V1, V3}) ); - } - - { - rt::arguments_store args_store; - char const* argv[] = { "test.exe" }; - parser.parse( sizeof(argv)/sizeof(char const*), (char**)argv, args_store ); - rt::finalize_arguments( params_store, args_store ); - BOOST_TEST( args_store.has( "P2" ) ); - BOOST_TEST( args_store.get>( "P2" ) == std::vector{} ); - } -} - -//____________________________________________________________________________// - -BOOST_AUTO_TEST_SUITE_END() - -//____________________________________________________________________________// -//____________________________________________________________________________// -//____________________________________________________________________________// - -BOOST_AUTO_TEST_CASE( test_fetch_from_environment ) -{ - rt::parameters_store params_store; - - rt::parameter p1( "P1", rt::env_var = "P1VAR"); - params_store.add( p1 ); - - rt::option p2( "P2", rt::env_var = "P2VAR"); - params_store.add( p2 ); - - rt::option p3( "P3"); - params_store.add( p3 ); - - { - rt::arguments_store args_store; - - auto env_read = []( rt::cstring ) -> std::pair - { - return std::make_pair( rt::cstring(), false ); - }; - - rt::env::env_detail::fetch_absent( params_store, args_store, env_read ); - - BOOST_TEST( args_store.size() == 0U ); - } - - { - rt::arguments_store args_store; - args_store.set( "P1", 3 ); - args_store.set( "P2", true ); - - auto env_read = []( rt::cstring ) -> std::pair - { - return std::make_pair( rt::cstring(), false ); - }; - - rt::env::env_detail::fetch_absent( params_store, args_store, env_read ); - - BOOST_TEST( args_store.size() == 2U ); - BOOST_TEST( args_store.has( "P1" ) ); - BOOST_TEST( !args_store.has( "P1VAR" ) ); - BOOST_TEST( args_store.has( "P2" ) ); - BOOST_TEST( args_store.get( "P1" ) == 3 ); - BOOST_TEST( args_store.get( "P2" ) == true ); - } - - { - rt::arguments_store args_store; - - auto env_read = []( rt::cstring var_name ) -> std::pair - { - if( var_name == "P1VAR" ) - return std::make_pair( rt::cstring("5"), true ); - - if( var_name == "P2VAR" ) - return std::make_pair( rt::cstring("Y"), true ); - - return std::make_pair( rt::cstring(), false ); - }; - - rt::env::env_detail::fetch_absent( params_store, args_store, env_read ); - - BOOST_TEST( args_store.size() == 2U ); - BOOST_TEST( args_store.has( "P1" ) ); - BOOST_TEST( !args_store.has( "P1VAR" ) ); - BOOST_TEST( args_store.has( "P2" ) ); - BOOST_TEST( args_store.get( "P1" ) == 5 ); - BOOST_TEST( args_store.get( "P2" ) == true ); - } - - { - rt::arguments_store args_store; - - auto env_read = []( rt::cstring var_name ) -> std::pair - { - if( var_name == "P2VAR" ) - return std::make_pair( rt::cstring("No"), true ); - - return std::make_pair( rt::cstring(), false ); - }; - - rt::env::env_detail::fetch_absent( params_store, args_store, env_read ); - - BOOST_TEST( args_store.size() == 1U ); - BOOST_TEST( !args_store.has( "P1" ) ); - BOOST_TEST( args_store.has( "P2" ) ); - BOOST_TEST( args_store.get( "P2" ) == false ); - } - - { - rt::arguments_store args_store; - - auto env_read = []( rt::cstring var_name ) -> std::pair - { - if( var_name == "P2VAR" ) - return std::make_pair( rt::cstring(), true ); - - return std::make_pair( rt::cstring(), false ); - }; - - rt::env::env_detail::fetch_absent( params_store, args_store, env_read ); - - BOOST_TEST( args_store.size() == 1U ); - BOOST_TEST( !args_store.has( "P1" ) ); - BOOST_TEST( args_store.has( "P2" ) ); - BOOST_TEST( args_store.get( "P2" ) == true ); - } - - { - rt::arguments_store args_store; - - auto env_read = []( rt::cstring var_name ) -> std::pair - { - if( var_name == "P1VAR" ) - return std::make_pair( rt::cstring("one"), true ); - - return std::make_pair( rt::cstring(), false ); - }; - - BOOST_CHECK_THROW( rt::env::env_detail::fetch_absent( params_store, args_store, env_read ), - rt::format_error ); - } - - { - rt::arguments_store args_store; - - auto env_read = []( rt::cstring var_name ) -> std::pair - { - if( var_name == "P1VAR" ) - return std::make_pair( rt::cstring(), true ); - - return std::make_pair( rt::cstring(), false ); - }; - - BOOST_CHECK_THROW( rt::env::env_detail::fetch_absent( params_store, args_store, env_read ), - rt::format_error ); - } -} - -//____________________________________________________________________________// - -BOOST_AUTO_TEST_CASE( test_finalize_arguments ) -{ - rt::parameters_store params_store; - - rt::parameter p1( "P1" ); - p1.add_cla_id( "--", "param_one", "=" ); - p1.add_cla_id( "-", "p1", " " ); - params_store.add( p1 ); - - rt::parameter p2( "P2", rt::default_value = 10 ); - params_store.add( p2 ); - - rt::option p3( "P3" ); - params_store.add( p3 ); - - rt::option p4( "P4", rt::default_value = true ); - - params_store.add( p4 ); - - { - rt::arguments_store args_store; - args_store.set( "P1", 3 ); - - rt::finalize_arguments( params_store, args_store ); - - BOOST_TEST( args_store.size() == 4U ); - BOOST_TEST( args_store.has( "P1" ) ); - BOOST_TEST( args_store.has( "P2" ) ); - BOOST_TEST( args_store.has( "P3" ) ); - BOOST_TEST( args_store.has( "P4" ) ); - BOOST_TEST( args_store.get( "P1" ) == 3 ); - BOOST_TEST( args_store.get( "P2" ) == 10 ); - BOOST_TEST( args_store.get( "P3" ) == false ); - BOOST_TEST( args_store.get( "P4" ) == true ); - } - - { - rt::arguments_store args_store; - args_store.set( "P1", 3 ); - args_store.set( "P2", 4 ); - - rt::finalize_arguments( params_store, args_store ); - - BOOST_TEST( args_store.size() == 4U ); - BOOST_TEST( args_store.has( "P1" ) ); - BOOST_TEST( args_store.has( "P2" ) ); - BOOST_TEST( args_store.get( "P1" ) == 3 ); - BOOST_TEST( args_store.get( "P2" ) == 4 ); - } - - { - rt::arguments_store args_store; - - BOOST_CHECK_THROW( rt::finalize_arguments( params_store, args_store ), rt::missing_req_arg ); - } -} - -//____________________________________________________________________________// - -BOOST_AUTO_TEST_CASE( test_param_callback ) -{ - rt::parameters_store params_store; - - int counter = 0; - auto cb = [&counter](rt::cstring param_name ) - { - BOOST_TEST( param_name == "P1" ); - counter++; - }; - - rt::parameter p1( "P1", rt::callback = cb ); - params_store.add( p1 ); - - rt::parameter p2( "P2" ); - params_store.add( p2 ); - - { - rt::arguments_store args_store; - args_store.set( "P1", 3 ); - - rt::finalize_arguments( params_store, args_store ); - BOOST_TEST( counter == 1 ); - } - - { - rt::arguments_store args_store; - args_store.set( "P2", 3 ); - - rt::finalize_arguments( params_store, args_store ); - BOOST_TEST( counter == 1 ); - } -} - -// EOF - -// cla help/usage -// build info diff --git a/test/writing-test-ts/test_tools-test.cpp b/test/writing-test-ts/test_tools-test.cpp index 57bdd25b..10d335b1 100644 --- a/test/writing-test-ts/test_tools-test.cpp +++ b/test/writing-test-ts/test_tools-test.cpp @@ -128,14 +128,11 @@ BOOST_AUTO_TEST_CASE( name ) \ ut::framework::finalize_setup_phase( impl->p_id ); \ ut::framework::run( impl ); \ \ - ut::log_level ll = ut::runtime_config::get( \ - ut::runtime_config::LOG_LEVEL ); \ - ut::output_format lf = ut::runtime_config::get( \ - ut::runtime_config::LOG_FORMAT ); \ - \ ut::unit_test_log.set_threshold_level( \ - ll != ut::invalid_log_level ? ll : ut::log_all_errors ); \ - ut::unit_test_log.set_format( lf ); \ + ut::runtime_config::log_level() != ut::invalid_log_level \ + ? ut::runtime_config::log_level() \ + : ut::log_all_errors ); \ + ut::unit_test_log.set_format( ut::runtime_config::log_format());\ ut::unit_test_log.set_stream( std::cout ); \ BOOST_CHECK( ots().match_pattern() ); \ } \