/
BirdLeon
/
ROBLOX2016
Обзор
Документация
Войти
/
BirdLeon
/
ROBLOX2016
Код
Запросы
0
Задачи
Вики
Пакеты
0
Релизы
0
Аналитика
Безопасность
main
Library/boost/libs/program_options/test/exception_txt_test.cpp
692 строки
29 KB
PatoFlamejanteTV
full source code
19 дек 2024, 19:11
19 дек 2024, 19:11
05db15d
Код
Авторство
О чём код?
// Copyright Leo Goodstadt 2012 // 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 <boost/program_options/parsers.hpp> #include <boost/program_options/options_description.hpp> #include <boost/program_options/variables_map.hpp> #include <boost/program_options/cmdline.hpp> using namespace boost::program_options; #include <iostream> #include <sstream> #include <vector> #include <cassert> 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<typename EXCEPTION> void test_each_exception_message(const string& test_description, const vector<const char*>& 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[0], 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<typename EXCEPTION> void test_exception_message(const vector<vector<const char*> >& 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<EXCEPTION>(error_description + " -- unix", argv[0], desc, unix_style, expected_message); // long dash only expected_message = expected_message_template[1]; test_each_exception_message<EXCEPTION>(error_description + " -- long_dash", argv[1], desc, long_dash, expected_message); // short dash only expected_message = expected_message_template[2]; test_each_exception_message<EXCEPTION>(error_description + " -- short_dash", argv[2], desc, short_dash, expected_message); // short slash only expected_message = expected_message_template[3]; test_each_exception_message<EXCEPTION>(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<EXCEPTION>(error_description + " -- config_file", argv[4], desc, -1, expected_message, istrm); } } #define VEC_STR_PUSH_BACK(vec, c_array) \ vec.push_back(vector<const char*>(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<vector<const char*> > 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<invalid_option_value>(argv, desc, "invalid_option_value", expected_msg); } //________________________________________________________________________________________ // // missing_value // //________________________________________________________________________________________ void test_missing_value_exception_msg() { options_description desc; desc.add_options() ("cfgfile,e", value<string>(), "the config file") ("output,o", value<string>(), "the output file") ; vector<vector<const char*> > 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<invalid_command_line_syntax>(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<string>(), "the config file") ("cfgfile2,o", value<string>(), "the config file") ("good,g", "good option") ("output,c", value<string>(), "the output file") ("output", value<string>(), "the output file") ; vector<vector<const char*> > 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<ambiguous_option>(argv, desc, "ambiguous_option", expected_msg); } //________________________________________________________________________________________ // // multiple_occurrences // //________________________________________________________________________________________ void test_multiple_occurrences_exception_msg() { options_description desc; desc.add_options() ("cfgfile,c", value<string>(), "the configfile") ; vector<vector<const char*> > 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<multiple_occurrences>(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<vector<const char*> > 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<unknown_option>(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<vector<const char*> > 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<validation_error>(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<string>()->multitoken(), "the config file") ("good,g", "good option") ("output,o", value<string>(), "the output file") ; vector<vector<const char*> > 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<validation_error>(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<int>()->zero_tokens(), "the config file") ("other,o", value<string>(), "other") ; vector<vector<const char*> > 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<validation_error>(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<string>()->required(), "the config file") ("good,g", "good option") ("output,o", value<string>()->required(), "the output file") ; vector<vector<const char*> > 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<required_option>(argv, desc, "required_option", expected_msg); } /** * Check if this is the expected exception with the right message is being thrown inside * func */ template <typename EXCEPTION, typename FUNC> 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<string>(), "the output file"); const char* file_name = "no_such_file"; store(parse_config_file<char>(file_name, desc, true), vm); } //________________________________________________________________________________________ // // config_file_wildcard // //________________________________________________________________________________________ void config_file_wildcard(options_description& desc, variables_map& vm) { desc.add_options() ("outpu*", value<string>(), "the output file1") ("outp*", value<string>(), "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<string>(), "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<string>(), "the output file"); vector<int> 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<string> 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. "); } } } void test_empty_value_inner(options_description &opts, variables_map& vm) { positional_options_description popts; opts.add_options()("foo", value<uint32_t>()->value_name("<time>")->required()); popts.add("foo", 1); vector<string> tokens(1, ""); parsed_options parsed = command_line_parser(tokens) .style(command_line_style::default_style & ~command_line_style::allow_guessing) .options(opts) .positional(popts) .run(); store(parsed, vm); } void test_empty_value() { // Test that passing empty token for an option that requires integer does not result // in out-of-range error in error reporting code. test_exception<invalid_option_value>( "test_empty_value", "the argument for option '--foo' is invalid", test_empty_value_inner); } 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(); test_empty_value(); 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<reading_file>(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<error>(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<invalid_syntax>(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<error>(test_name, expected_message, abbreviated_options_in_config_file); test_name = "too_many_positional_options"; expected_message = "too many positional options have been specified on the command line"; test_exception<too_many_positional_options_error>( test_name, expected_message, too_many_positional_options); test_invalid_command_line_style_exception_msg(); return 0; }