diff --git a/test/Jamfile.v2 b/test/Jamfile.v2 index 41a685e..e18e008 100644 --- a/test/Jamfile.v2 +++ b/test/Jamfile.v2 @@ -32,6 +32,7 @@ test-suite program_options : [ po-test split_test.cpp ] [ po-test unrecognized_test.cpp ] [ po-test required_test.cpp : required_test.cfg ] + [ po-test exception_txt_test.cpp ] ; exe test_convert : test_convert.cpp ; diff --git a/test/exception_txt_test.cpp b/test/exception_txt_test.cpp index ade6846..039aa55 100644 --- a/test/exception_txt_test.cpp +++ b/test/exception_txt_test.cpp @@ -101,7 +101,7 @@ const int long_dash = command_line_style::allow_long | command_line_style::long_ template -void test_exception_message(const vector>& argv, +void test_exception_message(const vector >& argv, options_description& desc, const string& error_description, const char* expected_message_template[5]) @@ -152,10 +152,10 @@ void test_invalid_option_value_exception_msg() { options_description desc; desc.add_options() - ("int_option,d", value< int >(), "An option taking an integer") + ("int-option,d", value< int >(), "An option taking an integer") ; - vector> argv; + vector > argv; const char* argv0[] = { "program", "-d", "A_STRING"} ; VEC_STR_PUSH_BACK(argv, argv0); const char* argv1[] = { "program", "--int", "A_STRING"}; VEC_STR_PUSH_BACK(argv, argv1); const char* argv2[] = { "program", "-d", "A_STRING"} ; VEC_STR_PUSH_BACK(argv, argv2); @@ -163,11 +163,11 @@ void test_invalid_option_value_exception_msg() const char* argv4[] = { "int_option=A_STRING"} ; VEC_STR_PUSH_BACK(argv, argv4); const char* expected_msg[5] = { - "the argument ('A_STRING') for option '--int_option' is invalid", - "the argument ('A_STRING') for option '--int_option' is invalid", + "the argument ('A_STRING') for option '--int-option' is invalid", + "the argument ('A_STRING') for option '--int-option' is invalid", "the argument ('A_STRING') for option '-d' is invalid", "the argument ('A_STRING') for option '/d' is invalid", - "the argument ('A_STRING') for option 'int_option' is invalid" + "the argument ('A_STRING') for option 'int-option' is invalid", }; @@ -189,7 +189,7 @@ void test_missing_value_exception_msg() ("cfgfile,e", value(), "the config file") ("output,o", value(), "the output file") ; - vector> argv; + vector > argv; const char* argv0[] = { "program", "-e", "-e", "output.txt"} ; VEC_STR_PUSH_BACK(argv, argv0); const char* argv1[] = { "program", "--cfgfile"} ; VEC_STR_PUSH_BACK(argv, argv1); const char* argv2[] = { "program", "-e", "-e", "output.txt"} ; VEC_STR_PUSH_BACK(argv, argv2); @@ -225,7 +225,7 @@ void test_ambiguous_option_exception_msg() ("output", value(), "the output file") ; - vector> argv; + vector > argv; const char* argv0[] = {"program", "-ggc", "file", "-o", "anotherfile"} ; VEC_STR_PUSH_BACK(argv, argv0); const char* argv1[] = {"program", "--cfgfile", "file", "--cfgfile", "anotherfile"} ; VEC_STR_PUSH_BACK(argv, argv1); const char* argv2[] = {"program", "-ggc", "file", "-o", "anotherfile"} ; VEC_STR_PUSH_BACK(argv, argv2); @@ -254,7 +254,7 @@ void test_multiple_occurrences_exception_msg() ("cfgfile,c", value(), "the configfile") ; - vector> argv; + vector > argv; const char* argv0[] = {"program", "-c", "file", "-c", "anotherfile"} ; VEC_STR_PUSH_BACK(argv, argv0); const char* argv1[] = {"program", "--cfgfi", "file", "--cfgfi", "anotherfile"} ; VEC_STR_PUSH_BACK(argv, argv1); const char* argv2[] = {"program", "-c", "file", "-c", "anotherfile"} ; VEC_STR_PUSH_BACK(argv, argv2); @@ -283,7 +283,7 @@ void test_unknown_option_exception_msg() ("good,g", "good option") ; - vector> argv; + vector > argv; const char* argv0[] = {"program", "-ggc", "file"} ; VEC_STR_PUSH_BACK(argv, argv0); const char* argv1[] = {"program", "--cfgfile", "file"} ; VEC_STR_PUSH_BACK(argv, argv1); const char* argv2[] = {"program", "-ggc", "file"} ; VEC_STR_PUSH_BACK(argv, argv2); @@ -312,7 +312,7 @@ void test_invalid_bool_value_exception_msg() ; - vector> argv; + vector > argv; const char* argv0[] = {"program", "-b", "file"} ; VEC_STR_PUSH_BACK(argv, argv0); const char* argv1[] = {"program", "--bool_optio", "file"} ; VEC_STR_PUSH_BACK(argv, argv1); const char* argv2[] = {"program", "-b", "file"} ; VEC_STR_PUSH_BACK(argv, argv2); @@ -353,7 +353,7 @@ void test_multiple_values_not_allowed_exception_msg() ("output,o", value(), "the output file") ; - vector> argv; + vector > argv; const char* argv0[] = { "program", "-c", "file", "c", "-o", "fritz", "hugo" } ; VEC_STR_PUSH_BACK(argv, argv0); const char* argv1[] = { "program", "--cfgfil", "file", "c", "--outpu", "fritz", "hugo" } ; VEC_STR_PUSH_BACK(argv, argv1); const char* argv2[] = { "program", "-c", "file", "c", "-o", "fritz", "hugo"} ; VEC_STR_PUSH_BACK(argv, argv2); @@ -392,7 +392,7 @@ void test_at_least_one_value_required_exception_msg() ("other,o", value(), "other") ; - vector> argv; + vector > argv; const char* argv0[] = { "program", "-c" } ; VEC_STR_PUSH_BACK(argv, argv0); const char* argv1[] = { "program", "--cfg", "--o", "name" } ; VEC_STR_PUSH_BACK(argv, argv1); const char* argv2[] = { "program", "-c" , "-o" , "name" } ; VEC_STR_PUSH_BACK(argv, argv2); @@ -426,7 +426,7 @@ void test_required_option_exception_msg() ("output,o", value()->required(), "the output file") ; - vector> argv; + vector > argv; const char* argv0[] = { "program", "-g" } ; VEC_STR_PUSH_BACK(argv, argv0); const char* argv1[] = { "program", "--g" } ; VEC_STR_PUSH_BACK(argv, argv1); const char* argv2[] = { "program", "-g"} ; VEC_STR_PUSH_BACK(argv, argv2); @@ -660,7 +660,7 @@ int main(int /*ac*/, char** /*av*/) test_exception(test_name, expected_message, abbreviated_options_in_config_file); test_name = "too_many_positional_options"; - expected_message = "too many positional arguments have been specified on the command line"; + expected_message = "too many positional options have been specified on the command line"; test_exception( test_name, expected_message, too_many_positional_options); @@ -670,3384 +670,3 @@ int main(int /*ac*/, char** /*av*/) return 0; } - - -// Copyright Sascha Ochsenknecht 2009. -// 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) - - -#include -#include -#include -#include -using namespace boost::program_options; - -#include -#include -#include -#include -using namespace std; - -#include "minitest.hpp" - - - -// -// like BOOST_CHECK_EQUAL but with more descriptive error message -// -#define CHECK_EQUAL(description, a, b) if (a != b) {std::cerr << "\n\nError:\n<<" << \ - description << ">>\n Expected text=\"" << b << "\"\n Actual text =\"" << a << "\"\n\n"; assert(a == b);} - - -// Uncomment for Debugging, removes asserts so we can see more failures! -//#define BOOST_ERROR(description) std::cerr << description; std::cerr << "\n"; - - -//8888888888888888888888888888888888888888888888888888888888888888888888888888888888888888 -// -// Uncomment to print out the complete set of diagnostic messages for the different test cases -/* -#define CHECK_EQUAL(description, a, b) if (a != b) {std::cerr << "\n\nError: " << \ - description << "\n Expecting\n" << b << "\n Found\n" << a << "\n\n"; } \ - else {std::cout << description<< "\t" << b << "\n";} -*/ - -//8888888888888888888888888888888888888888888888888888888888888888888888888888888888888888 - - -// -// test exception for each specified command line style, e.g. short dash or config file -// -template -void test_each_exception_message(const string& test_description, const vector& argv, options_description& desc, int style, string exception_msg, istream& is = cin) -{ - if (exception_msg.length() == 0) - return; - variables_map vm; - unsigned argc = argv.size(); - - - try { - if (style == -1) - store(parse_config_file(is, desc), vm); - else - store(parse_command_line(argv.size(), argv.data(), desc, style), vm); - notify(vm); - } - catch (EXCEPTION& e) - { - //cerr << "Correct:\n\t" << e.what() << "\n"; - CHECK_EQUAL(test_description, e.what(), exception_msg); - return; - } - catch (std::exception& e) - { - // concatenate argv without boost::algorithm::join - string argv_txt; - for (unsigned ii = 0; ii < argc - 1; ++ii) - argv_txt += argv[ii] + string(" "); - if (argc) - argv_txt += argv[argc - 1]; - - BOOST_ERROR("\n<<" + test_description + - string(">>\n Unexpected exception type!\n Actual text =\"") + e.what() + - "\"\n argv =\"" + argv_txt + - "\"\n Expected text=\"" + exception_msg + "\"\n"); - return; - } - BOOST_ERROR(test_description + ": No exception thrown. "); -} - - - - -// -// test exception messages for all command line styles (unix/long/short/slash/config file) -// -// try each command line style in turn -const int unix_style = command_line_style::unix_style; -const int short_dash = command_line_style::allow_dash_for_short | command_line_style::allow_short | command_line_style::short_allow_adjacent | command_line_style::allow_sticky; -const int short_slash = command_line_style::allow_slash_for_short | command_line_style::allow_short | command_line_style::short_allow_adjacent; -const int long_dash = command_line_style::allow_long | command_line_style::long_allow_adjacent | command_line_style::allow_guessing; - - - -template -void test_exception_message(const vector>& argv, - options_description& desc, - const string& error_description, - const char* expected_message_template[5]) -{ - string expected_message; - - // unix - expected_message = expected_message_template[0]; - test_each_exception_message(error_description + " -- unix", - argv[0], desc, unix_style, expected_message); - - // long dash only - expected_message = expected_message_template[1]; - test_each_exception_message(error_description + " -- long_dash", - argv[1], desc, long_dash, expected_message); - - - // short dash only - expected_message = expected_message_template[2]; - test_each_exception_message(error_description + " -- short_dash", - argv[2], desc, short_dash, expected_message); - - // short slash only - expected_message = expected_message_template[3]; - test_each_exception_message(error_description + " -- short_slash", - argv[3], desc, short_slash, expected_message); - - // config file only - expected_message = expected_message_template[4]; - if (expected_message.length()) - { - istringstream istrm(argv[4][0]); - test_each_exception_message(error_description + " -- config_file", - argv[4], desc, -1, expected_message, istrm); - } - -} - -#define VEC_STR_PUSH_BACK(vec, c_array) \ - vec.push_back(vector(c_array, c_array + sizeof(c_array) / sizeof(char*))); - -//________________________________________________________________________________________ -// -// invalid_option_value -// -//________________________________________________________________________________________ -void test_invalid_option_value_exception_msg() -{ - options_description desc; - desc.add_options() - ("int_option,d", value< int >(), "An option taking an integer") - ; - - vector> argv; - const char* argv0[] = { "program", "-d", "A_STRING"} ; VEC_STR_PUSH_BACK(argv, argv0); - const char* argv1[] = { "program", "--int", "A_STRING"}; VEC_STR_PUSH_BACK(argv, argv1); - const char* argv2[] = { "program", "-d", "A_STRING"} ; VEC_STR_PUSH_BACK(argv, argv2); - const char* argv3[] = { "program", "/d", "A_STRING"} ; VEC_STR_PUSH_BACK(argv, argv3); - const char* argv4[] = { "int_option=A_STRING"} ; VEC_STR_PUSH_BACK(argv, argv4); - - const char* expected_msg[5] = { - "the argument ('A_STRING') for option '--int_option' is invalid", - "the argument ('A_STRING') for option '--int_option' is invalid", - "the argument ('A_STRING') for option '-d' is invalid", - "the argument ('A_STRING') for option '/d' is invalid", - "the argument ('A_STRING') for option 'int_option' is invalid" - }; - - - test_exception_message(argv, desc, "invalid_option_value", - expected_msg); - - -} - -//________________________________________________________________________________________ -// -// missing_value -// -//________________________________________________________________________________________ -void test_missing_value_exception_msg() -{ - options_description desc; - desc.add_options() - ("cfgfile,e", value(), "the config file") - ("output,o", value(), "the output file") - ; - vector> argv; - const char* argv0[] = { "program", "-e", "-e", "output.txt"} ; VEC_STR_PUSH_BACK(argv, argv0); - const char* argv1[] = { "program", "--cfgfile"} ; VEC_STR_PUSH_BACK(argv, argv1); - const char* argv2[] = { "program", "-e", "-e", "output.txt"} ; VEC_STR_PUSH_BACK(argv, argv2); - const char* argv3[] = { "program", "/e", "/e", "output.txt"} ; VEC_STR_PUSH_BACK(argv, argv3); - const char* argv4[] = { ""} ; VEC_STR_PUSH_BACK(argv, argv4); - - const char* expected_msg[5] = { - "the required argument for option '--cfgfile' is missing", - "the required argument for option '--cfgfile' is missing", - "the required argument for option '-e' is missing", - "", // Ignore probable bug in cmdline::finish_option - //"the required argument for option '/e' is missing", - "", - }; - test_exception_message(argv, desc, - "invalid_syntax::missing_parameter", - expected_msg); -} - -//________________________________________________________________________________________ -// -// ambiguous_option -// -//________________________________________________________________________________________ -void test_ambiguous_option_exception_msg() -{ - options_description desc; - desc.add_options() - ("cfgfile1,c", value(), "the config file") - ("cfgfile2,o", value(), "the config file") - ("good,g", "good option") - ("output,c", value(), "the output file") - ("output", value(), "the output file") - ; - - vector> argv; - const char* argv0[] = {"program", "-ggc", "file", "-o", "anotherfile"} ; VEC_STR_PUSH_BACK(argv, argv0); - const char* argv1[] = {"program", "--cfgfile", "file", "--cfgfile", "anotherfile"} ; VEC_STR_PUSH_BACK(argv, argv1); - const char* argv2[] = {"program", "-ggc", "file", "-o", "anotherfile"} ; VEC_STR_PUSH_BACK(argv, argv2); - const char* argv3[] = {"program", "/c", "file", "/o", "anotherfile"} ; VEC_STR_PUSH_BACK(argv, argv3); - const char* argv4[] = { "output=output.txt\n"} ; VEC_STR_PUSH_BACK(argv, argv4); - const char* expected_msg[5] = { - "option '-c' is ambiguous and matches '--cfgfile1', and '--output'", - "option '--cfgfile' is ambiguous and matches '--cfgfile1', and '--cfgfile2'", - "option '-c' is ambiguous", - "option '/c' is ambiguous", - "option 'output' is ambiguous and matches different versions of 'output'", - }; - test_exception_message(argv, desc, "ambiguous_option", - expected_msg); -} - -//________________________________________________________________________________________ -// -// multiple_occurrences -// -//________________________________________________________________________________________ -void test_multiple_occurrences_exception_msg() -{ - options_description desc; - desc.add_options() - ("cfgfile,c", value(), "the configfile") - ; - - vector> argv; - const char* argv0[] = {"program", "-c", "file", "-c", "anotherfile"} ; VEC_STR_PUSH_BACK(argv, argv0); - const char* argv1[] = {"program", "--cfgfi", "file", "--cfgfi", "anotherfile"} ; VEC_STR_PUSH_BACK(argv, argv1); - const char* argv2[] = {"program", "-c", "file", "-c", "anotherfile"} ; VEC_STR_PUSH_BACK(argv, argv2); - const char* argv3[] = {"program", "/c", "file", "/c", "anotherfile"} ; VEC_STR_PUSH_BACK(argv, argv3); - const char* argv4[] = { "cfgfile=output.txt\ncfgfile=output.txt\n"} ; VEC_STR_PUSH_BACK(argv, argv4); - const char* expected_msg[5] = { - "option '--cfgfile' cannot be specified more than once", - "option '--cfgfile' cannot be specified more than once", - "option '-c' cannot be specified more than once", - "option '/c' cannot be specified more than once", - "option 'cfgfile' cannot be specified more than once", - }; - test_exception_message(argv, desc, "multiple_occurrences", - expected_msg); -} - -//________________________________________________________________________________________ -// -// unknown_option -// -//________________________________________________________________________________________ -void test_unknown_option_exception_msg() -{ - options_description desc; - desc.add_options() - ("good,g", "good option") - ; - - vector> argv; - const char* argv0[] = {"program", "-ggc", "file"} ; VEC_STR_PUSH_BACK(argv, argv0); - const char* argv1[] = {"program", "--cfgfile", "file"} ; VEC_STR_PUSH_BACK(argv, argv1); - const char* argv2[] = {"program", "-ggc", "file"} ; VEC_STR_PUSH_BACK(argv, argv2); - const char* argv3[] = {"program", "/c", "file"} ; VEC_STR_PUSH_BACK(argv, argv3); - const char* argv4[] = { "cfgfile=output.txt\n"} ; VEC_STR_PUSH_BACK(argv, argv4); - const char* expected_msg[5] = { - "unrecognised option '-ggc'", - "unrecognised option '--cfgfile'", - "unrecognised option '-ggc'", - "unrecognised option '/c'", - "unrecognised option 'cfgfile'", - }; - test_exception_message(argv, desc, "unknown_option", expected_msg); -} - -//________________________________________________________________________________________ -// -// validation_error::invalid_bool_value -// -//________________________________________________________________________________________ -void test_invalid_bool_value_exception_msg() -{ - options_description desc; - desc.add_options() - ("bool_option,b", value< bool>(), "bool_option") - ; - - - vector> argv; - const char* argv0[] = {"program", "-b", "file"} ; VEC_STR_PUSH_BACK(argv, argv0); - const char* argv1[] = {"program", "--bool_optio", "file"} ; VEC_STR_PUSH_BACK(argv, argv1); - const char* argv2[] = {"program", "-b", "file"} ; VEC_STR_PUSH_BACK(argv, argv2); - const char* argv3[] = {"program", "/b", "file"} ; VEC_STR_PUSH_BACK(argv, argv3); - const char* argv4[] = { "bool_option=output.txt\n"} ; VEC_STR_PUSH_BACK(argv, argv4); - const char* expected_msg[5] = { - "the argument ('file') for option '--bool_option' is invalid. Valid choices are 'on|off', 'yes|no', '1|0' and 'true|false'", - "the argument ('file') for option '--bool_option' is invalid. Valid choices are 'on|off', 'yes|no', '1|0' and 'true|false'", - "the argument ('file') for option '-b' is invalid. Valid choices are 'on|off', 'yes|no', '1|0' and 'true|false'", - "the argument ('file') for option '/b' is invalid. Valid choices are 'on|off', 'yes|no', '1|0' and 'true|false'", - "the argument ('output.txt') for option 'bool_option' is invalid. Valid choices are 'on|off', 'yes|no', '1|0' and 'true|false'", - }; - test_exception_message(argv, - desc, - "validation_error::invalid_bool_value", - expected_msg); -} - - - - -//________________________________________________________________________________________ -// -// validation_error::multiple_values_not_allowed -// -//________________________________________________________________________________________ -// -// Strange exception: sole purpose seems to be catching multitoken() associated with a scalar -// validation_error::multiple_values_not_allowed seems thus to be a programmer error -// -// -void test_multiple_values_not_allowed_exception_msg() -{ - options_description desc; - desc.add_options() - ("cfgfile,c", value()->multitoken(), "the config file") - ("good,g", "good option") - ("output,o", value(), "the output file") - ; - - vector> argv; - const char* argv0[] = { "program", "-c", "file", "c", "-o", "fritz", "hugo" } ; VEC_STR_PUSH_BACK(argv, argv0); - const char* argv1[] = { "program", "--cfgfil", "file", "c", "--outpu", "fritz", "hugo" } ; VEC_STR_PUSH_BACK(argv, argv1); - const char* argv2[] = { "program", "-c", "file", "c", "-o", "fritz", "hugo"} ; VEC_STR_PUSH_BACK(argv, argv2); - const char* argv3[] = { "program", "/c", "file", "c", "/o", "fritz", "hugo"} ; VEC_STR_PUSH_BACK(argv, argv3); - const char* argv4[] = { "" } ; VEC_STR_PUSH_BACK(argv, argv4); - const char* expected_msg[5] = { - "option '--cfgfile' only takes a single argument", - "option '--cfgfile' only takes a single argument", - "option '-c' only takes a single argument", - "option '/c' only takes a single argument", - "", - }; - test_exception_message(argv, - desc, - "validation_error::multiple_values_not_allowed", - expected_msg); -} - -//________________________________________________________________________________________ -// -// validation_error::at_least_one_value_required -// -//________________________________________________________________________________________ -// -// Strange exception: sole purpose seems to be catching zero_tokens() associated with a scalar -// validation_error::multiple_values_not_allowed seems thus to be a programmer error -// -// -void test_at_least_one_value_required_exception_msg() -{ - - - options_description desc; - desc.add_options() - ("cfgfile,c", value()->zero_tokens(), "the config file") - ("other,o", value(), "other") - ; - - vector> argv; - const char* argv0[] = { "program", "-c" } ; VEC_STR_PUSH_BACK(argv, argv0); - const char* argv1[] = { "program", "--cfg", "--o", "name" } ; VEC_STR_PUSH_BACK(argv, argv1); - const char* argv2[] = { "program", "-c" , "-o" , "name" } ; VEC_STR_PUSH_BACK(argv, argv2); - const char* argv3[] = { "program", "/c" } ; VEC_STR_PUSH_BACK(argv, argv3); - const char* argv4[] = { "" } ; VEC_STR_PUSH_BACK(argv, argv4); - const char* expected_msg[5] = { - "option '--cfgfile' requires at least one argument", - "option '--cfgfile' requires at least one argument", - "option '-c' requires at least one argument", - "option '/c' requires at least one argument", - "", - }; - test_exception_message(argv, - desc, - "validation_error::at_least_one_value_required", - expected_msg); -} - - -//________________________________________________________________________________________ -// -// required_option -// -//________________________________________________________________________________________ -void test_required_option_exception_msg() -{ - options_description desc; - desc.add_options() - ("cfgfile,c", value()->required(), "the config file") - ("good,g", "good option") - ("output,o", value()->required(), "the output file") - ; - - vector> argv; - const char* argv0[] = { "program", "-g" } ; VEC_STR_PUSH_BACK(argv, argv0); - const char* argv1[] = { "program", "--g" } ; VEC_STR_PUSH_BACK(argv, argv1); - const char* argv2[] = { "program", "-g"} ; VEC_STR_PUSH_BACK(argv, argv2); - const char* argv3[] = { "program", "/g"} ; VEC_STR_PUSH_BACK(argv, argv3); - const char* argv4[] = { "" } ; VEC_STR_PUSH_BACK(argv, argv4); - const char* expected_msg[5] = { - "the option '--cfgfile' is required but missing", - "the option '--cfgfile' is required but missing", - "the option '-c' is required but missing", - "the option '/c' is required but missing", - "the option 'cfgfile' is required but missing", - }; - test_exception_message(argv, - desc, - "required_option", - expected_msg); -} - - - - - - - - - - - - - - - - -/** - * Check if this is the expected exception with the right message is being thrown inside - * func -*/ -template -void test_exception(const string& test_name, const string& exception_txt, FUNC func) -{ - - try { - options_description desc; - variables_map vm; - func(desc, vm); - } - catch (EXCEPTION& e) - { - CHECK_EQUAL(test_name, e.what(), exception_txt); - return; - } - catch (std::exception& e) - { - BOOST_ERROR(string(test_name + ":\nUnexpected exception. ") + e.what() + - "\nExpected text:\n" + exception_txt + "\n\n"); - return; - } - BOOST_ERROR(test_name + ": No exception thrown. "); -} - - - -//________________________________________________________________________________________ -// -// check_reading_file -// -//________________________________________________________________________________________ -void check_reading_file(options_description& desc, variables_map& vm) -{ - desc.add_options() - ("output,o", value(), "the output file"); - - const char* file_name = "no_such_file"; - store(parse_config_file(file_name, desc, true), vm); - -} - - -//________________________________________________________________________________________ -// -// config_file_wildcard -// -//________________________________________________________________________________________ -void config_file_wildcard(options_description& desc, variables_map& vm) -{ - desc.add_options() - ("outpu*", value(), "the output file1") - ("outp*", value(), "the output file2") - ; - istringstream is("output1=whichone\noutput2=whichone\n"); - store(parse_config_file(is, desc), vm); -} - -//________________________________________________________________________________________ -// -// invalid_syntax::unrecognized_line -// -//________________________________________________________________________________________ -void unrecognized_line(options_description& desc, variables_map& vm) -{ - istringstream is("funny wierd line\n"); - store(parse_config_file(is, desc), vm); -} - -//________________________________________________________________________________________ -// -// abbreviated_options_in_config_file -// -//________________________________________________________________________________________ -void abbreviated_options_in_config_file(options_description& desc, variables_map& vm) -{ - desc.add_options()(",o", value(), "the output file"); - istringstream is("o=output.txt\n"); - store(parse_config_file(is, desc), vm); -} - - -//________________________________________________________________________________________ -// -// too_many_positional_options -// -//________________________________________________________________________________________ -void too_many_positional_options(options_description& desc, variables_map& vm) -{ - const char* argv[] = {"program", "1", "2", "3"}; - positional_options_description positional_args; - positional_args.add("two_positional_arguments", 2); - store(command_line_parser(4, argv).options(desc).positional(positional_args).run(), vm); -} - - -//________________________________________________________________________________________ -// -// invalid_command_line_style -// -//________________________________________________________________________________________ - -void test_invalid_command_line_style_exception_msg() -{ - string test_name = "invalid_command_line_style"; - using namespace command_line_style; - options_description desc; - desc.add_options()("output,o", value(), "the output file"); - - vector invalid_styles; - invalid_styles.push_back(allow_short | short_allow_adjacent); - invalid_styles.push_back(allow_short | allow_dash_for_short); - invalid_styles.push_back(allow_long); - vector invalid_diagnostics; - invalid_diagnostics.push_back("boost::program_options misconfiguration: choose one " - "or other of command_line_style::allow_slash_for_short " - "(slashes) or command_line_style::allow_dash_for_short " - "(dashes) for short options."); - invalid_diagnostics.push_back("boost::program_options misconfiguration: choose one " - "or other of 'command_line_style::short_allow_next' " - "(whitespace separated arguments) or " - "command_line_style::short_allow_adjacent ('=' " - "separated arguments) for short options."); - invalid_diagnostics.push_back("boost::program_options misconfiguration: choose one " - "or other of 'command_line_style::long_allow_next' " - "(whitespace separated arguments) or " - "command_line_style::long_allow_adjacent ('=' " - "separated arguments) for long options."); - - - const char* argv[] = {"program"}; - variables_map vm; - for (unsigned ii = 0; ii < 3; ++ii) - { - bool exception_thrown = false; - try - { - store(parse_command_line(1, argv, desc, invalid_styles[ii]), vm); - } - catch (invalid_command_line_style& e) - { - string error_msg("arguments are not allowed for unabbreviated option names"); - CHECK_EQUAL(test_name, e.what(), invalid_diagnostics[ii]); - exception_thrown = true; - } - catch (std::exception& e) - { - BOOST_ERROR(string(test_name + ":\nUnexpected exception. ") + e.what() + - "\nExpected text:\n" + invalid_diagnostics[ii] + "\n"); - exception_thrown = true; - } - if (!exception_thrown) - { - BOOST_ERROR(test_name << ": No exception thrown. "); - } - } -} - - - -int main(int /*ac*/, char** /*av*/) -{ - test_ambiguous_option_exception_msg(); - test_unknown_option_exception_msg(); - test_multiple_occurrences_exception_msg(); - test_missing_value_exception_msg(); - test_invalid_option_value_exception_msg(); - test_invalid_bool_value_exception_msg(); - test_multiple_values_not_allowed_exception_msg(); - test_required_option_exception_msg(); - test_at_least_one_value_required_exception_msg(); - - string test_name; - string expected_message; - - - // check_reading_file - test_name = "check_reading_file"; - expected_message = "can not read options configuration file 'no_such_file'"; - test_exception(test_name, expected_message, check_reading_file); - - // config_file_wildcard - test_name = "config_file_wildcard"; - expected_message = "options 'outpu*' and 'outp*' will both match the same arguments from the configuration file"; - test_exception(test_name, expected_message, config_file_wildcard); - - // unrecognized_line - test_name = "unrecognized_line"; - expected_message = "the options configuration file contains an invalid line 'funny wierd line'"; - test_exception(test_name, expected_message, unrecognized_line); - - - // abbreviated_options_in_config_file - test_name = "abbreviated_options_in_config_file"; - expected_message = "abbreviated option names are not permitted in options configuration files"; - test_exception(test_name, expected_message, abbreviated_options_in_config_file); - - test_name = "too_many_positional_options"; - expected_message = "too many positional arguments have been specified on the command line"; - test_exception( - test_name, expected_message, too_many_positional_options); - - test_invalid_command_line_style_exception_msg(); - - - return 0; -} - - - -// Copyright Sascha Ochsenknecht 2009. -// 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) - - -#include -#include -#include -#include -using namespace boost::program_options; - -#include -#include -#include -#include -using namespace std; - -#include "minitest.hpp" - - - -// -// like BOOST_CHECK_EQUAL but with more descriptive error message -// -#define CHECK_EQUAL(description, a, b) if (a != b) {std::cerr << "\n\nError:\n<<" << \ - description << ">>\n Expected text=\"" << b << "\"\n Actual text =\"" << a << "\"\n\n"; assert(a == b);} - - -// Uncomment for Debugging, removes asserts so we can see more failures! -//#define BOOST_ERROR(description) std::cerr << description; std::cerr << "\n"; - - -//8888888888888888888888888888888888888888888888888888888888888888888888888888888888888888 -// -// Uncomment to print out the complete set of diagnostic messages for the different test cases -/* -#define CHECK_EQUAL(description, a, b) if (a != b) {std::cerr << "\n\nError: " << \ - description << "\n Expecting\n" << b << "\n Found\n" << a << "\n\n"; } \ - else {std::cout << description<< "\t" << b << "\n";} -*/ - -//8888888888888888888888888888888888888888888888888888888888888888888888888888888888888888 - - -// -// test exception for each specified command line style, e.g. short dash or config file -// -template -void test_each_exception_message(const string& test_description, const vector& argv, options_description& desc, int style, string exception_msg, istream& is = cin) -{ - if (exception_msg.length() == 0) - return; - variables_map vm; - unsigned argc = argv.size(); - - - try { - if (style == -1) - store(parse_config_file(is, desc), vm); - else - store(parse_command_line(argv.size(), argv.data(), desc, style), vm); - notify(vm); - } - catch (EXCEPTION& e) - { - //cerr << "Correct:\n\t" << e.what() << "\n"; - CHECK_EQUAL(test_description, e.what(), exception_msg); - return; - } - catch (std::exception& e) - { - // concatenate argv without boost::algorithm::join - string argv_txt; - for (unsigned ii = 0; ii < argc - 1; ++ii) - argv_txt += argv[ii] + string(" "); - if (argc) - argv_txt += argv[argc - 1]; - - BOOST_ERROR("\n<<" + test_description + - string(">>\n Unexpected exception type!\n Actual text =\"") + e.what() + - "\"\n argv =\"" + argv_txt + - "\"\n Expected text=\"" + exception_msg + "\"\n"); - return; - } - BOOST_ERROR(test_description + ": No exception thrown. "); -} - - - - -// -// test exception messages for all command line styles (unix/long/short/slash/config file) -// -// try each command line style in turn -const int unix_style = command_line_style::unix_style; -const int short_dash = command_line_style::allow_dash_for_short | command_line_style::allow_short | command_line_style::short_allow_adjacent | command_line_style::allow_sticky; -const int short_slash = command_line_style::allow_slash_for_short | command_line_style::allow_short | command_line_style::short_allow_adjacent; -const int long_dash = command_line_style::allow_long | command_line_style::long_allow_adjacent | command_line_style::allow_guessing; - - - -template -void test_exception_message(const vector>& argv, - options_description& desc, - const string& error_description, - const char* expected_message_template[5]) -{ - string expected_message; - - // unix - expected_message = expected_message_template[0]; - test_each_exception_message(error_description + " -- unix", - argv[0], desc, unix_style, expected_message); - - // long dash only - expected_message = expected_message_template[1]; - test_each_exception_message(error_description + " -- long_dash", - argv[1], desc, long_dash, expected_message); - - - // short dash only - expected_message = expected_message_template[2]; - test_each_exception_message(error_description + " -- short_dash", - argv[2], desc, short_dash, expected_message); - - // short slash only - expected_message = expected_message_template[3]; - test_each_exception_message(error_description + " -- short_slash", - argv[3], desc, short_slash, expected_message); - - // config file only - expected_message = expected_message_template[4]; - if (expected_message.length()) - { - istringstream istrm(argv[4][0]); - test_each_exception_message(error_description + " -- config_file", - argv[4], desc, -1, expected_message, istrm); - } - -} - -#define VEC_STR_PUSH_BACK(vec, c_array) \ - vec.push_back(vector(c_array, c_array + sizeof(c_array) / sizeof(char*))); - -//________________________________________________________________________________________ -// -// invalid_option_value -// -//________________________________________________________________________________________ -void test_invalid_option_value_exception_msg() -{ - options_description desc; - desc.add_options() - ("int_option,d", value< int >(), "An option taking an integer") - ; - - vector> argv; - const char* argv0[] = { "program", "-d", "A_STRING"} ; VEC_STR_PUSH_BACK(argv, argv0); - const char* argv1[] = { "program", "--int", "A_STRING"}; VEC_STR_PUSH_BACK(argv, argv1); - const char* argv2[] = { "program", "-d", "A_STRING"} ; VEC_STR_PUSH_BACK(argv, argv2); - const char* argv3[] = { "program", "/d", "A_STRING"} ; VEC_STR_PUSH_BACK(argv, argv3); - const char* argv4[] = { "int_option=A_STRING"} ; VEC_STR_PUSH_BACK(argv, argv4); - - const char* expected_msg[5] = { - "the argument ('A_STRING') for option '--int_option' is invalid", - "the argument ('A_STRING') for option '--int_option' is invalid", - "the argument ('A_STRING') for option '-d' is invalid", - "the argument ('A_STRING') for option '/d' is invalid", - "the argument ('A_STRING') for option 'int_option' is invalid" - }; - - - test_exception_message(argv, desc, "invalid_option_value", - expected_msg); - - -} - -//________________________________________________________________________________________ -// -// missing_value -// -//________________________________________________________________________________________ -void test_missing_value_exception_msg() -{ - options_description desc; - desc.add_options() - ("cfgfile,e", value(), "the config file") - ("output,o", value(), "the output file") - ; - vector> argv; - const char* argv0[] = { "program", "-e", "-e", "output.txt"} ; VEC_STR_PUSH_BACK(argv, argv0); - const char* argv1[] = { "program", "--cfgfile"} ; VEC_STR_PUSH_BACK(argv, argv1); - const char* argv2[] = { "program", "-e", "-e", "output.txt"} ; VEC_STR_PUSH_BACK(argv, argv2); - const char* argv3[] = { "program", "/e", "/e", "output.txt"} ; VEC_STR_PUSH_BACK(argv, argv3); - const char* argv4[] = { ""} ; VEC_STR_PUSH_BACK(argv, argv4); - - const char* expected_msg[5] = { - "the required argument for option '--cfgfile' is missing", - "the required argument for option '--cfgfile' is missing", - "the required argument for option '-e' is missing", - "", // Ignore probable bug in cmdline::finish_option - //"the required argument for option '/e' is missing", - "", - }; - test_exception_message(argv, desc, - "invalid_syntax::missing_parameter", - expected_msg); -} - -//________________________________________________________________________________________ -// -// ambiguous_option -// -//________________________________________________________________________________________ -void test_ambiguous_option_exception_msg() -{ - options_description desc; - desc.add_options() - ("cfgfile1,c", value(), "the config file") - ("cfgfile2,o", value(), "the config file") - ("good,g", "good option") - ("output,c", value(), "the output file") - ("output", value(), "the output file") - ; - - vector> argv; - const char* argv0[] = {"program", "-ggc", "file", "-o", "anotherfile"} ; VEC_STR_PUSH_BACK(argv, argv0); - const char* argv1[] = {"program", "--cfgfile", "file", "--cfgfile", "anotherfile"} ; VEC_STR_PUSH_BACK(argv, argv1); - const char* argv2[] = {"program", "-ggc", "file", "-o", "anotherfile"} ; VEC_STR_PUSH_BACK(argv, argv2); - const char* argv3[] = {"program", "/c", "file", "/o", "anotherfile"} ; VEC_STR_PUSH_BACK(argv, argv3); - const char* argv4[] = { "output=output.txt\n"} ; VEC_STR_PUSH_BACK(argv, argv4); - const char* expected_msg[5] = { - "option '-c' is ambiguous and matches '--cfgfile1', and '--output'", - "option '--cfgfile' is ambiguous and matches '--cfgfile1', and '--cfgfile2'", - "option '-c' is ambiguous", - "option '/c' is ambiguous", - "option 'output' is ambiguous and matches different versions of 'output'", - }; - test_exception_message(argv, desc, "ambiguous_option", - expected_msg); -} - -//________________________________________________________________________________________ -// -// multiple_occurrences -// -//________________________________________________________________________________________ -void test_multiple_occurrences_exception_msg() -{ - options_description desc; - desc.add_options() - ("cfgfile,c", value(), "the configfile") - ; - - vector> argv; - const char* argv0[] = {"program", "-c", "file", "-c", "anotherfile"} ; VEC_STR_PUSH_BACK(argv, argv0); - const char* argv1[] = {"program", "--cfgfi", "file", "--cfgfi", "anotherfile"} ; VEC_STR_PUSH_BACK(argv, argv1); - const char* argv2[] = {"program", "-c", "file", "-c", "anotherfile"} ; VEC_STR_PUSH_BACK(argv, argv2); - const char* argv3[] = {"program", "/c", "file", "/c", "anotherfile"} ; VEC_STR_PUSH_BACK(argv, argv3); - const char* argv4[] = { "cfgfile=output.txt\ncfgfile=output.txt\n"} ; VEC_STR_PUSH_BACK(argv, argv4); - const char* expected_msg[5] = { - "option '--cfgfile' cannot be specified more than once", - "option '--cfgfile' cannot be specified more than once", - "option '-c' cannot be specified more than once", - "option '/c' cannot be specified more than once", - "option 'cfgfile' cannot be specified more than once", - }; - test_exception_message(argv, desc, "multiple_occurrences", - expected_msg); -} - -//________________________________________________________________________________________ -// -// unknown_option -// -//________________________________________________________________________________________ -void test_unknown_option_exception_msg() -{ - options_description desc; - desc.add_options() - ("good,g", "good option") - ; - - vector> argv; - const char* argv0[] = {"program", "-ggc", "file"} ; VEC_STR_PUSH_BACK(argv, argv0); - const char* argv1[] = {"program", "--cfgfile", "file"} ; VEC_STR_PUSH_BACK(argv, argv1); - const char* argv2[] = {"program", "-ggc", "file"} ; VEC_STR_PUSH_BACK(argv, argv2); - const char* argv3[] = {"program", "/c", "file"} ; VEC_STR_PUSH_BACK(argv, argv3); - const char* argv4[] = { "cfgfile=output.txt\n"} ; VEC_STR_PUSH_BACK(argv, argv4); - const char* expected_msg[5] = { - "unrecognised option '-ggc'", - "unrecognised option '--cfgfile'", - "unrecognised option '-ggc'", - "unrecognised option '/c'", - "unrecognised option 'cfgfile'", - }; - test_exception_message(argv, desc, "unknown_option", expected_msg); -} - -//________________________________________________________________________________________ -// -// validation_error::invalid_bool_value -// -//________________________________________________________________________________________ -void test_invalid_bool_value_exception_msg() -{ - options_description desc; - desc.add_options() - ("bool_option,b", value< bool>(), "bool_option") - ; - - - vector> argv; - const char* argv0[] = {"program", "-b", "file"} ; VEC_STR_PUSH_BACK(argv, argv0); - const char* argv1[] = {"program", "--bool_optio", "file"} ; VEC_STR_PUSH_BACK(argv, argv1); - const char* argv2[] = {"program", "-b", "file"} ; VEC_STR_PUSH_BACK(argv, argv2); - const char* argv3[] = {"program", "/b", "file"} ; VEC_STR_PUSH_BACK(argv, argv3); - const char* argv4[] = { "bool_option=output.txt\n"} ; VEC_STR_PUSH_BACK(argv, argv4); - const char* expected_msg[5] = { - "the argument ('file') for option '--bool_option' is invalid. Valid choices are 'on|off', 'yes|no', '1|0' and 'true|false'", - "the argument ('file') for option '--bool_option' is invalid. Valid choices are 'on|off', 'yes|no', '1|0' and 'true|false'", - "the argument ('file') for option '-b' is invalid. Valid choices are 'on|off', 'yes|no', '1|0' and 'true|false'", - "the argument ('file') for option '/b' is invalid. Valid choices are 'on|off', 'yes|no', '1|0' and 'true|false'", - "the argument ('output.txt') for option 'bool_option' is invalid. Valid choices are 'on|off', 'yes|no', '1|0' and 'true|false'", - }; - test_exception_message(argv, - desc, - "validation_error::invalid_bool_value", - expected_msg); -} - - - - -//________________________________________________________________________________________ -// -// validation_error::multiple_values_not_allowed -// -//________________________________________________________________________________________ -// -// Strange exception: sole purpose seems to be catching multitoken() associated with a scalar -// validation_error::multiple_values_not_allowed seems thus to be a programmer error -// -// -void test_multiple_values_not_allowed_exception_msg() -{ - options_description desc; - desc.add_options() - ("cfgfile,c", value()->multitoken(), "the config file") - ("good,g", "good option") - ("output,o", value(), "the output file") - ; - - vector> argv; - const char* argv0[] = { "program", "-c", "file", "c", "-o", "fritz", "hugo" } ; VEC_STR_PUSH_BACK(argv, argv0); - const char* argv1[] = { "program", "--cfgfil", "file", "c", "--outpu", "fritz", "hugo" } ; VEC_STR_PUSH_BACK(argv, argv1); - const char* argv2[] = { "program", "-c", "file", "c", "-o", "fritz", "hugo"} ; VEC_STR_PUSH_BACK(argv, argv2); - const char* argv3[] = { "program", "/c", "file", "c", "/o", "fritz", "hugo"} ; VEC_STR_PUSH_BACK(argv, argv3); - const char* argv4[] = { "" } ; VEC_STR_PUSH_BACK(argv, argv4); - const char* expected_msg[5] = { - "option '--cfgfile' only takes a single argument", - "option '--cfgfile' only takes a single argument", - "option '-c' only takes a single argument", - "option '/c' only takes a single argument", - "", - }; - test_exception_message(argv, - desc, - "validation_error::multiple_values_not_allowed", - expected_msg); -} - -//________________________________________________________________________________________ -// -// validation_error::at_least_one_value_required -// -//________________________________________________________________________________________ -// -// Strange exception: sole purpose seems to be catching zero_tokens() associated with a scalar -// validation_error::multiple_values_not_allowed seems thus to be a programmer error -// -// -void test_at_least_one_value_required_exception_msg() -{ - - - options_description desc; - desc.add_options() - ("cfgfile,c", value()->zero_tokens(), "the config file") - ("other,o", value(), "other") - ; - - vector> argv; - const char* argv0[] = { "program", "-c" } ; VEC_STR_PUSH_BACK(argv, argv0); - const char* argv1[] = { "program", "--cfg", "--o", "name" } ; VEC_STR_PUSH_BACK(argv, argv1); - const char* argv2[] = { "program", "-c" , "-o" , "name" } ; VEC_STR_PUSH_BACK(argv, argv2); - const char* argv3[] = { "program", "/c" } ; VEC_STR_PUSH_BACK(argv, argv3); - const char* argv4[] = { "" } ; VEC_STR_PUSH_BACK(argv, argv4); - const char* expected_msg[5] = { - "option '--cfgfile' requires at least one argument", - "option '--cfgfile' requires at least one argument", - "option '-c' requires at least one argument", - "option '/c' requires at least one argument", - "", - }; - test_exception_message(argv, - desc, - "validation_error::at_least_one_value_required", - expected_msg); -} - - -//________________________________________________________________________________________ -// -// required_option -// -//________________________________________________________________________________________ -void test_required_option_exception_msg() -{ - options_description desc; - desc.add_options() - ("cfgfile,c", value()->required(), "the config file") - ("good,g", "good option") - ("output,o", value()->required(), "the output file") - ; - - vector> argv; - const char* argv0[] = { "program", "-g" } ; VEC_STR_PUSH_BACK(argv, argv0); - const char* argv1[] = { "program", "--g" } ; VEC_STR_PUSH_BACK(argv, argv1); - const char* argv2[] = { "program", "-g"} ; VEC_STR_PUSH_BACK(argv, argv2); - const char* argv3[] = { "program", "/g"} ; VEC_STR_PUSH_BACK(argv, argv3); - const char* argv4[] = { "" } ; VEC_STR_PUSH_BACK(argv, argv4); - const char* expected_msg[5] = { - "the option '--cfgfile' is required but missing", - "the option '--cfgfile' is required but missing", - "the option '-c' is required but missing", - "the option '/c' is required but missing", - "the option 'cfgfile' is required but missing", - }; - test_exception_message(argv, - desc, - "required_option", - expected_msg); -} - - - - - - - - - - - - - - - - -/** - * Check if this is the expected exception with the right message is being thrown inside - * func -*/ -template -void test_exception(const string& test_name, const string& exception_txt, FUNC func) -{ - - try { - options_description desc; - variables_map vm; - func(desc, vm); - } - catch (EXCEPTION& e) - { - CHECK_EQUAL(test_name, e.what(), exception_txt); - return; - } - catch (std::exception& e) - { - BOOST_ERROR(string(test_name + ":\nUnexpected exception. ") + e.what() + - "\nExpected text:\n" + exception_txt + "\n\n"); - return; - } - BOOST_ERROR(test_name + ": No exception thrown. "); -} - - - -//________________________________________________________________________________________ -// -// check_reading_file -// -//________________________________________________________________________________________ -void check_reading_file(options_description& desc, variables_map& vm) -{ - desc.add_options() - ("output,o", value(), "the output file"); - - const char* file_name = "no_such_file"; - store(parse_config_file(file_name, desc, true), vm); - -} - - -//________________________________________________________________________________________ -// -// config_file_wildcard -// -//________________________________________________________________________________________ -void config_file_wildcard(options_description& desc, variables_map& vm) -{ - desc.add_options() - ("outpu*", value(), "the output file1") - ("outp*", value(), "the output file2") - ; - istringstream is("output1=whichone\noutput2=whichone\n"); - store(parse_config_file(is, desc), vm); -} - -//________________________________________________________________________________________ -// -// invalid_syntax::unrecognized_line -// -//________________________________________________________________________________________ -void unrecognized_line(options_description& desc, variables_map& vm) -{ - istringstream is("funny wierd line\n"); - store(parse_config_file(is, desc), vm); -} - -//________________________________________________________________________________________ -// -// abbreviated_options_in_config_file -// -//________________________________________________________________________________________ -void abbreviated_options_in_config_file(options_description& desc, variables_map& vm) -{ - desc.add_options()(",o", value(), "the output file"); - istringstream is("o=output.txt\n"); - store(parse_config_file(is, desc), vm); -} - - -//________________________________________________________________________________________ -// -// too_many_positional_options -// -//________________________________________________________________________________________ -void too_many_positional_options(options_description& desc, variables_map& vm) -{ - const char* argv[] = {"program", "1", "2", "3"}; - positional_options_description positional_args; - positional_args.add("two_positional_arguments", 2); - store(command_line_parser(4, argv).options(desc).positional(positional_args).run(), vm); -} - - -//________________________________________________________________________________________ -// -// invalid_command_line_style -// -//________________________________________________________________________________________ - -void test_invalid_command_line_style_exception_msg() -{ - string test_name = "invalid_command_line_style"; - using namespace command_line_style; - options_description desc; - desc.add_options()("output,o", value(), "the output file"); - - vector invalid_styles; - invalid_styles.push_back(allow_short | short_allow_adjacent); - invalid_styles.push_back(allow_short | allow_dash_for_short); - invalid_styles.push_back(allow_long); - vector invalid_diagnostics; - invalid_diagnostics.push_back("boost::program_options misconfiguration: choose one " - "or other of command_line_style::allow_slash_for_short " - "(slashes) or command_line_style::allow_dash_for_short " - "(dashes) for short options."); - invalid_diagnostics.push_back("boost::program_options misconfiguration: choose one " - "or other of 'command_line_style::short_allow_next' " - "(whitespace separated arguments) or " - "command_line_style::short_allow_adjacent ('=' " - "separated arguments) for short options."); - invalid_diagnostics.push_back("boost::program_options misconfiguration: choose one " - "or other of 'command_line_style::long_allow_next' " - "(whitespace separated arguments) or " - "command_line_style::long_allow_adjacent ('=' " - "separated arguments) for long options."); - - - const char* argv[] = {"program"}; - variables_map vm; - for (unsigned ii = 0; ii < 3; ++ii) - { - bool exception_thrown = false; - try - { - store(parse_command_line(1, argv, desc, invalid_styles[ii]), vm); - } - catch (invalid_command_line_style& e) - { - string error_msg("arguments are not allowed for unabbreviated option names"); - CHECK_EQUAL(test_name, e.what(), invalid_diagnostics[ii]); - exception_thrown = true; - } - catch (std::exception& e) - { - BOOST_ERROR(string(test_name + ":\nUnexpected exception. ") + e.what() + - "\nExpected text:\n" + invalid_diagnostics[ii] + "\n"); - exception_thrown = true; - } - if (!exception_thrown) - { - BOOST_ERROR(test_name << ": No exception thrown. "); - } - } -} - - - -int main(int /*ac*/, char** /*av*/) -{ - test_ambiguous_option_exception_msg(); - test_unknown_option_exception_msg(); - test_multiple_occurrences_exception_msg(); - test_missing_value_exception_msg(); - test_invalid_option_value_exception_msg(); - test_invalid_bool_value_exception_msg(); - test_multiple_values_not_allowed_exception_msg(); - test_required_option_exception_msg(); - test_at_least_one_value_required_exception_msg(); - - string test_name; - string expected_message; - - - // check_reading_file - test_name = "check_reading_file"; - expected_message = "can not read options configuration file 'no_such_file'"; - test_exception(test_name, expected_message, check_reading_file); - - // config_file_wildcard - test_name = "config_file_wildcard"; - expected_message = "options 'outpu*' and 'outp*' will both match the same arguments from the configuration file"; - test_exception(test_name, expected_message, config_file_wildcard); - - // unrecognized_line - test_name = "unrecognized_line"; - expected_message = "the options configuration file contains an invalid line 'funny wierd line'"; - test_exception(test_name, expected_message, unrecognized_line); - - - // abbreviated_options_in_config_file - test_name = "abbreviated_options_in_config_file"; - expected_message = "abbreviated option names are not permitted in options configuration files"; - test_exception(test_name, expected_message, abbreviated_options_in_config_file); - - test_name = "too_many_positional_options"; - expected_message = "too many positional arguments have been specified on the command line"; - test_exception( - test_name, expected_message, too_many_positional_options); - - test_invalid_command_line_style_exception_msg(); - - - return 0; -} - - - -// Copyright Sascha Ochsenknecht 2009. -// 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) - - -#include -#include -#include -#include -using namespace boost::program_options; - -#include -#include -#include -#include -using namespace std; - -#include "minitest.hpp" - - - -// -// like BOOST_CHECK_EQUAL but with more descriptive error message -// -#define CHECK_EQUAL(description, a, b) if (a != b) {std::cerr << "\n\nError:\n<<" << \ - description << ">>\n Expected text=\"" << b << "\"\n Actual text =\"" << a << "\"\n\n"; assert(a == b);} - - -// Uncomment for Debugging, removes asserts so we can see more failures! -//#define BOOST_ERROR(description) std::cerr << description; std::cerr << "\n"; - - -//8888888888888888888888888888888888888888888888888888888888888888888888888888888888888888 -// -// Uncomment to print out the complete set of diagnostic messages for the different test cases -// -//#define CHECK_EQUAL(description, a, b) if (a != b) {std::cerr << "\n\nError: " << \ -// description << "\n Expecting\n" << b << "\n Found\n" << a << "\n\n"; } \ -// else {std::cout << description<< "\t" << b << "\n";} - -//8888888888888888888888888888888888888888888888888888888888888888888888888888888888888888 - - -// -// test exception for each specified command line style, e.g. short dash or config file -// -template -void test_each_exception_message(const string& test_description, const vector& argv, options_description& desc, int style, string exception_msg, istream& is = cin) -{ - if (exception_msg.length() == 0) - return; - variables_map vm; - unsigned argc = argv.size(); - - - try { - if (style == -1) - store(parse_config_file(is, desc), vm); - else - store(parse_command_line(argv.size(), argv.data(), desc, style), vm); - notify(vm); - } - catch (EXCEPTION& e) - { - //cerr << "Correct:\n\t" << e.what() << "\n"; - CHECK_EQUAL(test_description, e.what(), exception_msg); - return; - } - catch (std::exception& e) - { - // concatenate argv without boost::algorithm::join - string argv_txt; - for (unsigned ii = 0; ii < argc - 1; ++ii) - argv_txt += argv[ii] + string(" "); - if (argc) - argv_txt += argv[argc - 1]; - - BOOST_ERROR("\n<<" + test_description + - string(">>\n Unexpected exception type!\n Actual text =\"") + e.what() + - "\"\n argv =\"" + argv_txt + - "\"\n Expected text=\"" + exception_msg + "\"\n"); - return; - } - BOOST_ERROR(test_description + ": No exception thrown. "); -} - - - - -// -// test exception messages for all command line styles (unix/long/short/slash/config file) -// -// try each command line style in turn -const int unix_style = command_line_style::unix_style; -const int short_dash = command_line_style::allow_dash_for_short | command_line_style::allow_short | command_line_style::short_allow_adjacent | command_line_style::allow_sticky; -const int short_slash = command_line_style::allow_slash_for_short | command_line_style::allow_short | command_line_style::short_allow_adjacent; -const int long_dash = command_line_style::allow_long | command_line_style::long_allow_adjacent | command_line_style::allow_guessing; - - - -template -void test_exception_message(const vector>& argv, - options_description& desc, - const string& error_description, - const char* expected_message_template[5]) -{ - string expected_message; - - // unix - expected_message = expected_message_template[0]; - test_each_exception_message(error_description + " -- unix", - argv[0], desc, unix_style, expected_message); - - // long dash only - expected_message = expected_message_template[1]; - test_each_exception_message(error_description + " -- long_dash", - argv[1], desc, long_dash, expected_message); - - - // short dash only - expected_message = expected_message_template[2]; - test_each_exception_message(error_description + " -- short_dash", - argv[2], desc, short_dash, expected_message); - - // short slash only - expected_message = expected_message_template[3]; - test_each_exception_message(error_description + " -- short_slash", - argv[3], desc, short_slash, expected_message); - - // config file only - expected_message = expected_message_template[4]; - if (expected_message.length()) - { - istringstream istrm(argv[4][0]); - test_each_exception_message(error_description + " -- config_file", - argv[4], desc, -1, expected_message, istrm); - } - -} - -#define VEC_STR_PUSH_BACK(vec, c_array) \ - vec.push_back(vector(c_array, c_array + sizeof(c_array) / sizeof(char*))); - -//________________________________________________________________________________________ -// -// invalid_option_value -// -//________________________________________________________________________________________ -void test_invalid_option_value_exception_msg() -{ - options_description desc; - int required_value; - desc.add_options() - ("int_option,d", value< int >(), "An option taking an integer") - ; - - vector> argv; - const char* argv0[] = { "program", "-d", "A_STRING"} ; VEC_STR_PUSH_BACK(argv, argv0); - const char* argv1[] = { "program", "--int", "A_STRING"}; VEC_STR_PUSH_BACK(argv, argv1); - const char* argv2[] = { "program", "-d", "A_STRING"} ; VEC_STR_PUSH_BACK(argv, argv2); - const char* argv3[] = { "program", "/d", "A_STRING"} ; VEC_STR_PUSH_BACK(argv, argv3); - const char* argv4[] = { "int_option=A_STRING"} ; VEC_STR_PUSH_BACK(argv, argv4); - - const char* expected_msg[5] = { - "the argument ('A_STRING') for option '--int_option' is invalid", - "the argument ('A_STRING') for option '--int_option' is invalid", - "the argument ('A_STRING') for option '-d' is invalid", - "the argument ('A_STRING') for option '/d' is invalid", - "the argument ('A_STRING') for option 'int_option' is invalid" - }; - - - test_exception_message(argv, desc, "invalid_option_value", - expected_msg); - - -} - -//________________________________________________________________________________________ -// -// missing_value -// -//________________________________________________________________________________________ -void test_missing_value_exception_msg() -{ - options_description desc; - desc.add_options() - ("cfgfile,e", value(), "the config file") - ("output,o", value(), "the output file") - ; - vector> argv; - const char* argv0[] = { "program", "-e", "-e", "output.txt"} ; VEC_STR_PUSH_BACK(argv, argv0); - const char* argv1[] = { "program", "--cfgfile"} ; VEC_STR_PUSH_BACK(argv, argv1); - const char* argv2[] = { "program", "-e", "-e", "output.txt"} ; VEC_STR_PUSH_BACK(argv, argv2); - const char* argv3[] = { "program", "/e", "/e", "output.txt"} ; VEC_STR_PUSH_BACK(argv, argv3); - const char* argv4[] = { ""} ; VEC_STR_PUSH_BACK(argv, argv4); - - const char* expected_msg[5] = { - "the required argument for option '--cfgfile' is missing", - "the required argument for option '--cfgfile' is missing", - "the required argument for option '-e' is missing", - "", // Ignore probable bug in cmdline::finish_option - //"the required argument for option '/e' is missing", - "", - }; - test_exception_message(argv, desc, - "invalid_syntax::missing_parameter", - expected_msg); -} - -//________________________________________________________________________________________ -// -// ambiguous_option -// -//________________________________________________________________________________________ -void test_ambiguous_option_exception_msg() -{ - options_description desc; - desc.add_options() - ("cfgfile1,c", value()->multitoken(), "the config file") - ("cfgfile2,o", value(), "the config file") - ("good,g", "good option") - ("output,c", value(), "the output file") - ("output", value(), "the output file") - ; - - vector> argv; - const char* argv0[] = {"program", "-ggc", "file", "-o", "anotherfile"} ; VEC_STR_PUSH_BACK(argv, argv0); - const char* argv1[] = {"program", "--cfgfile", "file", "--cfgfile", "anotherfile"} ; VEC_STR_PUSH_BACK(argv, argv1); - const char* argv2[] = {"program", "-ggc", "file", "-o", "anotherfile"} ; VEC_STR_PUSH_BACK(argv, argv2); - const char* argv3[] = {"program", "/c", "file", "/o", "anotherfile"} ; VEC_STR_PUSH_BACK(argv, argv3); - const char* argv4[] = { "output=output.txt\n"} ; VEC_STR_PUSH_BACK(argv, argv4); - const char* expected_msg[5] = { - "option '-c' is ambiguous and matches '--cfgfile1', and '--output'", - "option '--cfgfile' is ambiguous and matches '--cfgfile1', and '--cfgfile2'", - "option '-c' is ambiguous", - "option '/c' is ambiguous", - "option 'output' is ambiguous and matches different versions of 'output'", - }; - test_exception_message(argv, desc, "ambiguous_option", - expected_msg); -} - -//________________________________________________________________________________________ -// -// multiple_occurrences -// -//________________________________________________________________________________________ -void test_multiple_occurrences_exception_msg() -{ - options_description desc; - desc.add_options() - ("cfgfile,c", value(), "the configfile") - ; - - vector> argv; - const char* argv0[] = {"program", "-c", "file", "-c", "anotherfile"} ; VEC_STR_PUSH_BACK(argv, argv0); - const char* argv1[] = {"program", "--cfgfi", "file", "--cfgfi", "anotherfile"} ; VEC_STR_PUSH_BACK(argv, argv1); - const char* argv2[] = {"program", "-c", "file", "-c", "anotherfile"} ; VEC_STR_PUSH_BACK(argv, argv2); - const char* argv3[] = {"program", "/c", "file", "/c", "anotherfile"} ; VEC_STR_PUSH_BACK(argv, argv3); - const char* argv4[] = { "cfgfile=output.txt\ncfgfile=output.txt\n"} ; VEC_STR_PUSH_BACK(argv, argv4); - const char* expected_msg[5] = { - "option '--cfgfile' cannot be specified more than once", - "option '--cfgfile' cannot be specified more than once", - "option '-c' cannot be specified more than once", - "option '/c' cannot be specified more than once", - "option 'cfgfile' cannot be specified more than once", - }; - test_exception_message(argv, desc, "multiple_occurrences", - expected_msg); -} - -//________________________________________________________________________________________ -// -// unknown_option -// -//________________________________________________________________________________________ -void test_unknown_option_exception_msg() -{ - options_description desc; - desc.add_options() - ("good,g", "good option") - ; - - vector> argv; - const char* argv0[] = {"program", "-ggc", "file"} ; VEC_STR_PUSH_BACK(argv, argv0); - const char* argv1[] = {"program", "--cfgfile", "file"} ; VEC_STR_PUSH_BACK(argv, argv1); - const char* argv2[] = {"program", "-ggc", "file"} ; VEC_STR_PUSH_BACK(argv, argv2); - const char* argv3[] = {"program", "/c", "file"} ; VEC_STR_PUSH_BACK(argv, argv3); - const char* argv4[] = { "cfgfile=output.txt\n"} ; VEC_STR_PUSH_BACK(argv, argv4); - const char* expected_msg[5] = { - "unrecognised option '-ggc'", - "unrecognised option '--cfgfile'", - "unrecognised option '-ggc'", - "unrecognised option '/c'", - "unrecognised option 'cfgfile'", - }; - test_exception_message(argv, desc, "unknown_option", expected_msg); -} - -//________________________________________________________________________________________ -// -// validation_error::invalid_bool_value -// -//________________________________________________________________________________________ -void test_invalid_bool_value_exception_msg() -{ - options_description desc; - desc.add_options() - ("bool_option,b", value< bool>(), "bool_option") - ; - - - vector> argv; - const char* argv0[] = {"program", "-b", "file"} ; VEC_STR_PUSH_BACK(argv, argv0); - const char* argv1[] = {"program", "--bool_optio", "file"} ; VEC_STR_PUSH_BACK(argv, argv1); - const char* argv2[] = {"program", "-b", "file"} ; VEC_STR_PUSH_BACK(argv, argv2); - const char* argv3[] = {"program", "/b", "file"} ; VEC_STR_PUSH_BACK(argv, argv3); - const char* argv4[] = { "bool_option=output.txt\n"} ; VEC_STR_PUSH_BACK(argv, argv4); - const char* expected_msg[5] = { - "the argument ('file') for option '--bool_option' is invalid. Valid choices are 'on|off', 'yes|no', '1|0' and 'true|false'", - "the argument ('file') for option '--bool_option' is invalid. Valid choices are 'on|off', 'yes|no', '1|0' and 'true|false'", - "the argument ('file') for option '-b' is invalid. Valid choices are 'on|off', 'yes|no', '1|0' and 'true|false'", - "the argument ('file') for option '/b' is invalid. Valid choices are 'on|off', 'yes|no', '1|0' and 'true|false'", - "the argument ('output.txt') for option 'bool_option' is invalid. Valid choices are 'on|off', 'yes|no', '1|0' and 'true|false'", - }; - test_exception_message(argv, - desc, - "validation_error::invalid_bool_value", - expected_msg); -} - - - - -//________________________________________________________________________________________ -// -// validation_error::multiple_values_not_allowed -// -//________________________________________________________________________________________ -// -// Strange exception: sole purpose seems to be catching multitoken() not associated with a vector?? -// This is surely a corner case. -// -void test_multiple_values_not_allowed_exception_msg() -{ - options_description desc; - desc.add_options() - ("cfgfile,c", value()->multitoken(), "the config file") - ("good,g", "good option") - ("output,o", value()->multitoken(), "the output file") - ; - - vector> argv; - const char* argv0[] = { "program", "-c", "file", "c", "-o", "fritz", "hugo" } ; VEC_STR_PUSH_BACK(argv, argv0); - const char* argv1[] = { "program", "--cfgfil", "file", "c", "--outpu", "fritz", "hugo" } ; VEC_STR_PUSH_BACK(argv, argv1); - const char* argv2[] = { "program", "-c", "file", "c", "-o", "fritz", "hugo"} ; VEC_STR_PUSH_BACK(argv, argv2); - const char* argv3[] = { "program", "/c", "file", "c", "/o", "fritz", "hugo"} ; VEC_STR_PUSH_BACK(argv, argv3); - const char* argv4[] = { "" } ; VEC_STR_PUSH_BACK(argv, argv4); - const char* expected_msg[5] = { - "option '--cfgfile' only takes a single argument", - "option '--cfgfile' only takes a single argument", - "option '-c' only takes a single argument", - "option '/c' only takes a single argument", - "", - }; - test_exception_message(argv, - desc, - "validation_error::multiple_values_not_allowed", - expected_msg); -} - -//________________________________________________________________________________________ -// -// validation_error::at_least_one_value_required -// -//________________________________________________________________________________________ -// -// Can't build a test case!!! -// -// -void test_at_least_one_value_required_exception_msg() -{ - - return; - - options_description desc; - desc.add_options() - ("cfgfile,c", value>()->multitoken(), "the config file") - ("other,o", value(), "other") - ; - - vector> argv; - const char* argv0[] = { "program", "-c" } ; VEC_STR_PUSH_BACK(argv, argv0); - const char* argv1[] = { "program", "--cfg" } ; VEC_STR_PUSH_BACK(argv, argv1); - const char* argv2[] = { "program", "-c" , "-o" , "name" } ; VEC_STR_PUSH_BACK(argv, argv2); - const char* argv3[] = { "program", "/c" } ; VEC_STR_PUSH_BACK(argv, argv3); - const char* argv4[] = { "" } ; VEC_STR_PUSH_BACK(argv, argv4); - const char* expected_msg[5] = { - "Unexpected exception. the required argument for option '--cfgfile' is missing", - "Unexpected exception. the required argument for option '--cfgfile' is missing", - "Unexpected exception. the required argument for option '-c' is missing", - "Unexpected exception. the required argument for option '/c' is missing", - "", - }; - test_exception_message(argv, - desc, - "validation_error::at_least_one_value_required", - expected_msg); -} - - -//________________________________________________________________________________________ -// -// required_option -// -//________________________________________________________________________________________ -void test_required_option_exception_msg() -{ - options_description desc; - desc.add_options() - ("cfgfile,c", value()->required(), "the config file") - ("good,g", "good option") - ("output,o", value()->required(), "the output file") - ; - - vector> argv; - const char* argv0[] = { "program", "-g" } ; VEC_STR_PUSH_BACK(argv, argv0); - const char* argv1[] = { "program", "--g" } ; VEC_STR_PUSH_BACK(argv, argv1); - const char* argv2[] = { "program", "-g"} ; VEC_STR_PUSH_BACK(argv, argv2); - const char* argv3[] = { "program", "/g"} ; VEC_STR_PUSH_BACK(argv, argv3); - const char* argv4[] = { "" } ; VEC_STR_PUSH_BACK(argv, argv4); - const char* expected_msg[5] = { - "the option '--cfgfile' is required but missing", - "the option '--cfgfile' is required but missing", - "the option '-c' is required but missing", - "the option '/c' is required but missing", - "the option 'cfgfile' is required but missing", - }; - test_exception_message(argv, - desc, - "required_option", - expected_msg); -} - - - - - - - - - - - - - - - - - - -/** - * Check if this is the expected exception with the right message is being thrown inside - * func -*/ -template -void test_exception(const string& test_name, const string& exception_txt, FUNC func) -{ - - try { - options_description desc; - variables_map vm; - func(desc, vm); - } - catch (EXCEPTION& e) - { - CHECK_EQUAL(test_name, e.what(), exception_txt); - return; - } - catch (std::exception& e) - { - BOOST_ERROR(string(test_name + ":\nUnexpected exception. ") + e.what() + - "\nExpected text:\n" + exception_txt + "\n\n"); - return; - } - BOOST_ERROR(test_name + ": No exception thrown. "); -} - - - -//________________________________________________________________________________________ -// -// check_reading_file -// -//________________________________________________________________________________________ -void check_reading_file(options_description& desc, variables_map& vm) -{ - desc.add_options() - ("output,o", value(), "the output file"); - - const char* file_name = "no_such_file"; - store(parse_config_file(file_name, desc, true), vm); - -} - - -//________________________________________________________________________________________ -// -// config_file_wildcard -// -//________________________________________________________________________________________ -void config_file_wildcard(options_description& desc, variables_map& vm) -{ - desc.add_options() - ("outpu*", value(), "the output file1") - ("outp*", value(), "the output file2") - ; - istringstream is("output1=whichone\noutput2=whichone\n"); - store(parse_config_file(is, desc), vm); -} - -//________________________________________________________________________________________ -// -// invalid_syntax::unrecognized_line -// -//________________________________________________________________________________________ -void unrecognized_line(options_description& desc, variables_map& vm) -{ - istringstream is("funny wierd line\n"); - store(parse_config_file(is, desc), vm); -} - -//________________________________________________________________________________________ -// -// abbreviated_options_in_config_file -// -//________________________________________________________________________________________ -void abbreviated_options_in_config_file(options_description& desc, variables_map& vm) -{ - desc.add_options()(",o", value(), "the output file"); - istringstream is("o=output.txt\n"); - store(parse_config_file(is, desc), vm); -} - - -//________________________________________________________________________________________ -// -// too_many_positional_options -// -//________________________________________________________________________________________ -void too_many_positional_options(options_description& desc, variables_map& vm) -{ - const char* argv[] = {"program", "1", "2", "3"}; - positional_options_description positional_args; - positional_args.add("two_positional_arguments", 2); - store(command_line_parser(4, argv).options(desc).positional(positional_args).run(), vm); -} - - -//________________________________________________________________________________________ -// -// invalid_command_line_style -// -//________________________________________________________________________________________ - -void test_invalid_command_line_style_exception_msg() -{ - string test_name = "invalid_command_line_style"; - using namespace command_line_style; - unsigned basic_unix_style = (allow_short - | allow_long - | allow_sticky | allow_guessing - | allow_dash_for_short); - options_description desc; - desc.add_options()("output,o", value(), "the output file"); - - vector invalid_styles; - invalid_styles.push_back(allow_short | short_allow_adjacent); - invalid_styles.push_back(allow_short | allow_dash_for_short); - invalid_styles.push_back(allow_long); - vector invalid_diagnostics; - invalid_diagnostics.push_back("boost::program_options misconfiguration: choose one " - "or other of command_line_style::allow_slash_for_short " - "(slashes) or command_line_style::allow_dash_for_short " - "(dashes) for short options."); - invalid_diagnostics.push_back("boost::program_options misconfiguration: choose one " - "or other of 'command_line_style::short_allow_next' " - "(whitespace separated arguments) or " - "command_line_style::short_allow_adjacent ('=' " - "separated arguments) for short options."); - invalid_diagnostics.push_back("boost::program_options misconfiguration: choose one " - "or other of 'command_line_style::long_allow_next' " - "(whitespace separated arguments) or " - "command_line_style::long_allow_adjacent ('=' " - "separated arguments) for long options."); - - - const char* argv[] = {"program"}; - variables_map vm; - for (unsigned ii = 0; ii < 3; ++ii) - { - bool exception_thrown = false; - try - { - store(parse_command_line(1, argv, desc, invalid_styles[ii]), vm); - } - catch (invalid_command_line_style& e) - { - string error_msg("arguments are not allowed for unabbreviated option names"); - CHECK_EQUAL(test_name, e.what(), invalid_diagnostics[ii]); - exception_thrown = true; - } - catch (std::exception& e) - { - BOOST_ERROR(string(test_name + ":\nUnexpected exception. ") + e.what() + - "\nExpected text:\n" + invalid_diagnostics[ii] + "\n"); - exception_thrown = true; - } - if (!exception_thrown) - { - BOOST_ERROR(test_name << ": No exception thrown. "); - } - } -} - - -int main(int /*ac*/, char** /*av*/) -{ - test_ambiguous_option_exception_msg(); - test_unknown_option_exception_msg(); - test_multiple_occurrences_exception_msg(); - test_missing_value_exception_msg(); - test_invalid_option_value_exception_msg(); - test_invalid_bool_value_exception_msg(); - test_multiple_values_not_allowed_exception_msg(); - test_required_option_exception_msg(); - test_at_least_one_value_required_exception_msg(); - - - string test_name; - string expected_message; - - - // check_reading_file - test_name = "check_reading_file"; - expected_message = "can not read options configuration file 'no_such_file'"; - test_exception(test_name, expected_message, check_reading_file); - - // config_file_wildcard - test_name = "config_file_wildcard"; - expected_message = "options 'outpu*' and 'outp*' will both match the same arguments from the configuration file"; - test_exception(test_name, expected_message, config_file_wildcard); - - // unrecognized_line - test_name = "unrecognized_line"; - expected_message = "the options configuration file contains an invalid line 'funny wierd line'"; - test_exception(test_name, expected_message, unrecognized_line); - - - // abbreviated_options_in_config_file - test_name = "abbreviated_options_in_config_file"; - expected_message = "abbreviated option names are not permitted in options configuration files"; - test_exception(test_name, expected_message, abbreviated_options_in_config_file); - - test_name = "too_many_positional_options"; - expected_message = "too many positional arguments have been specified on the command line"; - test_exception( - test_name, expected_message, too_many_positional_options); - - test_invalid_command_line_style_exception_msg(); - return 0; -} - - - -// Copyright Sascha Ochsenknecht 2009. -// 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) - - -#include -#include -#include -#include -using namespace boost::program_options; - -#include -#include -#include -#include -using namespace std; - -#include "minitest.hpp" - - - -// -// like BOOST_CHECK_EQUAL but with more descriptive error message -// -#define CHECK_EQUAL(description, a, b) if (a != b) {std::cerr << "\n\nError:\n<<" << \ - description << ">>\n Expected text=\"" << b << "\"\n Actual text =\"" << a << "\"\n\n"; assert(a == b);} - - -// Uncomment for Debugging, removes asserts so we can see more failures! -//#define BOOST_ERROR(description) std::cerr << description; std::cerr << "\n"; - - -//8888888888888888888888888888888888888888888888888888888888888888888888888888888888888888 -// -// Uncomment to print out the complete set of diagnostic messages for the different test cases -// -//#define CHECK_EQUAL(description, a, b) if (a != b) {std::cerr << "\n\nError: " << \ -// description << "\n Expecting\n" << b << "\n Found\n" << a << "\n\n"; } \ -// else {std::cout << description<< "\t" << b << "\n";} - -//8888888888888888888888888888888888888888888888888888888888888888888888888888888888888888 - - -// -// test exception for each specified command line style, e.g. short dash or config file -// -template -void test_each_exception_message(const string& test_description, const vector& argv, options_description& desc, int style, string exception_msg, istream& is = cin) -{ - if (exception_msg.length() == 0) - return; - variables_map vm; - unsigned argc = argv.size(); - - - try { - if (style == -1) - store(parse_config_file(is, desc), vm); - else - store(parse_command_line(argv.size(), argv.data(), desc, style), vm); - notify(vm); - } - catch (EXCEPTION& e) - { - //cerr << "Correct:\n\t" << e.what() << "\n"; - CHECK_EQUAL(test_description, e.what(), exception_msg); - return; - } - catch (std::exception& e) - { - // concatenate argv without boost::algorithm::join - string argv_txt; - for (unsigned ii = 0; ii < argc - 1; ++ii) - argv_txt += argv[ii] + string(" "); - if (argc) - argv_txt += argv[argc - 1]; - - BOOST_ERROR("\n<<" + test_description + - string(">>\n Unexpected exception type!\n Actual text =\"") + e.what() + - "\"\n argv =\"" + argv_txt + - "\"\n Expected text=\"" + exception_msg + "\"\n"); - return; - } - BOOST_ERROR(test_description + ": No exception thrown. "); -} - - - - -// -// test exception messages for all command line styles (unix/long/short/slash/config file) -// -// try each command line style in turn -const int unix_style = command_line_style::unix_style; -const int short_dash = command_line_style::allow_dash_for_short | command_line_style::allow_short | command_line_style::short_allow_adjacent | command_line_style::allow_sticky; -const int short_slash = command_line_style::allow_slash_for_short | command_line_style::allow_short | command_line_style::short_allow_adjacent; -const int long_dash = command_line_style::allow_long | command_line_style::long_allow_adjacent | command_line_style::allow_guessing; - - - -template -void test_exception_message(const vector>& argv, - options_description& desc, - const string& error_description, - const char* expected_message_template[5]) -{ - string expected_message; - - // unix - expected_message = expected_message_template[0]; - test_each_exception_message(error_description + " -- unix", - argv[0], desc, unix_style, expected_message); - - // long dash only - expected_message = expected_message_template[1]; - test_each_exception_message(error_description + " -- long_dash", - argv[1], desc, long_dash, expected_message); - - - // short dash only - expected_message = expected_message_template[2]; - test_each_exception_message(error_description + " -- short_dash", - argv[2], desc, short_dash, expected_message); - - // short slash only - expected_message = expected_message_template[3]; - test_each_exception_message(error_description + " -- short_slash", - argv[3], desc, short_slash, expected_message); - - // config file only - expected_message = expected_message_template[4]; - if (expected_message.length()) - { - istringstream istrm(argv[4][0]); - test_each_exception_message(error_description + " -- config_file", - argv[4], desc, -1, expected_message, istrm); - } - -} - -#define VEC_STR_PUSH_BACK(vec, c_array) \ - vec.push_back(vector(c_array, c_array + sizeof(c_array) / sizeof(char*))); - -//________________________________________________________________________________________ -// -// invalid_option_value -// -//________________________________________________________________________________________ -void test_invalid_option_value_exception_msg() -{ - options_description desc; - int required_value; - desc.add_options() - ("int_option,d", value< int >(), "An option taking an integer") - ; - - vector> argv; - const char* argv0[] = { "program", "-d", "A_STRING"} ; VEC_STR_PUSH_BACK(argv, argv0); - const char* argv1[] = { "program", "--int", "A_STRING"}; VEC_STR_PUSH_BACK(argv, argv1); - const char* argv2[] = { "program", "-d", "A_STRING"} ; VEC_STR_PUSH_BACK(argv, argv2); - const char* argv3[] = { "program", "/d", "A_STRING"} ; VEC_STR_PUSH_BACK(argv, argv3); - const char* argv4[] = { "int_option=A_STRING"} ; VEC_STR_PUSH_BACK(argv, argv4); - - const char* expected_msg[5] = { - "the argument ('A_STRING') for option '--int_option' is invalid", - "the argument ('A_STRING') for option '--int_option' is invalid", - "the argument ('A_STRING') for option '-d' is invalid", - "the argument ('A_STRING') for option '/d' is invalid", - "the argument ('A_STRING') for option 'int_option' is invalid" - }; - - - test_exception_message(argv, desc, "invalid_option_value", - expected_msg); - - -} - -//________________________________________________________________________________________ -// -// missing_value -// -//________________________________________________________________________________________ -void test_missing_value_exception_msg() -{ - options_description desc; - desc.add_options() - ("cfgfile,e", value(), "the config file") - ("output,o", value(), "the output file") - ; - vector> argv; - const char* argv0[] = { "program", "-e", "-e", "output.txt"} ; VEC_STR_PUSH_BACK(argv, argv0); - const char* argv1[] = { "program", "--cfgfile"} ; VEC_STR_PUSH_BACK(argv, argv1); - const char* argv2[] = { "program", "-e", "-e", "output.txt"} ; VEC_STR_PUSH_BACK(argv, argv2); - const char* argv3[] = { "program", "/e", "/e", "output.txt"} ; VEC_STR_PUSH_BACK(argv, argv3); - const char* argv4[] = { ""} ; VEC_STR_PUSH_BACK(argv, argv4); - - const char* expected_msg[5] = { - "the required argument for option '--cfgfile' is missing", - "the required argument for option '--cfgfile' is missing", - "the required argument for option '-e' is missing", - "", // Ignore probable bug in cmdline::finish_option - //"the required argument for option '/e' is missing", - "", - }; - test_exception_message(argv, desc, - "invalid_syntax::missing_parameter", - expected_msg); -} - -//________________________________________________________________________________________ -// -// ambiguous_option -// -//________________________________________________________________________________________ -void test_ambiguous_option_exception_msg() -{ - options_description desc; - desc.add_options() - ("cfgfile1,c", value()->multitoken(), "the config file") - ("cfgfile2,o", value(), "the config file") - ("good,g", "good option") - ("output,c", value(), "the output file") - ("output", value(), "the output file") - ; - - vector> argv; - const char* argv0[] = {"program", "-ggc", "file", "-o", "anotherfile"} ; VEC_STR_PUSH_BACK(argv, argv0); - const char* argv1[] = {"program", "--cfgfile", "file", "--cfgfile", "anotherfile"} ; VEC_STR_PUSH_BACK(argv, argv1); - const char* argv2[] = {"program", "-ggc", "file", "-o", "anotherfile"} ; VEC_STR_PUSH_BACK(argv, argv2); - const char* argv3[] = {"program", "/c", "file", "/o", "anotherfile"} ; VEC_STR_PUSH_BACK(argv, argv3); - const char* argv4[] = { "output=output.txt\n"} ; VEC_STR_PUSH_BACK(argv, argv4); - const char* expected_msg[5] = { - "option '-c' is ambiguous and matches '--cfgfile1', and '--output'", - "option '--cfgfile' is ambiguous and matches '--cfgfile1', and '--cfgfile2'", - "option '-c' is ambiguous", - "option '/c' is ambiguous", - "option 'output' is ambiguous and matches different versions of 'output'", - }; - test_exception_message(argv, desc, "ambiguous_option", - expected_msg); -} - -//________________________________________________________________________________________ -// -// multiple_occurrences -// -//________________________________________________________________________________________ -void test_multiple_occurrences_exception_msg() -{ - options_description desc; - desc.add_options() - ("cfgfile,c", value(), "the configfile") - ; - - vector> argv; - const char* argv0[] = {"program", "-c", "file", "-c", "anotherfile"} ; VEC_STR_PUSH_BACK(argv, argv0); - const char* argv1[] = {"program", "--cfgfi", "file", "--cfgfi", "anotherfile"} ; VEC_STR_PUSH_BACK(argv, argv1); - const char* argv2[] = {"program", "-c", "file", "-c", "anotherfile"} ; VEC_STR_PUSH_BACK(argv, argv2); - const char* argv3[] = {"program", "/c", "file", "/c", "anotherfile"} ; VEC_STR_PUSH_BACK(argv, argv3); - const char* argv4[] = { "cfgfile=output.txt\ncfgfile=output.txt\n"} ; VEC_STR_PUSH_BACK(argv, argv4); - const char* expected_msg[5] = { - "option '--cfgfile' cannot be specified more than once", - "option '--cfgfile' cannot be specified more than once", - "option '-c' cannot be specified more than once", - "option '/c' cannot be specified more than once", - "option 'cfgfile' cannot be specified more than once", - }; - test_exception_message(argv, desc, "multiple_occurrences", - expected_msg); -} - -//________________________________________________________________________________________ -// -// unknown_option -// -//________________________________________________________________________________________ -void test_unknown_option_exception_msg() -{ - options_description desc; - desc.add_options() - ("good,g", "good option") - ; - - vector> argv; - const char* argv0[] = {"program", "-ggc", "file"} ; VEC_STR_PUSH_BACK(argv, argv0); - const char* argv1[] = {"program", "--cfgfile", "file"} ; VEC_STR_PUSH_BACK(argv, argv1); - const char* argv2[] = {"program", "-ggc", "file"} ; VEC_STR_PUSH_BACK(argv, argv2); - const char* argv3[] = {"program", "/c", "file"} ; VEC_STR_PUSH_BACK(argv, argv3); - const char* argv4[] = { "cfgfile=output.txt\n"} ; VEC_STR_PUSH_BACK(argv, argv4); - const char* expected_msg[5] = { - "unrecognised option '-ggc'", - "unrecognised option '--cfgfile'", - "unrecognised option '-ggc'", - "unrecognised option '/c'", - "unrecognised option 'cfgfile'", - }; - test_exception_message(argv, desc, "unknown_option", expected_msg); -} - -//________________________________________________________________________________________ -// -// validation_error::invalid_bool_value -// -//________________________________________________________________________________________ -void test_invalid_bool_value_exception_msg() -{ - options_description desc; - desc.add_options() - ("bool_option,b", value< bool>(), "bool_option") - ; - - - vector> argv; - const char* argv0[] = {"program", "-b", "file"} ; VEC_STR_PUSH_BACK(argv, argv0); - const char* argv1[] = {"program", "--bool_optio", "file"} ; VEC_STR_PUSH_BACK(argv, argv1); - const char* argv2[] = {"program", "-b", "file"} ; VEC_STR_PUSH_BACK(argv, argv2); - const char* argv3[] = {"program", "/b", "file"} ; VEC_STR_PUSH_BACK(argv, argv3); - const char* argv4[] = { "bool_option=output.txt\n"} ; VEC_STR_PUSH_BACK(argv, argv4); - const char* expected_msg[5] = { - "the argument ('file') for option '--bool_option' is invalid. Valid choices are 'on|off', 'yes|no', '1|0' and 'true|false'", - "the argument ('file') for option '--bool_option' is invalid. Valid choices are 'on|off', 'yes|no', '1|0' and 'true|false'", - "the argument ('file') for option '-b' is invalid. Valid choices are 'on|off', 'yes|no', '1|0' and 'true|false'", - "the argument ('file') for option '/b' is invalid. Valid choices are 'on|off', 'yes|no', '1|0' and 'true|false'", - "the argument ('output.txt') for option 'bool_option' is invalid. Valid choices are 'on|off', 'yes|no', '1|0' and 'true|false'", - }; - test_exception_message(argv, - desc, - "validation_error::invalid_bool_value", - expected_msg); -} - - - - -//________________________________________________________________________________________ -// -// validation_error::multiple_values_not_allowed -// -//________________________________________________________________________________________ -// -// Strange exception: sole purpose seems to be catching multitoken() not associated with a vector?? -// This is surely a corner case. -// -void test_multiple_values_not_allowed_exception_msg() -{ - options_description desc; - desc.add_options() - ("cfgfile,c", value()->multitoken(), "the config file") - ("good,g", "good option") - ("output,o", value()->multitoken(), "the output file") - ; - - vector> argv; - const char* argv0[] = { "program", "-c", "file", "c", "-o", "fritz", "hugo" } ; VEC_STR_PUSH_BACK(argv, argv0); - const char* argv1[] = { "program", "--cfgfil", "file", "c", "--outpu", "fritz", "hugo" } ; VEC_STR_PUSH_BACK(argv, argv1); - const char* argv2[] = { "program", "-c", "file", "c", "-o", "fritz", "hugo"} ; VEC_STR_PUSH_BACK(argv, argv2); - const char* argv3[] = { "program", "/c", "file", "c", "/o", "fritz", "hugo"} ; VEC_STR_PUSH_BACK(argv, argv3); - const char* argv4[] = { "" } ; VEC_STR_PUSH_BACK(argv, argv4); - const char* expected_msg[5] = { - "option '--cfgfile' only takes a single argument", - "option '--cfgfile' only takes a single argument", - "option '-c' only takes a single argument", - "option '/c' only takes a single argument", - "", - }; - test_exception_message(argv, - desc, - "validation_error::multiple_values_not_allowed", - expected_msg); -} - -//________________________________________________________________________________________ -// -// validation_error::at_least_one_value_required -// -//________________________________________________________________________________________ -// -// Can't build a test case!!! -// -// -void test_at_least_one_value_required_exception_msg() -{ - - return; - - options_description desc; - desc.add_options() - ("cfgfile,c", value>()->multitoken(), "the config file") - ("other,o", value(), "other") - ; - - vector> argv; - const char* argv0[] = { "program", "-c" } ; VEC_STR_PUSH_BACK(argv, argv0); - const char* argv1[] = { "program", "--cfg" } ; VEC_STR_PUSH_BACK(argv, argv1); - const char* argv2[] = { "program", "-c" , "-o" , "name" } ; VEC_STR_PUSH_BACK(argv, argv2); - const char* argv3[] = { "program", "/c" } ; VEC_STR_PUSH_BACK(argv, argv3); - const char* argv4[] = { "" } ; VEC_STR_PUSH_BACK(argv, argv4); - const char* expected_msg[5] = { - "Unexpected exception. the required argument for option '--cfgfile' is missing", - "Unexpected exception. the required argument for option '--cfgfile' is missing", - "Unexpected exception. the required argument for option '-c' is missing", - "Unexpected exception. the required argument for option '/c' is missing", - "", - }; - test_exception_message(argv, - desc, - "validation_error::at_least_one_value_required", - expected_msg); -} - - -//________________________________________________________________________________________ -// -// required_option -// -//________________________________________________________________________________________ -void test_required_option_exception_msg() -{ - options_description desc; - desc.add_options() - ("cfgfile,c", value()->required(), "the config file") - ("good,g", "good option") - ("output,o", value()->required(), "the output file") - ; - - vector> argv; - const char* argv0[] = { "program", "-g" } ; VEC_STR_PUSH_BACK(argv, argv0); - const char* argv1[] = { "program", "--g" } ; VEC_STR_PUSH_BACK(argv, argv1); - const char* argv2[] = { "program", "-g"} ; VEC_STR_PUSH_BACK(argv, argv2); - const char* argv3[] = { "program", "/g"} ; VEC_STR_PUSH_BACK(argv, argv3); - const char* argv4[] = { "" } ; VEC_STR_PUSH_BACK(argv, argv4); - const char* expected_msg[5] = { - "the option '--cfgfile' is required but missing", - "the option '--cfgfile' is required but missing", - "the option '-c' is required but missing", - "the option '/c' is required but missing", - "the option 'cfgfile' is required but missing", - }; - test_exception_message(argv, - desc, - "required_option", - expected_msg); -} - - - - - - - - - - - - - - - - - - -/** - * Check if this is the expected exception with the right message is being thrown inside - * func -*/ -template -void test_exception(const string& test_name, const string& exception_txt, FUNC func) -{ - - try { - options_description desc; - variables_map vm; - func(desc, vm); - } - catch (EXCEPTION& e) - { - CHECK_EQUAL(test_name, e.what(), exception_txt); - return; - } - catch (std::exception& e) - { - BOOST_ERROR(string(test_name + ":\nUnexpected exception. ") + e.what() + - "\nExpected text:\n" + exception_txt + "\n\n"); - return; - } - BOOST_ERROR(test_name + ": No exception thrown. "); -} - - - -//________________________________________________________________________________________ -// -// check_reading_file -// -//________________________________________________________________________________________ -void check_reading_file(options_description& desc, variables_map& vm) -{ - desc.add_options() - ("output,o", value(), "the output file"); - - const char* file_name = "no_such_file"; - store(parse_config_file(file_name, desc, true), vm); - -} - - -//________________________________________________________________________________________ -// -// config_file_wildcard -// -//________________________________________________________________________________________ -void config_file_wildcard(options_description& desc, variables_map& vm) -{ - desc.add_options() - ("outpu*", value(), "the output file1") - ("outp*", value(), "the output file2") - ; - istringstream is("output1=whichone\noutput2=whichone\n"); - store(parse_config_file(is, desc), vm); -} - -//________________________________________________________________________________________ -// -// invalid_syntax::unrecognized_line -// -//________________________________________________________________________________________ -void unrecognized_line(options_description& desc, variables_map& vm) -{ - istringstream is("funny wierd line\n"); - store(parse_config_file(is, desc), vm); -} - -//________________________________________________________________________________________ -// -// abbreviated_options_in_config_file -// -//________________________________________________________________________________________ -void abbreviated_options_in_config_file(options_description& desc, variables_map& vm) -{ - desc.add_options()(",o", value(), "the output file"); - istringstream is("o=output.txt\n"); - store(parse_config_file(is, desc), vm); -} - - -//________________________________________________________________________________________ -// -// too_many_positional_options -// -//________________________________________________________________________________________ -void too_many_positional_options(options_description& desc, variables_map& vm) -{ - const char* argv[] = {"program", "1", "2", "3"}; - positional_options_description positional_args; - positional_args.add("two_positional_arguments", 2); - store(command_line_parser(4, argv).options(desc).positional(positional_args).run(), vm); -} - - -//________________________________________________________________________________________ -// -// invalid_command_line_style -// -//________________________________________________________________________________________ - -void test_invalid_command_line_style_exception_msg() -{ - string test_name = "invalid_command_line_style"; - using namespace command_line_style; - unsigned basic_unix_style = (allow_short - | allow_long - | allow_sticky | allow_guessing - | allow_dash_for_short); - options_description desc; - desc.add_options()("output,o", value(), "the output file"); - - vector invalid_styles; - invalid_styles.push_back(allow_short | short_allow_adjacent); - invalid_styles.push_back(allow_short | allow_dash_for_short); - invalid_styles.push_back(allow_long); - vector invalid_diagnostics; - invalid_diagnostics.push_back("boost::program_options misconfiguration: choose one " - "or other of command_line_style::allow_slash_for_short " - "(slashes) or command_line_style::allow_dash_for_short " - "(dashes) for short options."); - invalid_diagnostics.push_back("boost::program_options misconfiguration: choose one " - "or other of 'command_line_style::short_allow_next' " - "(whitespace separated arguments) or " - "command_line_style::short_allow_adjacent ('=' " - "separated arguments) for short options."); - invalid_diagnostics.push_back("boost::program_options misconfiguration: choose one " - "or other of 'command_line_style::long_allow_next' " - "(whitespace separated arguments) or " - "command_line_style::long_allow_adjacent ('=' " - "separated arguments) for long options."); - - - const char* argv[] = {"program"}; - variables_map vm; - for (unsigned ii = 0; ii < 3; ++ii) - { - bool exception_thrown = false; - try - { - store(parse_command_line(1, argv, desc, invalid_styles[ii]), vm); - } - catch (invalid_command_line_style& e) - { - string error_msg("arguments are not allowed for unabbreviated option names"); - CHECK_EQUAL(test_name, e.what(), invalid_diagnostics[ii]); - exception_thrown = true; - } - catch (std::exception& e) - { - BOOST_ERROR(string(test_name + ":\nUnexpected exception. ") + e.what() + - "\nExpected text:\n" + invalid_diagnostics[ii] + "\n"); - exception_thrown = true; - } - if (!exception_thrown) - { - BOOST_ERROR(test_name << ": No exception thrown. "); - } - } -} - - -int main(int /*ac*/, char** /*av*/) -{ - test_ambiguous_option_exception_msg(); - test_unknown_option_exception_msg(); - test_multiple_occurrences_exception_msg(); - test_missing_value_exception_msg(); - test_invalid_option_value_exception_msg(); - test_invalid_bool_value_exception_msg(); - test_multiple_values_not_allowed_exception_msg(); - test_required_option_exception_msg(); - test_at_least_one_value_required_exception_msg(); - - - string test_name; - string expected_message; - - - // check_reading_file - test_name = "check_reading_file"; - expected_message = "can not read options configuration file 'no_such_file'"; - test_exception(test_name, expected_message, check_reading_file); - - // config_file_wildcard - test_name = "config_file_wildcard"; - expected_message = "options 'outpu*' and 'outp*' will both match the same arguments from the configuration file"; - test_exception(test_name, expected_message, config_file_wildcard); - - // unrecognized_line - test_name = "unrecognized_line"; - expected_message = "the options configuration file contains an invalid line 'funny wierd line'"; - test_exception(test_name, expected_message, unrecognized_line); - - - // abbreviated_options_in_config_file - test_name = "abbreviated_options_in_config_file"; - expected_message = "abbreviated option names are not permitted in options configuration files"; - test_exception(test_name, expected_message, abbreviated_options_in_config_file); - - test_name = "too_many_positional_options"; - expected_message = "too many positional arguments have been specified on the command line"; - test_exception( - test_name, expected_message, too_many_positional_options); - - test_invalid_command_line_style_exception_msg(); - return 0; -} - - - -// Copyright Sascha Ochsenknecht 2009. -// 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) - - -#include -#include -#include -#include -using namespace boost::program_options; - -#include -#include -#include -#include -using namespace std; - -#include "minitest.hpp" - - - -// -// like BOOST_CHECK_EQUAL but with more descriptive error message -// -#define CHECK_EQUAL(description, a, b) if (a != b) {std::cerr << "\n\nError:\n<<" << \ - description << ">>\n Expected text=\"" << b << "\"\n Actual text =\"" << a << "\"\n\n"; assert(a == b);} - - -// Uncomment for Debugging, removes asserts so we can see more failures! -//#define BOOST_ERROR(description) std::cerr << description; std::cerr << "\n"; - - -//8888888888888888888888888888888888888888888888888888888888888888888888888888888888888888 -// -// Uncomment to print out the complete set of diagnostic messages for the different test cases -// -//#define CHECK_EQUAL(description, a, b) if (a != b) {std::cerr << "\n\nError: " << \ -// description << "\n Expecting\n" << b << "\n Found\n" << a << "\n\n"; } \ -// else {std::cout << description<< "\t" << b << "\n";} - -//8888888888888888888888888888888888888888888888888888888888888888888888888888888888888888 - - -// -// test exception for each specified command line style, e.g. short dash or config file -// -template -void test_each_exception_message(const string& test_description, const vector& argv, options_description& desc, int style, string exception_msg, istream& is = cin) -{ - if (exception_msg.length() == 0) - return; - variables_map vm; - unsigned argc = argv.size(); - - - try { - if (style == -1) - store(parse_config_file(is, desc), vm); - else - store(parse_command_line(argv.size(), argv.data(), desc, style), vm); - notify(vm); - } - catch (EXCEPTION& e) - { - //cerr << "Correct:\n\t" << e.what() << "\n"; - CHECK_EQUAL(test_description, e.what(), exception_msg); - return; - } - catch (std::exception& e) - { - // concatenate argv without boost::algorithm::join - string argv_txt; - for (unsigned ii = 0; ii < argc - 1; ++ii) - argv_txt += argv[ii] + string(" "); - if (argc) - argv_txt += argv[argc - 1]; - - BOOST_ERROR("\n<<" + test_description + - string(">>\n Unexpected exception type!\n Actual text =\"") + e.what() + - "\"\n argv =\"" + argv_txt + - "\"\n Expected text=\"" + exception_msg + "\"\n"); - return; - } - BOOST_ERROR(test_description + ": No exception thrown. "); -} - - - - -// -// test exception messages for all command line styles (unix/long/short/slash/config file) -// -// try each command line style in turn -const int unix_style = command_line_style::unix_style; -const int short_dash = command_line_style::allow_dash_for_short | command_line_style::allow_short | command_line_style::short_allow_adjacent | command_line_style::allow_sticky; -const int short_slash = command_line_style::allow_slash_for_short | command_line_style::allow_short | command_line_style::short_allow_adjacent; -const int long_dash = command_line_style::allow_long | command_line_style::long_allow_adjacent | command_line_style::allow_guessing; - - - -template -void test_exception_message(const vector>& argv, - options_description& desc, - const string& error_description, - const char* expected_message_template[5]) -{ - string expected_message; - - // unix - expected_message = expected_message_template[0]; - test_each_exception_message(error_description + " -- unix", - argv[0], desc, unix_style, expected_message); - - // long dash only - expected_message = expected_message_template[1]; - test_each_exception_message(error_description + " -- long_dash", - argv[1], desc, long_dash, expected_message); - - - // short dash only - expected_message = expected_message_template[2]; - test_each_exception_message(error_description + " -- short_dash", - argv[2], desc, short_dash, expected_message); - - // short slash only - expected_message = expected_message_template[3]; - test_each_exception_message(error_description + " -- short_slash", - argv[3], desc, short_slash, expected_message); - - // config file only - expected_message = expected_message_template[4]; - if (expected_message.length()) - { - istringstream istrm(argv[4][0]); - test_each_exception_message(error_description + " -- config_file", - argv[4], desc, -1, expected_message, istrm); - } - -} - -#define VEC_STR_PUSH_BACK(vec, c_array) \ - vec.push_back(vector(c_array, c_array + sizeof(c_array) / sizeof(char*))); - -//________________________________________________________________________________________ -// -// invalid_option_value -// -//________________________________________________________________________________________ -void test_invalid_option_value_exception_msg() -{ - options_description desc; - int required_value; - desc.add_options() - ("int_option,d", value< int >(), "An option taking an integer") - ; - - vector> argv; - const char* argv0[] = { "program", "-d", "A_STRING"} ; VEC_STR_PUSH_BACK(argv, argv0); - const char* argv1[] = { "program", "--int", "A_STRING"}; VEC_STR_PUSH_BACK(argv, argv1); - const char* argv2[] = { "program", "-d", "A_STRING"} ; VEC_STR_PUSH_BACK(argv, argv2); - const char* argv3[] = { "program", "/d", "A_STRING"} ; VEC_STR_PUSH_BACK(argv, argv3); - const char* argv4[] = { "int_option=A_STRING"} ; VEC_STR_PUSH_BACK(argv, argv4); - - const char* expected_msg[5] = { - "the argument ('A_STRING') for option '--int_option' is invalid", - "the argument ('A_STRING') for option '--int_option' is invalid", - "the argument ('A_STRING') for option '-d' is invalid", - "the argument ('A_STRING') for option '/d' is invalid", - "the argument ('A_STRING') for option 'int_option' is invalid" - }; - - - test_exception_message(argv, desc, "invalid_option_value", - expected_msg); - - -} - -//________________________________________________________________________________________ -// -// missing_value -// -//________________________________________________________________________________________ -void test_missing_value_exception_msg() -{ - options_description desc; - desc.add_options() - ("cfgfile,e", value(), "the config file") - ("output,o", value(), "the output file") - ; - vector> argv; - const char* argv0[] = { "program", "-e", "-e", "output.txt"} ; VEC_STR_PUSH_BACK(argv, argv0); - const char* argv1[] = { "program", "--cfgfile"} ; VEC_STR_PUSH_BACK(argv, argv1); - const char* argv2[] = { "program", "-e", "-e", "output.txt"} ; VEC_STR_PUSH_BACK(argv, argv2); - const char* argv3[] = { "program", "/e", "/e", "output.txt"} ; VEC_STR_PUSH_BACK(argv, argv3); - const char* argv4[] = { ""} ; VEC_STR_PUSH_BACK(argv, argv4); - - const char* expected_msg[5] = { - "the required argument for option '--cfgfile' is missing", - "the required argument for option '--cfgfile' is missing", - "the required argument for option '-e' is missing", - "", // Ignore probable bug in cmdline::finish_option - //"the required argument for option '/e' is missing", - "", - }; - test_exception_message(argv, desc, - "invalid_syntax::missing_parameter", - expected_msg); -} - -//________________________________________________________________________________________ -// -// ambiguous_option -// -//________________________________________________________________________________________ -void test_ambiguous_option_exception_msg() -{ - options_description desc; - desc.add_options() - ("cfgfile1,c", value()->multitoken(), "the config file") - ("cfgfile2,o", value(), "the config file") - ("good,g", "good option") - ("output,c", value(), "the output file") - ("output", value(), "the output file") - ; - - vector> argv; - const char* argv0[] = {"program", "-ggc", "file", "-o", "anotherfile"} ; VEC_STR_PUSH_BACK(argv, argv0); - const char* argv1[] = {"program", "--cfgfile", "file", "--cfgfile", "anotherfile"} ; VEC_STR_PUSH_BACK(argv, argv1); - const char* argv2[] = {"program", "-ggc", "file", "-o", "anotherfile"} ; VEC_STR_PUSH_BACK(argv, argv2); - const char* argv3[] = {"program", "/c", "file", "/o", "anotherfile"} ; VEC_STR_PUSH_BACK(argv, argv3); - const char* argv4[] = { "output=output.txt\n"} ; VEC_STR_PUSH_BACK(argv, argv4); - const char* expected_msg[5] = { - "option '-c' is ambiguous and matches '--cfgfile1', and '--output'", - "option '--cfgfile' is ambiguous and matches '--cfgfile1', and '--cfgfile2'", - "option '-c' is ambiguous", - "option '/c' is ambiguous", - "option 'output' is ambiguous and matches different versions of 'output'", - }; - test_exception_message(argv, desc, "ambiguous_option", - expected_msg); -} - -//________________________________________________________________________________________ -// -// multiple_occurrences -// -//________________________________________________________________________________________ -void test_multiple_occurrences_exception_msg() -{ - options_description desc; - desc.add_options() - ("cfgfile,c", value(), "the configfile") - ; - - vector> argv; - const char* argv0[] = {"program", "-c", "file", "-c", "anotherfile"} ; VEC_STR_PUSH_BACK(argv, argv0); - const char* argv1[] = {"program", "--cfgfi", "file", "--cfgfi", "anotherfile"} ; VEC_STR_PUSH_BACK(argv, argv1); - const char* argv2[] = {"program", "-c", "file", "-c", "anotherfile"} ; VEC_STR_PUSH_BACK(argv, argv2); - const char* argv3[] = {"program", "/c", "file", "/c", "anotherfile"} ; VEC_STR_PUSH_BACK(argv, argv3); - const char* argv4[] = { "cfgfile=output.txt\ncfgfile=output.txt\n"} ; VEC_STR_PUSH_BACK(argv, argv4); - const char* expected_msg[5] = { - "option '--cfgfile' cannot be specified more than once", - "option '--cfgfile' cannot be specified more than once", - "option '-c' cannot be specified more than once", - "option '/c' cannot be specified more than once", - "option 'cfgfile' cannot be specified more than once", - }; - test_exception_message(argv, desc, "multiple_occurrences", - expected_msg); -} - -//________________________________________________________________________________________ -// -// unknown_option -// -//________________________________________________________________________________________ -void test_unknown_option_exception_msg() -{ - options_description desc; - desc.add_options() - ("good,g", "good option") - ; - - vector> argv; - const char* argv0[] = {"program", "-ggc", "file"} ; VEC_STR_PUSH_BACK(argv, argv0); - const char* argv1[] = {"program", "--cfgfile", "file"} ; VEC_STR_PUSH_BACK(argv, argv1); - const char* argv2[] = {"program", "-ggc", "file"} ; VEC_STR_PUSH_BACK(argv, argv2); - const char* argv3[] = {"program", "/c", "file"} ; VEC_STR_PUSH_BACK(argv, argv3); - const char* argv4[] = { "cfgfile=output.txt\n"} ; VEC_STR_PUSH_BACK(argv, argv4); - const char* expected_msg[5] = { - "unrecognised option '-ggc'", - "unrecognised option '--cfgfile'", - "unrecognised option '-ggc'", - "unrecognised option '/c'", - "unrecognised option 'cfgfile'", - }; - test_exception_message(argv, desc, "unknown_option", expected_msg); -} - -//________________________________________________________________________________________ -// -// validation_error::invalid_bool_value -// -//________________________________________________________________________________________ -void test_invalid_bool_value_exception_msg() -{ - options_description desc; - desc.add_options() - ("bool_option,b", value< bool>(), "bool_option") - ; - - - vector> argv; - const char* argv0[] = {"program", "-b", "file"} ; VEC_STR_PUSH_BACK(argv, argv0); - const char* argv1[] = {"program", "--bool_optio", "file"} ; VEC_STR_PUSH_BACK(argv, argv1); - const char* argv2[] = {"program", "-b", "file"} ; VEC_STR_PUSH_BACK(argv, argv2); - const char* argv3[] = {"program", "/b", "file"} ; VEC_STR_PUSH_BACK(argv, argv3); - const char* argv4[] = { "bool_option=output.txt\n"} ; VEC_STR_PUSH_BACK(argv, argv4); - const char* expected_msg[5] = { - "the argument ('file') for option '--bool_option' is invalid. Valid choices are 'on|off', 'yes|no', '1|0' and 'true|false'", - "the argument ('file') for option '--bool_option' is invalid. Valid choices are 'on|off', 'yes|no', '1|0' and 'true|false'", - "the argument ('file') for option '-b' is invalid. Valid choices are 'on|off', 'yes|no', '1|0' and 'true|false'", - "the argument ('file') for option '/b' is invalid. Valid choices are 'on|off', 'yes|no', '1|0' and 'true|false'", - "the argument ('output.txt') for option 'bool_option' is invalid. Valid choices are 'on|off', 'yes|no', '1|0' and 'true|false'", - }; - test_exception_message(argv, - desc, - "validation_error::invalid_bool_value", - expected_msg); -} - - - - -//________________________________________________________________________________________ -// -// validation_error::multiple_values_not_allowed -// -//________________________________________________________________________________________ -// -// Strange exception: sole purpose seems to be catching multitoken() not associated with a vector?? -// This is surely a corner case. -// -void test_multiple_values_not_allowed_exception_msg() -{ - options_description desc; - desc.add_options() - ("cfgfile,c", value()->multitoken(), "the config file") - ("good,g", "good option") - ("output,o", value()->multitoken(), "the output file") - ; - - vector> argv; - const char* argv0[] = { "program", "-c", "file", "c", "-o", "fritz", "hugo" } ; VEC_STR_PUSH_BACK(argv, argv0); - const char* argv1[] = { "program", "--cfgfil", "file", "c", "--outpu", "fritz", "hugo" } ; VEC_STR_PUSH_BACK(argv, argv1); - const char* argv2[] = { "program", "-c", "file", "c", "-o", "fritz", "hugo"} ; VEC_STR_PUSH_BACK(argv, argv2); - const char* argv3[] = { "program", "/c", "file", "c", "/o", "fritz", "hugo"} ; VEC_STR_PUSH_BACK(argv, argv3); - const char* argv4[] = { "" } ; VEC_STR_PUSH_BACK(argv, argv4); - const char* expected_msg[5] = { - "option '--cfgfile' only takes a single argument", - "option '--cfgfile' only takes a single argument", - "option '-c' only takes a single argument", - "option '/c' only takes a single argument", - "", - }; - test_exception_message(argv, - desc, - "validation_error::multiple_values_not_allowed", - expected_msg); -} - -//________________________________________________________________________________________ -// -// validation_error::at_least_one_value_required -// -//________________________________________________________________________________________ -// -// Can't build a test case!!! -// -// -void test_at_least_one_value_required_exception_msg() -{ - - return; - - options_description desc; - desc.add_options() - ("cfgfile,c", value>()->multitoken(), "the config file") - ("other,o", value(), "other") - ; - - vector> argv; - const char* argv0[] = { "program", "-c" } ; VEC_STR_PUSH_BACK(argv, argv0); - const char* argv1[] = { "program", "--cfg" } ; VEC_STR_PUSH_BACK(argv, argv1); - const char* argv2[] = { "program", "-c" , "-o" , "name" } ; VEC_STR_PUSH_BACK(argv, argv2); - const char* argv3[] = { "program", "/c" } ; VEC_STR_PUSH_BACK(argv, argv3); - const char* argv4[] = { "" } ; VEC_STR_PUSH_BACK(argv, argv4); - const char* expected_msg[5] = { - "Unexpected exception. the required argument for option '--cfgfile' is missing", - "Unexpected exception. the required argument for option '--cfgfile' is missing", - "Unexpected exception. the required argument for option '-c' is missing", - "Unexpected exception. the required argument for option '/c' is missing", - "", - }; - test_exception_message(argv, - desc, - "validation_error::at_least_one_value_required", - expected_msg); -} - - -//________________________________________________________________________________________ -// -// required_option -// -//________________________________________________________________________________________ -void test_required_option_exception_msg() -{ - options_description desc; - desc.add_options() - ("cfgfile,c", value()->required(), "the config file") - ("good,g", "good option") - ("output,o", value()->required(), "the output file") - ; - - vector> argv; - const char* argv0[] = { "program", "-g" } ; VEC_STR_PUSH_BACK(argv, argv0); - const char* argv1[] = { "program", "--g" } ; VEC_STR_PUSH_BACK(argv, argv1); - const char* argv2[] = { "program", "-g"} ; VEC_STR_PUSH_BACK(argv, argv2); - const char* argv3[] = { "program", "/g"} ; VEC_STR_PUSH_BACK(argv, argv3); - const char* argv4[] = { "" } ; VEC_STR_PUSH_BACK(argv, argv4); - const char* expected_msg[5] = { - "the option '--cfgfile' is required but missing", - "the option '--cfgfile' is required but missing", - "the option '-c' is required but missing", - "the option '/c' is required but missing", - "the option 'cfgfile' is required but missing", - }; - test_exception_message(argv, - desc, - "required_option", - expected_msg); -} - - - - - - - - - - - - - - - - - - -/** - * Check if this is the expected exception with the right message is being thrown inside - * func -*/ -template -void test_exception(const string& test_name, const string& exception_txt, FUNC func) -{ - - try { - options_description desc; - variables_map vm; - func(desc, vm); - } - catch (EXCEPTION& e) - { - CHECK_EQUAL(test_name, e.what(), exception_txt); - return; - } - catch (std::exception& e) - { - BOOST_ERROR(string(test_name + ":\nUnexpected exception. ") + e.what() + - "\nExpected text:\n" + exception_txt + "\n\n"); - return; - } - BOOST_ERROR(test_name + ": No exception thrown. "); -} - - - -//________________________________________________________________________________________ -// -// check_reading_file -// -//________________________________________________________________________________________ -void check_reading_file(options_description& desc, variables_map& vm) -{ - desc.add_options() - ("output,o", value(), "the output file"); - - const char* file_name = "no_such_file"; - store(parse_config_file(file_name, desc, true), vm); - -} - - -//________________________________________________________________________________________ -// -// config_file_wildcard -// -//________________________________________________________________________________________ -void config_file_wildcard(options_description& desc, variables_map& vm) -{ - desc.add_options() - ("outpu*", value(), "the output file1") - ("outp*", value(), "the output file2") - ; - istringstream is("output1=whichone\noutput2=whichone\n"); - store(parse_config_file(is, desc), vm); -} - -//________________________________________________________________________________________ -// -// invalid_syntax::unrecognized_line -// -//________________________________________________________________________________________ -void unrecognized_line(options_description& desc, variables_map& vm) -{ - istringstream is("funny wierd line\n"); - store(parse_config_file(is, desc), vm); -} - -//________________________________________________________________________________________ -// -// abbreviated_options_in_config_file -// -//________________________________________________________________________________________ -void abbreviated_options_in_config_file(options_description& desc, variables_map& vm) -{ - desc.add_options()(",o", value(), "the output file"); - istringstream is("o=output.txt\n"); - store(parse_config_file(is, desc), vm); -} - - -//________________________________________________________________________________________ -// -// too_many_positional_options -// -//________________________________________________________________________________________ -void too_many_positional_options(options_description& desc, variables_map& vm) -{ - const char* argv[] = {"program", "1", "2", "3"}; - positional_options_description positional_args; - positional_args.add("two_positional_arguments", 2); - store(command_line_parser(4, argv).options(desc).positional(positional_args).run(), vm); -} - - -//________________________________________________________________________________________ -// -// invalid_command_line_style -// -//________________________________________________________________________________________ - -void test_invalid_command_line_style_exception_msg() -{ - string test_name = "invalid_command_line_style"; - using namespace command_line_style; - unsigned basic_unix_style = (allow_short - | allow_long - | allow_sticky | allow_guessing - | allow_dash_for_short); - options_description desc; - desc.add_options()("output,o", value(), "the output file"); - - vector invalid_styles; - invalid_styles.push_back(allow_short | short_allow_adjacent); - invalid_styles.push_back(allow_short | allow_dash_for_short); - invalid_styles.push_back(allow_long); - vector invalid_diagnostics; - invalid_diagnostics.push_back("boost::program_options misconfiguration: choose one " - "or other of command_line_style::allow_slash_for_short " - "(slashes) or command_line_style::allow_dash_for_short " - "(dashes) for short options."); - invalid_diagnostics.push_back("boost::program_options misconfiguration: choose one " - "or other of 'command_line_style::short_allow_next' " - "(whitespace separated arguments) or " - "command_line_style::short_allow_adjacent ('=' " - "separated arguments) for short options."); - invalid_diagnostics.push_back("boost::program_options misconfiguration: choose one " - "or other of 'command_line_style::long_allow_next' " - "(whitespace separated arguments) or " - "command_line_style::long_allow_adjacent ('=' " - "separated arguments) for long options."); - - - const char* argv[] = {"program"}; - variables_map vm; - for (unsigned ii = 0; ii < 3; ++ii) - { - bool exception_thrown = false; - try - { - store(parse_command_line(1, argv, desc, invalid_styles[ii]), vm); - } - catch (invalid_command_line_style& e) - { - string error_msg("arguments are not allowed for unabbreviated option names"); - CHECK_EQUAL(test_name, e.what(), invalid_diagnostics[ii]); - exception_thrown = true; - } - catch (std::exception& e) - { - BOOST_ERROR(string(test_name + ":\nUnexpected exception. ") + e.what() + - "\nExpected text:\n" + invalid_diagnostics[ii] + "\n"); - exception_thrown = true; - } - if (!exception_thrown) - { - BOOST_ERROR(test_name << ": No exception thrown. "); - } - } -} - - -int main(int /*ac*/, char** /*av*/) -{ - test_ambiguous_option_exception_msg(); - test_unknown_option_exception_msg(); - test_multiple_occurrences_exception_msg(); - test_missing_value_exception_msg(); - test_invalid_option_value_exception_msg(); - test_invalid_bool_value_exception_msg(); - test_multiple_values_not_allowed_exception_msg(); - test_required_option_exception_msg(); - test_at_least_one_value_required_exception_msg(); - - - string test_name; - string expected_message; - - - // check_reading_file - test_name = "check_reading_file"; - expected_message = "can not read options configuration file 'no_such_file'"; - test_exception(test_name, expected_message, check_reading_file); - - // config_file_wildcard - test_name = "config_file_wildcard"; - expected_message = "options 'outpu*' and 'outp*' will both match the same arguments from the configuration file"; - test_exception(test_name, expected_message, config_file_wildcard); - - // unrecognized_line - test_name = "unrecognized_line"; - expected_message = "the options configuration file contains an invalid line 'funny wierd line'"; - test_exception(test_name, expected_message, unrecognized_line); - - - // abbreviated_options_in_config_file - test_name = "abbreviated_options_in_config_file"; - expected_message = "abbreviated option names are not permitted in options configuration files"; - test_exception(test_name, expected_message, abbreviated_options_in_config_file); - - test_name = "too_many_positional_options"; - expected_message = "too many positional arguments have been specified on the command line"; - test_exception( - test_name, expected_message, too_many_positional_options); - - test_invalid_command_line_style_exception_msg(); - return 0; -} - - -