diff --git a/include/CLI/App.hpp b/include/CLI/App.hpp index 082a4f80..c2f9d3ca 100644 --- a/include/CLI/App.hpp +++ b/include/CLI/App.hpp @@ -857,7 +857,7 @@ class App { for(const App_p &com : subcommands_) if(com->check_name(current)) return true; - if(parent_ != nullptr && fallthrough_) + if(parent_ != nullptr) return parent_->_valid_subcommand(current); else return false; @@ -1093,7 +1093,7 @@ class App { } } - if(parent_ != nullptr)// TODO && fallthrough_) + if(parent_ != nullptr && fallthrough_) return parent_->_parse_positional(args); else { args.pop_back(); @@ -1113,6 +1113,8 @@ class App { /// /// Unlike the others, this one will always allow fallthrough void _parse_subcommand(std::vector &args) { + if(_count_remaining_required_positionals() > 0) + return _parse_positional(args); for(const App_p &com : subcommands_) { if(com->check_name(args.back())) { args.pop_back(); diff --git a/tests/SubcommandTest.cpp b/tests/SubcommandTest.cpp index c2753705..46372b80 100644 --- a/tests/SubcommandTest.cpp +++ b/tests/SubcommandTest.cpp @@ -74,6 +74,55 @@ TEST_F(TApp, MultiSubFallthrough) { EXPECT_THROW(app.got_subcommand("sub3"), CLI::OptionNotFound); } +TEST_F(TApp, RequiredAndSubcoms) { // #23 + + std::string baz; + app.add_option("baz", baz, "Baz Description", true)->required(); + auto foo = app.add_subcommand("foo"); + auto bar = app.add_subcommand("bar"); + + args = {"bar", "foo"}; + EXPECT_NO_THROW(run()); + EXPECT_TRUE(*foo); + EXPECT_FALSE(*bar); + EXPECT_EQ(baz, "bar"); + + app.reset(); + args = {"foo"}; + EXPECT_NO_THROW(run()); + EXPECT_FALSE(*foo); + EXPECT_EQ(baz, "foo"); + + app.reset(); + args = {"foo", "foo"}; + EXPECT_NO_THROW(run()); + EXPECT_TRUE(*foo); + EXPECT_EQ(baz, "foo"); + + app.reset(); + args = {"foo", "other"}; + EXPECT_THROW(run(), CLI::ParseError); +} + +TEST_F(TApp, RequiredAndSubcomFallthrough) { + + std::string baz; + app.add_option("baz", baz, "Baz Description", true)->required(); + app.add_subcommand("foo"); + auto bar = app.add_subcommand("bar"); + app.fallthrough(); + + args = {"other", "bar"}; + run(); + EXPECT_TRUE(bar); + EXPECT_EQ(baz, "other"); + + app.reset(); + args = {"bar", "other2"}; + EXPECT_THROW(run(), CLI::ParseError); // RequiredError or ExtrasError (actual) + +} + TEST_F(TApp, Callbacks) { auto sub1 = app.add_subcommand("sub1"); sub1->set_callback([]() { throw CLI::Success(); });