1
0
mirror of https://github.com/CLIUtils/CLI11.git synced 2025-05-01 21:23:52 +00:00

Tests, fix extra options after subcommand going to parent

This commit is contained in:
Henry Fredrick Schreiner 2017-02-20 13:51:33 -05:00
parent 4fca03d031
commit cfc389d4e4
5 changed files with 115 additions and 4 deletions

View File

@ -1,6 +1,6 @@
## Version 0.5 (in progress) ## Version 0.5 (in progress)
* `->ignore_case()` added to subcommands, options, and `add_set_ignore_case` (untested). Subcommand inherit setting from parent App on creation. * `->ignore_case()` added to subcommands, options, and `add_set_ignore_case`. Subcommand inherit setting from parent App on creation.
* Subcommands now can be "chained", that is, left over arguments can now include subcommands that then get parsed. Subcommands are now a list (`get_subcommands`). Added `got_subcommand(App_or_name)` to check for subcommands. (untested) * Subcommands now can be "chained", that is, left over arguments can now include subcommands that then get parsed. Subcommands are now a list (`get_subcommands`). Added `got_subcommand(App_or_name)` to check for subcommands. (untested)
* Added `.allow_extras()` to disable error on failure. Parse returns a vector of leftover options. Renamed error to `ExtrasError`, and now triggers on extra options too. (untested) * Added `.allow_extras()` to disable error on failure. Parse returns a vector of leftover options. Renamed error to `ExtrasError`, and now triggers on extra options too. (untested)
* Added `require_subcommand` to `App`, to simplify forcing subcommands. Do not "chain" with `add_subcommand`, since that is the subcommand, not the master `App`. * Added `require_subcommand` to `App`, to simplify forcing subcommands. Do not "chain" with `add_subcommand`, since that is the subcommand, not the master `App`.

View File

