diff --git a/include/CLI.hpp b/include/CLI.hpp index 3540c8d1..1faf942e 100644 --- a/include/CLI.hpp +++ b/include/CLI.hpp @@ -87,7 +87,7 @@ struct Combiner { Combiner operator() (int n) const { Combiner self = *this; self.num = n; - return *this; + return self; } /// Call to give a validator Combiner operator() (std::function func) const { @@ -182,8 +182,7 @@ const Combiner NOTHING {0, false,false,false, {}}; const Combiner REQUIRED {1, false,true, false, {}}; const Combiner DEFAULT {1, false,false,true, {}}; const Combiner POSITIONAL {1, true, false,false, {}}; -const Combiner ARGS {1, false,false,false, {}}; -const Combiner UNLIMITED {-1,false,false,false, {}}; +const Combiner ARGS {-1, false,false,false, {}}; const Combiner VALIDATORS {1, false, false, false, {}}; // Warning about using these validators: @@ -196,6 +195,8 @@ const Combiner NonexistentPath {1, false, false, false, {_NonexistentPath}}; typedef std::vector> results_t; typedef std::function callback_t; + + class Option { public: protected: @@ -433,27 +434,28 @@ public: * std::string filename * program.add_option("filename", filename, "discription of filename"); */ - void add_option( + Option* add_option( std::string name, ///< The name, long,short callback_t callback, ///< The callback std::string discription="", ///< Discription string - Combiner opts=ARGS ///< The options (REQUIRED, DEFAULT, POSITIONAL, ARGS()) + Combiner opts=VALIDATORS ///< The options (REQUIRED, DEFAULT, POSITIONAL, ARGS()) ) { Option myopt{name, discription, opts, callback}; if(std::find(std::begin(options), std::end(options), myopt) == std::end(options)) options.push_back(myopt); else throw OptionAlreadyAdded(myopt.get_name()); + return &options.back(); } /// Add option for string template::value, detail::enabler> = dummy> - void add_option( + Option* add_option( std::string name, ///< The name, long,short T &variable, ///< The variable to set std::string discription="", ///< Discription string - Combiner opts=ARGS ///< The options (REQUIRED, DEFAULT, POSITIONAL, ARGS()) + Combiner opts=VALIDATORS ///< The options (REQUIRED, DEFAULT, POSITIONAL, ARGS()) ) { @@ -469,38 +471,37 @@ public: return lexical_cast(res[0][0], variable); }; - add_option(name, fun, discription, opts); + return add_option(name, fun, discription, opts); } /// Add option for vector of results template - void add_option( + Option* add_option( std::string name, ///< The name, long,short std::vector &variable, ///< The variable to set std::string discription="", ///< Discription string - Combiner opts=ARGS ///< The options (REQUIRED, DEFAULT, POSITIONAL, ARGS()) + Combiner opts=VALIDATORS ///< The options (REQUIRED, DEFAULT, POSITIONAL, ARGS()) ) { if(opts.num==0) - throw IncorrectConstruction("Must have ARGS(1) or be a vector."); + throw IncorrectConstruction("Must have ARGS or be a vector."); CLI::callback_t fun = [&variable](CLI::results_t res){ bool retval = true; - int count = 0; variable.clear(); for(const auto &a : res) for(const auto &b : a) { variable.emplace_back(); retval &= lexical_cast(b, variable.back()); } - return count != 0 && retval; + return variable.size() > 0 && retval; }; - add_option(name, fun, discription, opts); + return add_option(name, fun, discription, opts); } /// Add option for flag - void add_flag( + Option* add_flag( std::string name, ///< The name, short,long std::string discription="" ///< Discription string ) { @@ -508,12 +509,12 @@ public: return true; }; - add_option(name, fun, discription, NOTHING); + return add_option(name, fun, discription, NOTHING); } /// Add option for flag template::value, detail::enabler> = dummy> - void add_flag( + Option* add_flag( std::string name, ///< The name, short,long T &count, ///< A varaible holding the count std::string discription="" ///< Discription string @@ -525,19 +526,22 @@ public: return true; }; - add_option(name, fun, discription, NOTHING); + return add_option(name, fun, discription, NOTHING); } /// Add set of options template - void add_set( + Option* add_set( std::string name, ///< The name, short,long T &member, ///< The selected member of the set std::unordered_set options, ///< The set of posibilities std::string discription="", ///< Discription string - Combiner opts=ARGS ///< The options (REQUIRED, DEFAULT, POSITIONAL, ARGS()) + Combiner opts=VALIDATORS ///< The options (REQUIRED, DEFAULT, POSITIONAL, ARGS()) ) { + if(opts.num!=1) + throw IncorrectConstruction("Must have ARGS(1)."); + CLI::callback_t fun = [&member, options](CLI::results_t res){ if(res.size()!=1) { return false; @@ -551,7 +555,7 @@ public: return std::find(std::begin(options), std::end(options), retval) != std::end(options); }; - add_option(name, fun, discription, opts); + return add_option(name, fun, discription, opts); } diff --git a/tests/CLITest.cpp b/tests/CLITest.cpp index 1aa070b1..694420d4 100644 --- a/tests/CLITest.cpp +++ b/tests/CLITest.cpp @@ -249,10 +249,37 @@ TEST_F(TApp, FileExists) { EXPECT_FALSE(CLI::_ExistingFile(myfile)); } +TEST_F(TApp, VectorFixedString) { + std::vector strvec; + std::vector answer{"mystring", "mystring2", "mystring3"}; -// TODO: Add directory test + CLI::Option* opt = app.add_option("s,string", strvec, "", CLI::ARGS(3)); + EXPECT_EQ(3, opt->expected()); + + args = {"--string", "mystring", "mystring2", "mystring3"}; + run(); + EXPECT_EQ(3, app.count("string")); + EXPECT_EQ(answer, strvec); +} -TEST_F(TApp, Basic) { + + +TEST_F(TApp, VectorUnlimString) { + std::vector strvec; + std::vector answer{"mystring", "mystring2", "mystring3"}; + + CLI::Option* opt = app.add_option("s,string", strvec, "", CLI::ARGS); + EXPECT_EQ(-1, opt->expected()); + + args = {"--string", "mystring", "mystring2", "mystring3"}; + EXPECT_NO_THROW(run()); + EXPECT_EQ(3, app.count("string")); + EXPECT_EQ(answer, strvec); +} + + + +TEST_F(TApp, BasicSubcommands) { auto sub1 = app.add_subcommand("sub1"); auto sub2 = app.add_subcommand("sub2"); @@ -272,6 +299,9 @@ TEST_F(TApp, Basic) { EXPECT_EQ(sub2, app.get_subcommand()); } +// TODO: Add directory test + + struct SubcommandProgram : public TApp { @@ -316,7 +346,7 @@ TEST_F(SubcommandProgram, SpareSub) { } // TODO: Add vector arguments -// TODO: Maybe add function to call on subcommand parse? +// TODO: Maybe add function to call on subcommand parse? Stashed. // TODO: Check help output // TODO: Add default/type info to help // TODO: Add set checking