1
0
mirror of https://github.com/CLIUtils/CLI11.git synced 2025-04-29 12:13:52 +00:00

Subcommand parse order corrected and preserved

This commit is contained in:
Henry Fredrick Schreiner 2017-11-21 13:10:40 -05:00 committed by Henry Schreiner
parent 512b3604e2
commit 9acaeebd1e
2 changed files with 102 additions and 8 deletions

View File

@ -102,6 +102,9 @@ class App {
/// This is a list of pointers to options with the original parse order
std::vector<Option *> parse_order_;
/// This is a list of the subcommands collected, in order
std::vector<App *> parsed_subcommands_;
///@}
/// @name Subcommands
///@{
@ -732,6 +735,7 @@ class App {
parsed_ = false;
missing_.clear();
parsed_subcommands_.clear();
for(const Option_p &opt : options_) {
opt->clear();
@ -755,13 +759,18 @@ class App {
throw OptionNotFound(name);
}
/// Get a subcommand pointer list to the currently selected subcommands (after parsing)
std::vector<App *> get_subcommands() const {
std::vector<App *> subcomms;
for(const App_p &subcomptr : subcommands_)
if(subcomptr->parsed_)
subcomms.push_back(subcomptr.get());
return subcomms;
/// Get a subcommand pointer list to the currently selected subcommands (after parsing by default, in command line
/// order)
std::vector<App *> get_subcommands(bool parsed = true) const {
if(parsed) {
return parsed_subcommands_;
} else {
std::vector<App *> subcomms(subcommands_.size());
std::transform(std::begin(subcommands_), std::end(subcommands_), std::begin(subcomms), [](const App_p &v) {
return v.get();
});
return subcomms;
}
}
/// Check to see if given subcommand was selected
@ -952,7 +961,7 @@ class App {
miss_list.push_back(std::get<1>(miss));
}
if(recurse) {
for(const App_p &sub : subcommands_) {
for(const App *sub : parsed_subcommands_) {
std::vector<std::string> output = sub->remaining(recurse);
std::copy(std::begin(output), std::end(output), std::back_inserter(miss_list));
}
@ -1260,6 +1269,9 @@ class App {
for(const App_p &com : subcommands_) {
if(com->check_name(args.back())) {
args.pop_back();
if(std::find(std::begin(parsed_subcommands_), std::end(parsed_subcommands_), com.get()) ==
std::end(parsed_subcommands_))
parsed_subcommands_.push_back(com.get());
com->_parse(args);
return;
}

View File

@ -27,6 +27,7 @@ TEST_F(TApp, BasicSubcommands) {
args = {"sub2"};
run();
EXPECT_EQ((size_t)1, app.get_subcommands().size());
EXPECT_EQ(sub2, app.get_subcommands().at(0));
app.reset();
@ -560,3 +561,84 @@ TEST_F(SubcommandProgram, Groups) {
EXPECT_THAT(help, HasSubstr("More Commands:"));
EXPECT_THAT(help, Not(HasSubstr("Subcommands:")));
}
TEST_F(SubcommandProgram, ExtrasErrors) {
args = {"one", "two", "start", "three", "four"};
EXPECT_THROW(run(), CLI::ExtrasError);
app.reset();
args = {"start", "three", "four"};
EXPECT_THROW(run(), CLI::ExtrasError);
app.reset();
args = {"one", "two"};
EXPECT_THROW(run(), CLI::ExtrasError);
app.reset();
}
TEST_F(SubcommandProgram, OrderedExtras) {
app.allow_extras();
args = {"one", "two", "start", "three", "four"};
EXPECT_THROW(run(), CLI::ExtrasError);
app.reset();
start->allow_extras();
run();
EXPECT_EQ(app.remaining(), std::vector<std::string>({"one", "two"}));
EXPECT_EQ(start->remaining(), std::vector<std::string>({"three", "four"}));
EXPECT_EQ(app.remaining(true), std::vector<std::string>({"one", "two", "three", "four"}));
app.reset();
args = {"one", "two", "start", "three", "--", "four"};
run();
EXPECT_EQ(app.remaining(), std::vector<std::string>({"one", "two"}));
EXPECT_EQ(start->remaining(), std::vector<std::string>({"three", "--", "four"}));
EXPECT_EQ(app.remaining(true), std::vector<std::string>({"one", "two", "three", "--", "four"}));
}
TEST_F(SubcommandProgram, MixedOrderExtras) {
app.allow_extras();
start->allow_extras();
stop->allow_extras();
args = {"one", "two", "start", "three", "four", "stop", "five", "six"};
run();
EXPECT_EQ(app.remaining(), std::vector<std::string>({"one", "two"}));
EXPECT_EQ(start->remaining(), std::vector<std::string>({"three", "four"}));
EXPECT_EQ(stop->remaining(), std::vector<std::string>({"five", "six"}));
EXPECT_EQ(app.remaining(true), std::vector<std::string>({"one", "two", "three", "four", "five", "six"}));
app.reset();
args = {"one", "two", "stop", "three", "four", "start", "five", "six"};
run();
EXPECT_EQ(app.remaining(), std::vector<std::string>({"one", "two"}));
EXPECT_EQ(stop->remaining(), std::vector<std::string>({"three", "four"}));
EXPECT_EQ(start->remaining(), std::vector<std::string>({"five", "six"}));
EXPECT_EQ(app.remaining(true), std::vector<std::string>({"one", "two", "three", "four", "five", "six"}));
}
TEST_F(SubcommandProgram, CallbackOrder) {
std::vector<int> callback_order;
start->set_callback([&callback_order]() { callback_order.push_back(1); });
stop->set_callback([&callback_order]() { callback_order.push_back(2); });
args = {"start", "stop"};
run();
EXPECT_EQ(callback_order, std::vector<int>({1, 2}));
app.reset();
callback_order.clear();
args = {"stop", "start"};
run();
EXPECT_EQ(callback_order, std::vector<int>({2, 1}));
}