diff --git a/test/options.cpp b/test/options.cpp index 7ef5aca..3adf75e 100644 --- a/test/options.cpp +++ b/test/options.cpp @@ -277,6 +277,113 @@ TEST_CASE("Providing options values via equal sign", "[options]") } } +TEST_CASE("Valid/Invalid Option names", "[options]") +{ + const char prog_name[] = "test_invalid_opt_names"; + std::vector> invalid_opts = { + {"Equals short name", "="}, + {"Dash short name", "-"}, + {"Long name starts with =", "a,=abcd"}, + {"Long name starts with dash", "a,-abcd"}, + {"Whitespace as name", " "}, + {"Name is a space", "a, "}, + {"Only comma delimiter given", ","}, + {"Leading comma", ",a"}, + {"Trailing comma after names", "a,ab,"}, + {"Double comma", "a,,ab"}, + {"Empty option name string", ""}, + {"Control character in name", "\x03"}, + {"Tab inside option name", "a,ab,\tac"}, + {"Equals inside option name", "a,ab,ac,ab=cd"}, + {"Two simple option names", "a,b"}, + {"Duplicate option names", "ab,ab"}, + }; + + std::vector> valid_opts = { + {"Basic", "a,ab"}, + {"Spaces", "a, ab, xyz"}, + {"Arbitrary characters", "#,%%%,/><>?"}, + }; + + for(const auto& t: invalid_opts) { + SECTION(t.first){ + cxxopts::Options options(prog_name, " - Option names as invalid characters"); + auto option_adder = options.add_options(); + CHECK_THROWS(option_adder(t.second, "description", cxxopts::value())); + } + } + for(const auto& t: valid_opts) { + SECTION(t.first){ + cxxopts::Options options(prog_name, " - Option names as invalid characters"); + auto option_adder = options.add_options(); + CHECK_NOTHROW(option_adder(t.second, "description", cxxopts::value())); + } + } +} + +TEST_CASE("Option names as arbitrary characters", "[options]") +{ + const char prog_name[] = "test_name_chars"; + + struct testcases + { + std::string name; + std::vector opt_names; + Argv argv; + std::vector> expValues; + bool parseException; + } tests[] = { + { + "Arbitrary chars", + {"#,^^","$$$"}, + Argv{prog_name, "-#", "abc", "--$$$=@#$$"}, + {{"#", "abc"}, {"$$$", "@#$$"}}, + false, + }, + { + "Arbitrary chars 2", + {"*, ab-cd","ab_cd"}, + Argv{prog_name, "--ab-cd", "xyz","--ab_cd={}()"}, + {{"ab-cd", "xyz"}, {"ab_cd", "{}()"}}, + false, + }, + { + "Arbitrary chars 3", + {"."}, + Argv{prog_name, "-.=.."}, + {{".", ".."}}, + false, + }, + { + "Arbitrary chars 4", + {"@",":","?","[","}","*","~","!"}, + Argv{prog_name, "-@:?[}*~!"}, + {}, + false, + } + }; + + for(const auto& tc : tests) { + SECTION(tc.name){ + cxxopts::Options options(prog_name, " - Option names as arbitrary characters"); + auto option_adder = options.add_options(); + for(const auto& opt_name: tc.opt_names) { + option_adder(opt_name, "description", cxxopts::value()); + } + if(tc.parseException) { + CHECK_THROWS(options.parse(tc.argv.argc(), tc.argv.argv())); + continue; + } + auto result = options.parse(tc.argv.argc(), tc.argv.argv()); + for (const auto& p : tc.expValues) { + CHECK(result[p.first].as() == p.second); + } + + } + } +} + + TEST_CASE("No positional", "[positional]") { cxxopts::Options options("test_no_positional", @@ -951,7 +1058,7 @@ TEST_CASE("Allow bad short syntax", "[options]") { Argv av({ "--ab?", - "-?b?#@" + "-=?b?#@" }); auto** argv = av.argv(); @@ -965,7 +1072,7 @@ TEST_CASE("Allow bad short syntax", "[options]") { options.allow_unrecognised_options(); CHECK_NOTHROW(options.parse(argc, argv)); REQUIRE(argc == 2); - CHECK_THAT(argv[1], Catch::Equals("-?b?#@")); + CHECK_THAT(argv[1], Catch::Equals("-=?b?#@")); } }