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,7 +198,7 @@ public: | ||
| 198 | /// | 198 | /// |
| 199 | /// For example, | 199 | /// For example, |
| 200 | /// | 200 | /// |
| 201 | - /// std::string filename | 201 | + /// std::string filename; |
| 202 | /// program.add_option("filename", filename, "description of filename"); | 202 | /// program.add_option("filename", filename, "description of filename"); |
| 203 | /// | 203 | /// |
| 204 | Option* add_option( | 204 | Option* add_option( |
| @@ -474,6 +474,7 @@ public: | @@ -474,6 +474,7 @@ public: | ||
| 474 | /// The real work is done here. Expects a reversed vector. | 474 | /// The real work is done here. Expects a reversed vector. |
| 475 | /// Changes the vector to the remaining options. | 475 | /// Changes the vector to the remaining options. |
| 476 | std::vector<std::string>& parse(std::vector<std::string> &args) { | 476 | std::vector<std::string>& parse(std::vector<std::string> &args) { |
| 477 | + _validate(); | ||
| 477 | _parse(args); | 478 | _parse(args); |
| 478 | run_callback(); | 479 | run_callback(); |
| 479 | return args; | 480 | return args; |
| @@ -678,6 +679,18 @@ public: | @@ -678,6 +679,18 @@ public: | ||
| 678 | 679 | ||
| 679 | protected: | 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 | /// Return missing from the master | 695 | /// Return missing from the master |
| 683 | missing_t* missing() { | 696 | missing_t* missing() { |
include/CLI/Error.hpp
| @@ -100,6 +100,11 @@ struct ExtrasError : public ParseError { | @@ -100,6 +100,11 @@ struct ExtrasError : public ParseError { | ||
| 100 | ExtrasError(std::string name) : ParseError("ExtrasError", name, 6) {} | 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 | /// This is just a safety check to verify selection and parsing match | 108 | /// This is just a safety check to verify selection and parsing match |
| 104 | struct HorribleError : public ParseError { | 109 | struct HorribleError : public ParseError { |
| 105 | HorribleError(std::string name) : ParseError("HorribleError", "(You should never see this error) " + name, 7) {} | 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,6 +35,24 @@ TEST_F(TApp, AddingExistingWithCaseAfter2) { | ||
| 35 | EXPECT_THROW(cat->ignore_case(), CLI::OptionAlreadyAdded); | 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 | TEST_F(TApp, MultipleSubcomMatching) { | 56 | TEST_F(TApp, MultipleSubcomMatching) { |
| 39 | app.add_subcommand("first"); | 57 | app.add_subcommand("first"); |
| 40 | app.add_subcommand("second"); | 58 | app.add_subcommand("second"); |