Commit 47a7c3b89f5cc2b100f1143b2eb05321fc19606e
1 parent
c36c913a
Add vectors, fix bad bug
Showing
2 changed files
with
58 additions
and
24 deletions
include/CLI.hpp
| @@ -87,7 +87,7 @@ struct Combiner { | @@ -87,7 +87,7 @@ struct Combiner { | ||
| 87 | Combiner operator() (int n) const { | 87 | Combiner operator() (int n) const { |
| 88 | Combiner self = *this; | 88 | Combiner self = *this; |
| 89 | self.num = n; | 89 | self.num = n; |
| 90 | - return *this; | 90 | + return self; |
| 91 | } | 91 | } |
| 92 | /// Call to give a validator | 92 | /// Call to give a validator |
| 93 | Combiner operator() (std::function<bool(std::string)> func) const { | 93 | Combiner operator() (std::function<bool(std::string)> func) const { |
| @@ -182,8 +182,7 @@ const Combiner NOTHING {0, false,false,false, {}}; | @@ -182,8 +182,7 @@ const Combiner NOTHING {0, false,false,false, {}}; | ||
| 182 | const Combiner REQUIRED {1, false,true, false, {}}; | 182 | const Combiner REQUIRED {1, false,true, false, {}}; |
| 183 | const Combiner DEFAULT {1, false,false,true, {}}; | 183 | const Combiner DEFAULT {1, false,false,true, {}}; |
| 184 | const Combiner POSITIONAL {1, true, false,false, {}}; | 184 | const Combiner POSITIONAL {1, true, false,false, {}}; |
| 185 | -const Combiner ARGS {1, false,false,false, {}}; | ||
| 186 | -const Combiner UNLIMITED {-1,false,false,false, {}}; | 185 | +const Combiner ARGS {-1, false,false,false, {}}; |
| 187 | const Combiner VALIDATORS {1, false, false, false, {}}; | 186 | const Combiner VALIDATORS {1, false, false, false, {}}; |
| 188 | 187 | ||
| 189 | // Warning about using these validators: | 188 | // Warning about using these validators: |
| @@ -196,6 +195,8 @@ const Combiner NonexistentPath {1, false, false, false, {_NonexistentPath}}; | @@ -196,6 +195,8 @@ const Combiner NonexistentPath {1, false, false, false, {_NonexistentPath}}; | ||
| 196 | typedef std::vector<std::vector<std::string>> results_t; | 195 | typedef std::vector<std::vector<std::string>> results_t; |
| 197 | typedef std::function<bool(results_t)> callback_t; | 196 | typedef std::function<bool(results_t)> callback_t; |
| 198 | 197 | ||
| 198 | + | ||
| 199 | + | ||
| 199 | class Option { | 200 | class Option { |
| 200 | public: | 201 | public: |
| 201 | protected: | 202 | protected: |
| @@ -433,27 +434,28 @@ public: | @@ -433,27 +434,28 @@ public: | ||
| 433 | * std::string filename | 434 | * std::string filename |
| 434 | * program.add_option("filename", filename, "discription of filename"); | 435 | * program.add_option("filename", filename, "discription of filename"); |
| 435 | */ | 436 | */ |
| 436 | - void add_option( | 437 | + Option* add_option( |
| 437 | std::string name, ///< The name, long,short | 438 | std::string name, ///< The name, long,short |
| 438 | callback_t callback, ///< The callback | 439 | callback_t callback, ///< The callback |
| 439 | std::string discription="", ///< Discription string | 440 | std::string discription="", ///< Discription string |
| 440 | - Combiner opts=ARGS ///< The options (REQUIRED, DEFAULT, POSITIONAL, ARGS()) | 441 | + Combiner opts=VALIDATORS ///< The options (REQUIRED, DEFAULT, POSITIONAL, ARGS()) |
| 441 | ) { | 442 | ) { |
| 442 | Option myopt{name, discription, opts, callback}; | 443 | Option myopt{name, discription, opts, callback}; |
| 443 | if(std::find(std::begin(options), std::end(options), myopt) == std::end(options)) | 444 | if(std::find(std::begin(options), std::end(options), myopt) == std::end(options)) |
| 444 | options.push_back(myopt); | 445 | options.push_back(myopt); |
| 445 | else | 446 | else |
| 446 | throw OptionAlreadyAdded(myopt.get_name()); | 447 | throw OptionAlreadyAdded(myopt.get_name()); |
| 448 | + return &options.back(); | ||
| 447 | 449 | ||
| 448 | } | 450 | } |
| 449 | 451 | ||
| 450 | /// Add option for string | 452 | /// Add option for string |
| 451 | template<typename T, enable_if_t<!std::is_array<T>::value, detail::enabler> = dummy> | 453 | template<typename T, enable_if_t<!std::is_array<T>::value, detail::enabler> = dummy> |
| 452 | - void add_option( | 454 | + Option* add_option( |
| 453 | std::string name, ///< The name, long,short | 455 | std::string name, ///< The name, long,short |
| 454 | T &variable, ///< The variable to set | 456 | T &variable, ///< The variable to set |
| 455 | std::string discription="", ///< Discription string | 457 | std::string discription="", ///< Discription string |
| 456 | - Combiner opts=ARGS ///< The options (REQUIRED, DEFAULT, POSITIONAL, ARGS()) | 458 | + Combiner opts=VALIDATORS ///< The options (REQUIRED, DEFAULT, POSITIONAL, ARGS()) |
| 457 | ) { | 459 | ) { |
| 458 | 460 | ||
| 459 | 461 | ||
| @@ -469,38 +471,37 @@ public: | @@ -469,38 +471,37 @@ public: | ||
| 469 | return lexical_cast(res[0][0], variable); | 471 | return lexical_cast(res[0][0], variable); |
| 470 | }; | 472 | }; |
| 471 | 473 | ||
| 472 | - add_option(name, fun, discription, opts); | 474 | + return add_option(name, fun, discription, opts); |
| 473 | } | 475 | } |
| 474 | 476 | ||
| 475 | /// Add option for vector of results | 477 | /// Add option for vector of results |
| 476 | template<typename T> | 478 | template<typename T> |
| 477 | - void add_option( | 479 | + Option* add_option( |
| 478 | std::string name, ///< The name, long,short | 480 | std::string name, ///< The name, long,short |
| 479 | std::vector<T> &variable, ///< The variable to set | 481 | std::vector<T> &variable, ///< The variable to set |
| 480 | std::string discription="", ///< Discription string | 482 | std::string discription="", ///< Discription string |
| 481 | - Combiner opts=ARGS ///< The options (REQUIRED, DEFAULT, POSITIONAL, ARGS()) | 483 | + Combiner opts=VALIDATORS ///< The options (REQUIRED, DEFAULT, POSITIONAL, ARGS()) |
| 482 | ) { | 484 | ) { |
| 483 | 485 | ||
| 484 | if(opts.num==0) | 486 | if(opts.num==0) |
| 485 | - throw IncorrectConstruction("Must have ARGS(1) or be a vector."); | 487 | + throw IncorrectConstruction("Must have ARGS or be a vector."); |
| 486 | CLI::callback_t fun = [&variable](CLI::results_t res){ | 488 | CLI::callback_t fun = [&variable](CLI::results_t res){ |
| 487 | bool retval = true; | 489 | bool retval = true; |
| 488 | - int count = 0; | ||
| 489 | variable.clear(); | 490 | variable.clear(); |
| 490 | for(const auto &a : res) | 491 | for(const auto &a : res) |
| 491 | for(const auto &b : a) { | 492 | for(const auto &b : a) { |
| 492 | variable.emplace_back(); | 493 | variable.emplace_back(); |
| 493 | retval &= lexical_cast(b, variable.back()); | 494 | retval &= lexical_cast(b, variable.back()); |
| 494 | } | 495 | } |
| 495 | - return count != 0 && retval; | 496 | + return variable.size() > 0 && retval; |
| 496 | }; | 497 | }; |
| 497 | 498 | ||
| 498 | - add_option(name, fun, discription, opts); | 499 | + return add_option(name, fun, discription, opts); |
| 499 | } | 500 | } |
| 500 | 501 | ||
| 501 | 502 | ||
| 502 | /// Add option for flag | 503 | /// Add option for flag |
| 503 | - void add_flag( | 504 | + Option* add_flag( |
| 504 | std::string name, ///< The name, short,long | 505 | std::string name, ///< The name, short,long |
| 505 | std::string discription="" ///< Discription string | 506 | std::string discription="" ///< Discription string |
| 506 | ) { | 507 | ) { |
| @@ -508,12 +509,12 @@ public: | @@ -508,12 +509,12 @@ public: | ||
| 508 | return true; | 509 | return true; |
| 509 | }; | 510 | }; |
| 510 | 511 | ||
| 511 | - add_option(name, fun, discription, NOTHING); | 512 | + return add_option(name, fun, discription, NOTHING); |
| 512 | } | 513 | } |
| 513 | 514 | ||
| 514 | /// Add option for flag | 515 | /// Add option for flag |
| 515 | template<typename T, enable_if_t<std::is_integral<T>::value, detail::enabler> = dummy> | 516 | template<typename T, enable_if_t<std::is_integral<T>::value, detail::enabler> = dummy> |
| 516 | - void add_flag( | 517 | + Option* add_flag( |
| 517 | std::string name, ///< The name, short,long | 518 | std::string name, ///< The name, short,long |
| 518 | T &count, ///< A varaible holding the count | 519 | T &count, ///< A varaible holding the count |
| 519 | std::string discription="" ///< Discription string | 520 | std::string discription="" ///< Discription string |
| @@ -525,19 +526,22 @@ public: | @@ -525,19 +526,22 @@ public: | ||
| 525 | return true; | 526 | return true; |
| 526 | }; | 527 | }; |
| 527 | 528 | ||
| 528 | - add_option(name, fun, discription, NOTHING); | 529 | + return add_option(name, fun, discription, NOTHING); |
| 529 | } | 530 | } |
| 530 | 531 | ||
| 531 | /// Add set of options | 532 | /// Add set of options |
| 532 | template<typename T> | 533 | template<typename T> |
| 533 | - void add_set( | 534 | + Option* add_set( |
| 534 | std::string name, ///< The name, short,long | 535 | std::string name, ///< The name, short,long |
| 535 | T &member, ///< The selected member of the set | 536 | T &member, ///< The selected member of the set |
| 536 | std::unordered_set<T> options, ///< The set of posibilities | 537 | std::unordered_set<T> options, ///< The set of posibilities |
| 537 | std::string discription="", ///< Discription string | 538 | std::string discription="", ///< Discription string |
| 538 | - Combiner opts=ARGS ///< The options (REQUIRED, DEFAULT, POSITIONAL, ARGS()) | 539 | + Combiner opts=VALIDATORS ///< The options (REQUIRED, DEFAULT, POSITIONAL, ARGS()) |
| 539 | ) { | 540 | ) { |
| 540 | 541 | ||
| 542 | + if(opts.num!=1) | ||
| 543 | + throw IncorrectConstruction("Must have ARGS(1)."); | ||
| 544 | + | ||
| 541 | CLI::callback_t fun = [&member, options](CLI::results_t res){ | 545 | CLI::callback_t fun = [&member, options](CLI::results_t res){ |
| 542 | if(res.size()!=1) { | 546 | if(res.size()!=1) { |
| 543 | return false; | 547 | return false; |
| @@ -551,7 +555,7 @@ public: | @@ -551,7 +555,7 @@ public: | ||
| 551 | return std::find(std::begin(options), std::end(options), retval) != std::end(options); | 555 | return std::find(std::begin(options), std::end(options), retval) != std::end(options); |
| 552 | }; | 556 | }; |
| 553 | 557 | ||
| 554 | - add_option(name, fun, discription, opts); | 558 | + return add_option(name, fun, discription, opts); |
| 555 | } | 559 | } |
| 556 | 560 | ||
| 557 | 561 |
tests/CLITest.cpp
| @@ -249,10 +249,37 @@ TEST_F(TApp, FileExists) { | @@ -249,10 +249,37 @@ TEST_F(TApp, FileExists) { | ||
| 249 | EXPECT_FALSE(CLI::_ExistingFile(myfile)); | 249 | EXPECT_FALSE(CLI::_ExistingFile(myfile)); |
| 250 | } | 250 | } |
| 251 | 251 | ||
| 252 | +TEST_F(TApp, VectorFixedString) { | ||
| 253 | + std::vector<std::string> strvec; | ||
| 254 | + std::vector<std::string> answer{"mystring", "mystring2", "mystring3"}; | ||
| 255 | + | ||
| 256 | + CLI::Option* opt = app.add_option("s,string", strvec, "", CLI::ARGS(3)); | ||
| 257 | + EXPECT_EQ(3, opt->expected()); | ||
| 258 | + | ||
| 259 | + args = {"--string", "mystring", "mystring2", "mystring3"}; | ||
| 260 | + run(); | ||
| 261 | + EXPECT_EQ(3, app.count("string")); | ||
| 262 | + EXPECT_EQ(answer, strvec); | ||
| 263 | +} | ||
| 252 | 264 | ||
| 253 | -// TODO: Add directory test | ||
| 254 | 265 | ||
| 255 | -TEST_F(TApp, Basic) { | 266 | + |
| 267 | +TEST_F(TApp, VectorUnlimString) { | ||
| 268 | + std::vector<std::string> strvec; | ||
| 269 | + std::vector<std::string> answer{"mystring", "mystring2", "mystring3"}; | ||
| 270 | + | ||
| 271 | + CLI::Option* opt = app.add_option("s,string", strvec, "", CLI::ARGS); | ||
| 272 | + EXPECT_EQ(-1, opt->expected()); | ||
| 273 | + | ||
| 274 | + args = {"--string", "mystring", "mystring2", "mystring3"}; | ||
| 275 | + EXPECT_NO_THROW(run()); | ||
| 276 | + EXPECT_EQ(3, app.count("string")); | ||
| 277 | + EXPECT_EQ(answer, strvec); | ||
| 278 | +} | ||
| 279 | + | ||
| 280 | + | ||
| 281 | + | ||
| 282 | +TEST_F(TApp, BasicSubcommands) { | ||
| 256 | auto sub1 = app.add_subcommand("sub1"); | 283 | auto sub1 = app.add_subcommand("sub1"); |
| 257 | auto sub2 = app.add_subcommand("sub2"); | 284 | auto sub2 = app.add_subcommand("sub2"); |
| 258 | 285 | ||
| @@ -272,6 +299,9 @@ TEST_F(TApp, Basic) { | @@ -272,6 +299,9 @@ TEST_F(TApp, Basic) { | ||
| 272 | EXPECT_EQ(sub2, app.get_subcommand()); | 299 | EXPECT_EQ(sub2, app.get_subcommand()); |
| 273 | } | 300 | } |
| 274 | 301 | ||
| 302 | +// TODO: Add directory test | ||
| 303 | + | ||
| 304 | + | ||
| 275 | 305 | ||
| 276 | struct SubcommandProgram : public TApp { | 306 | struct SubcommandProgram : public TApp { |
| 277 | 307 | ||
| @@ -316,7 +346,7 @@ TEST_F(SubcommandProgram, SpareSub) { | @@ -316,7 +346,7 @@ TEST_F(SubcommandProgram, SpareSub) { | ||
| 316 | } | 346 | } |
| 317 | 347 | ||
| 318 | // TODO: Add vector arguments | 348 | // TODO: Add vector arguments |
| 319 | -// TODO: Maybe add function to call on subcommand parse? | 349 | +// TODO: Maybe add function to call on subcommand parse? Stashed. |
| 320 | // TODO: Check help output | 350 | // TODO: Check help output |
| 321 | // TODO: Add default/type info to help | 351 | // TODO: Add default/type info to help |
| 322 | // TODO: Add set checking | 352 | // TODO: Add set checking |