/
BirdLeon
/
ROBLOX2016
Обзор
Документация
Войти
/
BirdLeon
/
ROBLOX2016
Код
Запросы
0
Задачи
Вики
Пакеты
0
Релизы
0
Аналитика
Безопасность
main
Library/boost/libs/program_options/test/cmdline_test.cpp
656 строк
19 KB
PatoFlamejanteTV
full source code
19 дек 2024, 19:11
19 дек 2024, 19:11
05db15d
Код
Авторство
О чём код?
// Copyright Vladimir Prus 2002-2004. // 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/cmdline.hpp> #include <boost/program_options/options_description.hpp> #include <boost/program_options/detail/cmdline.hpp> using namespace boost::program_options; using boost::program_options::detail::cmdline; #include <iostream> #include <sstream> #include <vector> #include <cassert> using namespace std; #include "minitest.hpp" /* To facilitate testing, declare a number of error codes. Otherwise, we'd have to specify the type of exception that should be thrown. */ const int s_success = 0; const int s_unknown_option = 1; const int s_ambiguous_option = 2; const int s_long_not_allowed = 3; const int s_long_adjacent_not_allowed = 4; const int s_short_adjacent_not_allowed = 5; const int s_empty_adjacent_parameter = 6; const int s_missing_parameter = 7; const int s_extra_parameter = 8; const int s_unrecognized_line = 9; int translate_syntax_error_kind(invalid_command_line_syntax::kind_t k) { invalid_command_line_syntax::kind_t table[] = { invalid_command_line_syntax::long_not_allowed, invalid_command_line_syntax::long_adjacent_not_allowed, invalid_command_line_syntax::short_adjacent_not_allowed, invalid_command_line_syntax::empty_adjacent_parameter, invalid_command_line_syntax::missing_parameter, invalid_command_line_syntax::extra_parameter, invalid_command_line_syntax::unrecognized_line }; invalid_command_line_syntax::kind_t *b, *e, *i; b = table; e = table + sizeof(table)/sizeof(table[0]); i = std::find(b, e, k); assert(i != e); return std::distance(b, i) + 3; } struct test_case { const char* input; int expected_status; const char* expected_result; }; /* Parses the syntax description in 'syntax' and initialized 'cmd' accordingly' The "boost::program_options" in parameter type is needed because CW9 has std::detail and it causes an ambiguity. */ void apply_syntax(options_description& desc, const char* syntax) { string s; stringstream ss; ss << syntax; while(ss >> s) { value_semantic* v = 0; if (*(s.end()-1) == '=') { v = value<string>(); s.resize(s.size()-1); } else if (*(s.end()-1) == '?') { v = value<string>()->implicit_value("default"); s.resize(s.size()-1); } else if (*(s.end()-1) == '*') { v = value<vector<string> >()->multitoken(); s.resize(s.size()-1); } else if (*(s.end()-1) == '+') { v = value<vector<string> >()->multitoken(); s.resize(s.size()-1); } if (v) { desc.add_options() (s.c_str(), v, ""); } else { desc.add_options() (s.c_str(), ""); } } } void test_cmdline(const char* syntax, command_line_style::style_t style, const test_case* cases) { for (int i = 0; cases[i].input; ++i) { // Parse input vector<string> xinput; { string s; stringstream ss; ss << cases[i].input; while (ss >> s) { xinput.push_back(s); } } options_description desc; apply_syntax(desc, syntax); cmdline cmd(xinput); cmd.style(style); cmd.set_options_description(desc); string result; int status = 0; try { vector<option> options = cmd.run(); for(unsigned j = 0; j < options.size(); ++j) { option opt = options[j]; if (opt.position_key != -1) { if (!result.empty()) result += " "; result += opt.value[0]; } else { if (!result.empty()) result += " "; result += opt.string_key + ":"; for (size_t k = 0; k < opt.value.size(); ++k) { if (k != 0) result += "-"; result += opt.value[k]; } } } } catch(unknown_option&) { status = s_unknown_option; } catch(ambiguous_option&) { status = s_ambiguous_option; } catch(invalid_command_line_syntax& e) { status = translate_syntax_error_kind(e.kind()); } BOOST_CHECK_EQUAL(status, cases[i].expected_status); BOOST_CHECK_EQUAL(result, cases[i].expected_result); } } void test_long_options() { using namespace command_line_style; cmdline::style_t style = cmdline::style_t( allow_long | long_allow_adjacent); test_case test_cases1[] = { // Test that long options are recognized and everything else // is treated like arguments {"--foo foo -123 /asd", s_success, "foo: foo -123 /asd"}, // Unknown option {"--unk", s_unknown_option, ""}, // Test that abbreviated names do not work {"--fo", s_unknown_option, ""}, // Test for disallowed parameter {"--foo=13", s_extra_parameter, ""}, // Test option with required parameter {"--bar=", s_empty_adjacent_parameter, ""}, {"--bar", s_missing_parameter, ""}, {"--bar=123", s_success, "bar:123"}, {0, 0, 0} }; test_cmdline("foo bar=", style, test_cases1); style = cmdline::style_t( allow_long | long_allow_next); test_case test_cases2[] = { {"--bar 10", s_success, "bar:10"}, {"--bar", s_missing_parameter, ""}, // Since --bar accepts a parameter, --foo is // considered a value, even though it looks like // an option. {"--bar --foo", s_success, "bar:--foo"}, {0, 0, 0} }; test_cmdline("foo bar=", style, test_cases2); style = cmdline::style_t( allow_long | long_allow_adjacent | long_allow_next); test_case test_cases3[] = { {"--bar=10", s_success, "bar:10"}, {"--bar 11", s_success, "bar:11"}, {0, 0, 0} }; test_cmdline("foo bar=", style, test_cases3); style = cmdline::style_t( allow_long | long_allow_adjacent | long_allow_next | case_insensitive); // Test case insensitive style. // Note that option names are normalized to lower case. test_case test_cases4[] = { {"--foo", s_success, "foo:"}, {"--Foo", s_success, "foo:"}, {"--bar=Ab", s_success, "bar:Ab"}, {"--Bar=ab", s_success, "bar:ab"}, {"--giz", s_success, "Giz:"}, {0, 0, 0} }; test_cmdline("foo bar= baz? Giz", style, test_cases4); } void test_short_options() { using namespace command_line_style; cmdline::style_t style; style = cmdline::style_t( allow_short | allow_dash_for_short | short_allow_adjacent); test_case test_cases1[] = { {"-d d /bar", s_success, "-d: d /bar"}, // This is treated as error when long options are disabled {"--foo", s_success, "--foo"}, {"-d13", s_extra_parameter, ""}, {"-f14", s_success, "-f:14"}, {"-g -f1", s_success, "-g: -f:1"}, {"-f", s_missing_parameter, ""}, {0, 0, 0} }; test_cmdline(",d ,f= ,g", style, test_cases1); style = cmdline::style_t( allow_short | allow_dash_for_short | short_allow_next); test_case test_cases2[] = { {"-f 13", s_success, "-f:13"}, {"-f -13", s_success, "-f:-13"}, {"-f", s_missing_parameter, ""}, {"-f /foo", s_success, "-f:/foo"}, {"-f -d", s_missing_parameter, ""}, {0, 0, 0} }; test_cmdline(",d ,f=", style, test_cases2); style = cmdline::style_t( allow_short | short_allow_next | allow_dash_for_short | short_allow_adjacent); test_case test_cases3[] = { {"-f10", s_success, "-f:10"}, {"-f 10", s_success, "-f:10"}, {"-f -d", s_missing_parameter, ""}, {0, 0, 0} }; test_cmdline(",d ,f=", style, test_cases3); style = cmdline::style_t( allow_short | short_allow_next | allow_dash_for_short | short_allow_adjacent | allow_sticky); test_case test_cases4[] = { {"-de", s_success, "-d: -e:"}, {"-df10", s_success, "-d: -f:10"}, // FIXME: review //{"-d12", s_extra_parameter, ""}, {"-f12", s_success, "-f:12"}, {"-fe", s_success, "-f:e"}, {0, 0, 0} }; test_cmdline(",d ,f= ,e", style, test_cases4); } void test_dos_options() { using namespace command_line_style; cmdline::style_t style; style = cmdline::style_t( allow_short | allow_slash_for_short | short_allow_adjacent); test_case test_cases1[] = { {"/d d -bar", s_success, "-d: d -bar"}, {"--foo", s_success, "--foo"}, {"/d13", s_extra_parameter, ""}, {"/f14", s_success, "-f:14"}, {"/f", s_missing_parameter, ""}, {0, 0, 0} }; test_cmdline(",d ,f=", style, test_cases1); style = cmdline::style_t( allow_short | allow_slash_for_short | short_allow_next | short_allow_adjacent | allow_sticky); test_case test_cases2[] = { {"/de", s_extra_parameter, ""}, {"/fe", s_success, "-f:e"}, {0, 0, 0} }; test_cmdline(",d ,f= ,e", style, test_cases2); } void test_disguised_long() { using namespace command_line_style; cmdline::style_t style; style = cmdline::style_t( allow_short | short_allow_adjacent | allow_dash_for_short | short_allow_next | allow_long_disguise | long_allow_adjacent); test_case test_cases1[] = { {"-foo -f", s_success, "foo: foo:"}, {"-goo=x -gy", s_success, "goo:x goo:y"}, {"-bee=x -by", s_success, "bee:x bee:y"}, {0, 0, 0} }; test_cmdline("foo,f goo,g= bee,b?", style, test_cases1); style = cmdline::style_t(style | allow_slash_for_short); test_case test_cases2[] = { {"/foo -f", s_success, "foo: foo:"}, {"/goo=x", s_success, "goo:x"}, {0, 0, 0} }; test_cmdline("foo,f goo,g= bee,b?", style, test_cases2); } void test_guessing() { using namespace command_line_style; cmdline::style_t style; style = cmdline::style_t( allow_short | short_allow_adjacent | allow_dash_for_short | allow_long | long_allow_adjacent | allow_guessing | allow_long_disguise); test_case test_cases1[] = { {"--opt1", s_success, "opt123:"}, {"--opt", s_ambiguous_option, ""}, {"--f=1", s_success, "foo:1"}, {"-far", s_success, "foo:ar"}, {0, 0, 0} }; test_cmdline("opt123 opt56 foo,f=", style, test_cases1); test_case test_cases2[] = { {"--fname file --fname2 file2", s_success, "fname: file fname2: file2"}, {"--fnam file --fnam file2", s_ambiguous_option, ""}, {"--fnam file --fname2 file2", s_ambiguous_option, ""}, {"--fname2 file2 --fnam file", s_ambiguous_option, ""}, {0, 0, 0} }; test_cmdline("fname fname2", style, test_cases2); } void test_arguments() { using namespace command_line_style; cmdline::style_t style; style = cmdline::style_t( allow_short | allow_long | allow_dash_for_short | short_allow_adjacent | long_allow_adjacent); test_case test_cases1[] = { {"-f file -gx file2", s_success, "-f: file -g:x file2"}, {"-f - -gx - -- -e", s_success, "-f: - -g:x - -e"}, {0, 0, 0} }; test_cmdline(",f ,g= ,e", style, test_cases1); // "--" should stop options regardless of whether long options are // allowed or not. style = cmdline::style_t( allow_short | short_allow_adjacent | allow_dash_for_short); test_case test_cases2[] = { {"-f - -gx - -- -e", s_success, "-f: - -g:x - -e"}, {0, 0, 0} }; test_cmdline(",f ,g= ,e", style, test_cases2); } void test_prefix() { using namespace command_line_style; cmdline::style_t style; style = cmdline::style_t( allow_short | allow_long | allow_dash_for_short | short_allow_adjacent | long_allow_adjacent ); test_case test_cases1[] = { {"--foo.bar=12", s_success, "foo.bar:12"}, {0, 0, 0} }; test_cmdline("foo*=", style, test_cases1); } pair<string, string> at_option_parser(string const&s) { if ('@' == s[0]) return std::make_pair(string("response-file"), s.substr(1)); else return pair<string, string>(); } pair<string, string> at_option_parser_broken(string const&s) { if ('@' == s[0]) return std::make_pair(string("some garbage"), s.substr(1)); else return pair<string, string>(); } void test_additional_parser() { options_description desc; desc.add_options() ("response-file", value<string>(), "response file") ("foo", value<int>(), "foo") ("bar,baz", value<int>(), "bar") ; vector<string> input; input.push_back("@config"); input.push_back("--foo=1"); input.push_back("--baz=11"); cmdline cmd(input); cmd.set_options_description(desc); cmd.set_additional_parser(at_option_parser); vector<option> result = cmd.run(); BOOST_REQUIRE(result.size() == 3); BOOST_CHECK_EQUAL(result[0].string_key, "response-file"); BOOST_CHECK_EQUAL(result[0].value[0], "config"); BOOST_CHECK_EQUAL(result[1].string_key, "foo"); BOOST_CHECK_EQUAL(result[1].value[0], "1"); BOOST_CHECK_EQUAL(result[2].string_key, "bar"); BOOST_CHECK_EQUAL(result[2].value[0], "11"); // Test that invalid options returned by additional style // parser are detected. cmdline cmd2(input); cmd2.set_options_description(desc); cmd2.set_additional_parser(at_option_parser_broken); BOOST_CHECK_THROW(cmd2.run(), unknown_option); } vector<option> at_option_parser2(vector<string>& args) { vector<option> result; if ('@' == args[0][0]) { // Simulate reading the response file. result.push_back(option("foo", vector<string>(1, "1"))); result.push_back(option("bar", vector<string>(1, "1"))); args.erase(args.begin()); } return result; } void test_style_parser() { options_description desc; desc.add_options() ("foo", value<int>(), "foo") ("bar", value<int>(), "bar") ; vector<string> input; input.push_back("@config"); cmdline cmd(input); cmd.set_options_description(desc); cmd.extra_style_parser(at_option_parser2); vector<option> result = cmd.run(); BOOST_REQUIRE(result.size() == 2); BOOST_CHECK_EQUAL(result[0].string_key, "foo"); BOOST_CHECK_EQUAL(result[0].value[0], "1"); BOOST_CHECK_EQUAL(result[1].string_key, "bar"); BOOST_CHECK_EQUAL(result[1].value[0], "1"); } void test_unregistered() { // Check unregisted option when no options are registed at all. options_description desc; vector<string> input; input.push_back("--foo=1"); input.push_back("--bar"); input.push_back("1"); input.push_back("-b"); input.push_back("-biz"); cmdline cmd(input); cmd.set_options_description(desc); cmd.allow_unregistered(); vector<option> result = cmd.run(); BOOST_REQUIRE(result.size() == 5); // --foo=1 BOOST_CHECK_EQUAL(result[0].string_key, "foo"); BOOST_CHECK_EQUAL(result[0].unregistered, true); BOOST_CHECK_EQUAL(result[0].value[0], "1"); // --bar BOOST_CHECK_EQUAL(result[1].string_key, "bar"); BOOST_CHECK_EQUAL(result[1].unregistered, true); BOOST_CHECK(result[1].value.empty()); // '1' is considered a positional option, not a value to // --bar BOOST_CHECK(result[2].string_key.empty()); BOOST_CHECK(result[2].position_key == 0); BOOST_CHECK_EQUAL(result[2].unregistered, false); BOOST_CHECK_EQUAL(result[2].value[0], "1"); // -b BOOST_CHECK_EQUAL(result[3].string_key, "-b"); BOOST_CHECK_EQUAL(result[3].unregistered, true); BOOST_CHECK(result[3].value.empty()); // -biz BOOST_CHECK_EQUAL(result[4].string_key, "-b"); BOOST_CHECK_EQUAL(result[4].unregistered, true); BOOST_CHECK_EQUAL(result[4].value[0], "iz"); // Check sticky short options together with unregisted options. desc.add_options() ("help,h", "") ("magic,m", value<string>(), "") ; input.clear(); input.push_back("-hc"); input.push_back("-mc"); cmdline cmd2(input); cmd2.set_options_description(desc); cmd2.allow_unregistered(); result = cmd2.run(); BOOST_REQUIRE(result.size() == 3); BOOST_CHECK_EQUAL(result[0].string_key, "help"); BOOST_CHECK_EQUAL(result[0].unregistered, false); BOOST_CHECK(result[0].value.empty()); BOOST_CHECK_EQUAL(result[1].string_key, "-c"); BOOST_CHECK_EQUAL(result[1].unregistered, true); BOOST_CHECK(result[1].value.empty()); BOOST_CHECK_EQUAL(result[2].string_key, "magic"); BOOST_CHECK_EQUAL(result[2].unregistered, false); BOOST_CHECK_EQUAL(result[2].value[0], "c"); // CONSIDER: // There's a corner case: // -foo // when 'allow_long_disguise' is set. Should this be considered // disguised long option 'foo' or short option '-f' with value 'oo'? // It's not clear yet, so I'm leaving the decision till later. } void test_implicit_value() { using namespace command_line_style; cmdline::style_t style; style = cmdline::style_t( allow_long | long_allow_adjacent ); test_case test_cases1[] = { // 'bar' does not even look like option, so is consumed {"--foo bar", s_success, "foo:bar"}, // '--bar' looks like option, and such option exists, so we don't consume this token {"--foo --bar", s_success, "foo: bar:"}, // '--biz' looks like option, but does not match any existing one. // Presently this results in parse error, since // (1) in cmdline.cpp:finish_option, we only consume following tokens if they are // requires // (2) in cmdline.cpp:run, we let options consume following positional options // For --biz, an exception is thrown between 1 and 2. // We might want to fix that in future. {"--foo --biz", s_unknown_option, ""}, {0, 0, 0} }; test_cmdline("foo? bar?", style, test_cases1); } int main(int /*ac*/, char** /*av*/) { test_long_options(); test_short_options(); test_dos_options(); test_disguised_long(); test_guessing(); test_arguments(); test_prefix(); test_additional_parser(); test_style_parser(); test_unregistered(); test_implicit_value(); return 0; }