@ -43,7 +43,6 @@ This library was built to supply the Application object for the GooFit CUDA/OMP
* Evaluate compatibility with [ROOT](https://root.cern.ch)'s TApplication object. * Evaluate compatibility with [ROOT](https://root.cern.ch)'s TApplication object.
* Add tests: Add way for subclasses to return remaining options rather than throwing error * Add tests: Add way for subclasses to return remaining options rather than throwing error
* Chained subcommands are not tested, once a subcommand is given the rest of the options go to that subcommand, rather than allowing multiple subcommands. This is currently intentional behavior, but multiple base level subcommands, like [`Click`](http://click.pocoo.org) supports, might be considered in the future. * Chained subcommands are not tested, once a subcommand is given the rest of the options go to that subcommand, rather than allowing multiple subcommands. This is currently intentional behavior, but multiple base level subcommands, like [`Click`](http://click.pocoo.org) supports, might be considered in the future.
* Test and refine support for case insensitive set and/or subcommands?
* Throw error if `ignore_case` causes non-unique matches * Throw error if `ignore_case` causes non-unique matches
See the [changelog](./CHANGELOG.md) or [GitHub releases](https://github.com/henryiii/CLI11/releases) for details. See the [changelog](./CHANGELOG.md) or [GitHub releases](https://github.com/henryiii/CLI11/releases) for details.

View File

@ -600,12 +600,23 @@ protected:
_parse_subcommand(args); _parse_subcommand(args);
break; break;
case detail::Classifer::LONG: case detail::Classifer::LONG:
_parse_long(args); // If already parsed a subcommand, don't accept options
if(selected_subcommands.size() > 0) {
missing.emplace_back(classifer, args.back());
args.pop_back();
} else
_parse_long(args);
break; break;
case detail::Classifer::SHORT: case detail::Classifer::SHORT:
_parse_short(args); // If already parsed a subcommand, don't accept options
if(selected_subcommands.size() > 0) {
missing.emplace_back(classifer, args.back());
args.pop_back();
} else
_parse_short(args);
break; break;
case detail::Classifer::NONE: case detail::Classifer::NONE:
// Probably a positional or something for a parent (sub)command
missing.emplace_back(classifer, args.back()); missing.emplace_back(classifer, args.back());
args.pop_back(); args.pop_back();
} }

View File

@ -325,6 +325,47 @@ TEST_F(TApp, InSet) {
EXPECT_THROW(run(), CLI::ConversionError); EXPECT_THROW(run(), CLI::ConversionError);
} }
TEST_F(TApp, InIntSet) {
int choice;
app.add_set("-q,--quick", choice, {1, 2, 3});
args = {"--quick", "2"};
EXPECT_NO_THROW(run());
EXPECT_EQ(2, choice);
app.reset();
args = {"--quick", "4"};
EXPECT_THROW(run(), CLI::ConversionError);
}
TEST_F(TApp, InSetIgnoreCase) {
std::string choice;
app.add_set_ignore_case("-q,--quick", choice, {"one", "Two", "THREE"});
args = {"--quick", "One"};
EXPECT_NO_THROW(run());
EXPECT_EQ("one", choice);
app.reset();
args = {"--quick", "two"};
EXPECT_NO_THROW(run());
EXPECT_EQ("Two", choice); // Keeps caps from set
app.reset();
args = {"--quick", "ThrEE"};
EXPECT_NO_THROW(run());
EXPECT_EQ("THREE", choice); // Keeps caps from set
app.reset();
args = {"--quick", "four"};
EXPECT_THROW(run(), CLI::ConversionError);
}
TEST_F(TApp, VectorFixedString) { TEST_F(TApp, VectorFixedString) {
std::vector<std::string> strvec; std::vector<std::string> strvec;
std::vector<std::string> answer{"mystring", "mystring2", "mystring3"}; std::vector<std::string> answer{"mystring", "mystring2", "mystring3"};

View File

@ -18,6 +18,10 @@ TEST_F(TApp, BasicSubcommands) {
args = {"sub2"}; args = {"sub2"};
EXPECT_NO_THROW(run()); EXPECT_NO_THROW(run());
EXPECT_EQ(sub2, app.get_subcommands().at(0)); EXPECT_EQ(sub2, app.get_subcommands().at(0));
app.reset();
args = {"SUb2"};
EXPECT_THROW(run(), CLI::ExtrasError);
} }
@ -98,6 +102,30 @@ TEST_F(SubcommandProgram, SpareSub) {
EXPECT_THROW(run(), CLI::ExtrasError); EXPECT_THROW(run(), CLI::ExtrasError);
} }
TEST_F(SubcommandProgram, Multiple) {
args = {"-d", "start", "-ffilename", "stop"};
EXPECT_NO_THROW(run());
EXPECT_EQ(2, app.get_subcommands().size());
EXPECT_EQ(1, dummy);
EXPECT_EQ("filename", file);
}
TEST_F(SubcommandProgram, MultipleOtherOrder) {
args = {"start", "-d", "-ffilename", "stop"};
EXPECT_THROW(run(), CLI::ExtrasError);
}
TEST_F(SubcommandProgram, MultipleArgs) {
args = {"start", "stop"};
EXPECT_NO_THROW(run());
EXPECT_EQ(2, app.get_subcommands().size());
}
TEST_F(SubcommandProgram, CaseCheck) { TEST_F(SubcommandProgram, CaseCheck) {
args = {"Start"}; args = {"Start"};
EXPECT_THROW(run(), CLI::ExtrasError); EXPECT_THROW(run(), CLI::ExtrasError);
@ -117,3 +145,35 @@ TEST_F(SubcommandProgram, CaseCheck) {
EXPECT_NO_THROW(run()); EXPECT_NO_THROW(run());
} }
TEST_F(TApp, SubcomInheritCaseCheck) {
app.ignore_case();
auto sub1 = app.add_subcommand("sub1");
auto sub2 = app.add_subcommand("sub2");
EXPECT_NO_THROW(run());
EXPECT_EQ(0, app.get_subcommands().size());
app.reset();
args = {"SuB1"};
EXPECT_NO_THROW(run());
EXPECT_EQ(sub1, app.get_subcommands().at(0));
app.reset();
EXPECT_EQ(0, app.get_subcommands().size());
args = {"sUb2"};
EXPECT_NO_THROW(run());
EXPECT_EQ(sub2, app.get_subcommands().at(0));
}
TEST_F(SubcommandProgram, HelpOrder) {
args = {"-h"};
EXPECT_THROW(run(), CLI::CallForHelp);
args = {"start", "-h"};
EXPECT_THROW(run(), CLI::CallForHelp);
args = {"-h", "start"};
EXPECT_THROW(run(), CLI::CallForHelp);
}