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 | 87 | Combiner operator() (int n) const { |
| 88 | 88 | Combiner self = *this; |
| 89 | 89 | self.num = n; |
| 90 | - return *this; | |
| 90 | + return self; | |
| 91 | 91 | } |
| 92 | 92 | /// Call to give a validator |
| 93 | 93 | Combiner operator() (std::function<bool(std::string)> func) const { |
| ... | ... | @@ -182,8 +182,7 @@ const Combiner NOTHING {0, false,false,false, {}}; |
| 182 | 182 | const Combiner REQUIRED {1, false,true, false, {}}; |
| 183 | 183 | const Combiner DEFAULT {1, false,false,true, {}}; |
| 184 | 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 | 186 | const Combiner VALIDATORS {1, false, false, false, {}}; |
| 188 | 187 | |
| 189 | 188 | // Warning about using these validators: |
| ... | ... | @@ -196,6 +195,8 @@ const Combiner NonexistentPath {1, false, false, false, {_NonexistentPath}}; |
| 196 | 195 | typedef std::vector<std::vector<std::string>> results_t; |
| 197 | 196 | typedef std::function<bool(results_t)> callback_t; |
| 198 | 197 | |
| 198 | + | |
| 199 | + | |
| 199 | 200 | class Option { |
| 200 | 201 | public: |
| 201 | 202 | protected: |
| ... | ... | @@ -433,27 +434,28 @@ public: |
| 433 | 434 | * std::string filename |
| 434 | 435 | * program.add_option("filename", filename, "discription of filename"); |
| 435 | 436 | */ |
| 436 | - void add_option( | |
| 437 | + Option* add_option( | |
| 437 | 438 | std::string name, ///< The name, long,short |
| 438 | 439 | callback_t callback, ///< The callback |
| 439 | 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 | 443 | Option myopt{name, discription, opts, callback}; |
| 443 | 444 | if(std::find(std::begin(options), std::end(options), myopt) == std::end(options)) |
| 444 | 445 | options.push_back(myopt); |
| 445 | 446 | else |
| 446 | 447 | throw OptionAlreadyAdded(myopt.get_name()); |
| 448 | + return &options.back(); | |
| 447 | 449 | |
| 448 | 450 | } |
| 449 | 451 | |
| 450 | 452 | /// Add option for string |
| 451 | 453 | template<typename T, enable_if_t<!std::is_array<T>::value, detail::enabler> = dummy> |
| 452 | - void add_option( | |
| 454 | + Option* add_option( | |
| 453 | 455 | std::string name, ///< The name, long,short |
| 454 | 456 | T &variable, ///< The variable to set |
| 455 | 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 | 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 | 477 | /// Add option for vector of results |
| 476 | 478 | template<typename T> |
| 477 | - void add_option( | |
| 479 | + Option* add_option( | |
| 478 | 480 | std::string name, ///< The name, long,short |
| 479 | 481 | std::vector<T> &variable, ///< The variable to set |
| 480 | 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 | 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 | 488 | CLI::callback_t fun = [&variable](CLI::results_t res){ |
| 487 | 489 | bool retval = true; |
| 488 | - int count = 0; | |
| 489 | 490 | variable.clear(); |
| 490 | 491 | for(const auto &a : res) |
| 491 | 492 | for(const auto &b : a) { |
| 492 | 493 | variable.emplace_back(); |
| 493 | 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 | 503 | /// Add option for flag |
| 503 | - void add_flag( | |
| 504 | + Option* add_flag( | |
| 504 | 505 | std::string name, ///< The name, short,long |
| 505 | 506 | std::string discription="" ///< Discription string |
| 506 | 507 | ) { |
| ... | ... | @@ -508,12 +509,12 @@ public: |
| 508 | 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 | 515 | /// Add option for flag |
| 515 | 516 | template<typename T, enable_if_t<std::is_integral<T>::value, detail::enabler> = dummy> |
| 516 | - void add_flag( | |
| 517 | + Option* add_flag( | |
| 517 | 518 | std::string name, ///< The name, short,long |
| 518 | 519 | T &count, ///< A varaible holding the count |
| 519 | 520 | std::string discription="" ///< Discription string |
| ... | ... | @@ -525,19 +526,22 @@ public: |
| 525 | 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 | 532 | /// Add set of options |
| 532 | 533 | template<typename T> |
| 533 | - void add_set( | |
| 534 | + Option* add_set( | |
| 534 | 535 | std::string name, ///< The name, short,long |
| 535 | 536 | T &member, ///< The selected member of the set |
| 536 | 537 | std::unordered_set<T> options, ///< The set of posibilities |
| 537 | 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 | 545 | CLI::callback_t fun = [&member, options](CLI::results_t res){ |
| 542 | 546 | if(res.size()!=1) { |
| 543 | 547 | return false; |
| ... | ... | @@ -551,7 +555,7 @@ public: |
| 551 | 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 | 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 | 283 | auto sub1 = app.add_subcommand("sub1"); |
| 257 | 284 | auto sub2 = app.add_subcommand("sub2"); |
| 258 | 285 | |
| ... | ... | @@ -272,6 +299,9 @@ TEST_F(TApp, Basic) { |
| 272 | 299 | EXPECT_EQ(sub2, app.get_subcommand()); |
| 273 | 300 | } |
| 274 | 301 | |
| 302 | +// TODO: Add directory test | |
| 303 | + | |
| 304 | + | |
| 275 | 305 | |
| 276 | 306 | struct SubcommandProgram : public TApp { |
| 277 | 307 | |
| ... | ... | @@ -316,7 +346,7 @@ TEST_F(SubcommandProgram, SpareSub) { |
| 316 | 346 | } |
| 317 | 347 | |
| 318 | 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 | 350 | // TODO: Check help output |
| 321 | 351 | // TODO: Add default/type info to help |
| 322 | 352 | // TODO: Add set checking | ... | ... |