From cfc389d4e46d7ed0ac65cc0849b213d19843a79a Mon Sep 17 00:00:00 2001 From: Henry Fredrick Schreiner Date: Mon, 20 Feb 2017 13:51:33 -0500 Subject: [PATCH] Tests, fix extra options after subcommand going to parent --- CHANGELOG.md | 2 +- README.md | 1 - include/CLI/App.hpp | 15 ++++++++-- tests/AppTest.cpp | 41 +++++++++++++++++++++++++++ tests/SubcommandTest.cpp | 60 ++++++++++++++++++++++++++++++++++++++++ 5 files changed, 115 insertions(+), 4 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 776a952e..cbe639e3 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,6 +1,6 @@ ## 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) * 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`. diff --git a/README.md b/README.md index 9a0d7e07..7a6d2966 100644 --- a/README.md +++ b/README.md @@ -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. * 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. -* Test and refine support for case insensitive set and/or subcommands? * 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. diff --git a/include/CLI/App.hpp b/include/CLI/App.hpp index c501b7e2..5e4d510e 100644 --- a/include/CLI/App.hpp +++ b/include/CLI/App.hpp @@ -600,12 +600,23 @@ protected: _parse_subcommand(args); break; 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; 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; case detail::Classifer::NONE: + // Probably a positional or something for a parent (sub)command missing.emplace_back(classifer, args.back()); args.pop_back(); } diff --git a/tests/AppTest.cpp b/tests/AppTest.cpp index a90b2f20..cc0194b8 100644 --- a/tests/AppTest.cpp +++ b/tests/AppTest.cpp @@ -325,6 +325,47 @@ TEST_F(TApp, InSet) { 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) { std::vector strvec; std::vector answer{"mystring", "mystring2", "mystring3"}; diff --git a/tests/SubcommandTest.cpp b/tests/SubcommandTest.cpp index 4756619e..7fbd0f8c 100644 --- a/tests/SubcommandTest.cpp +++ b/tests/SubcommandTest.cpp @@ -18,6 +18,10 @@ TEST_F(TApp, BasicSubcommands) { args = {"sub2"}; EXPECT_NO_THROW(run()); 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); } +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) { args = {"Start"}; EXPECT_THROW(run(), CLI::ExtrasError); @@ -117,3 +145,35 @@ TEST_F(SubcommandProgram, CaseCheck) { 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); +}