Commit cf4f60862169407902696801a6066dd0946f3a5e
1 parent
af79da5d
Adding check for invalid positionals
Showing
3 changed files
with
37 additions
and
1 deletions
include/CLI/App.hpp
| ... | ... | @@ -198,7 +198,7 @@ public: |
| 198 | 198 | /// |
| 199 | 199 | /// For example, |
| 200 | 200 | /// |
| 201 | - /// std::string filename | |
| 201 | + /// std::string filename; | |
| 202 | 202 | /// program.add_option("filename", filename, "description of filename"); |
| 203 | 203 | /// |
| 204 | 204 | Option* add_option( |
| ... | ... | @@ -474,6 +474,7 @@ public: |
| 474 | 474 | /// The real work is done here. Expects a reversed vector. |
| 475 | 475 | /// Changes the vector to the remaining options. |
| 476 | 476 | std::vector<std::string>& parse(std::vector<std::string> &args) { |
| 477 | + _validate(); | |
| 477 | 478 | _parse(args); |
| 478 | 479 | run_callback(); |
| 479 | 480 | return args; |
| ... | ... | @@ -678,6 +679,18 @@ public: |
| 678 | 679 | |
| 679 | 680 | protected: |
| 680 | 681 | |
| 682 | + /// Check the options to make sure there are no conficts. | |
| 683 | + /// | |
| 684 | + /// Currenly checks to see if mutiple positionals exist with -1 args | |
| 685 | + void _validate() const { | |
| 686 | + auto count = std::count_if(std::begin(options_), std::end(options_), | |
| 687 | + [](const Option_p& opt){return opt->get_expected() == -1 && opt->get_positional();}); | |
| 688 | + if(count > 1) | |
| 689 | + throw InvalidError(name_ + ": Too many positional arguments with unlimited expected args"); | |
| 690 | + for(const App_p& app : subcommands_) | |
| 691 | + app->_validate(); | |
| 692 | + } | |
| 693 | + | |
| 681 | 694 | |
| 682 | 695 | /// Return missing from the master |
| 683 | 696 | missing_t* missing() { | ... | ... |
include/CLI/Error.hpp
| ... | ... | @@ -100,6 +100,11 @@ struct ExtrasError : public ParseError { |
| 100 | 100 | ExtrasError(std::string name) : ParseError("ExtrasError", name, 6) {} |
| 101 | 101 | }; |
| 102 | 102 | |
| 103 | +/// Thrown when validation fails before parsing | |
| 104 | +struct InvalidError : public ParseError { | |
| 105 | + InvalidError(std::string name) : ParseError("InvalidError", name, 15) {} | |
| 106 | +}; | |
| 107 | + | |
| 103 | 108 | /// This is just a safety check to verify selection and parsing match |
| 104 | 109 | struct HorribleError : public ParseError { |
| 105 | 110 | HorribleError(std::string name) : ParseError("HorribleError", "(You should never see this error) " + name, 7) {} | ... | ... |
tests/CreationTest.cpp
| ... | ... | @@ -35,6 +35,24 @@ TEST_F(TApp, AddingExistingWithCaseAfter2) { |
| 35 | 35 | EXPECT_THROW(cat->ignore_case(), CLI::OptionAlreadyAdded); |
| 36 | 36 | } |
| 37 | 37 | |
| 38 | +TEST_F(TApp, AddingMultipleInfPositionals) { | |
| 39 | + std::vector<std::string> one, two; | |
| 40 | + app.add_option("one", one); | |
| 41 | + app.add_option("two", two); | |
| 42 | + | |
| 43 | + EXPECT_THROW(run(), CLI::InvalidError); | |
| 44 | +} | |
| 45 | + | |
| 46 | + | |
| 47 | +TEST_F(TApp, AddingMultipleInfPositionalsSubcom) { | |
| 48 | + std::vector<std::string> one, two; | |
| 49 | + CLI::App* below = app.add_subcommand("below"); | |
| 50 | + below->add_option("one", one); | |
| 51 | + below->add_option("two", two); | |
| 52 | + | |
| 53 | + EXPECT_THROW(run(), CLI::InvalidError); | |
| 54 | +} | |
| 55 | + | |
| 38 | 56 | TEST_F(TApp, MultipleSubcomMatching) { |
| 39 | 57 | app.add_subcommand("first"); |
| 40 | 58 | app.add_subcommand("second"); | ... | ... |