Commit cf4f60862169407902696801a6066dd0946f3a5e

Authored by Henry Fredrick Schreiner
1 parent af79da5d

Adding check for invalid positionals

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");
... ...