1 // Copyright (c) 2017-2021, University of Cincinnati, developed by Henry Schreiner 2 // under NSF AWARD 1414736 and by the respective contributors. 3 // All rights reserved. 4 // 5 // SPDX-License-Identifier: BSD-3-Clause 6 7 #include "app_helper.hpp" 8 #include <complex> 9 #include <cstdint> 10 #include <cstdlib> 11 12 TEST_CASE_METHOD(TApp, "OneFlagShort", "[app]") { 13 app.add_flag("-c,--count"); 14 args = {"-c"}; 15 run(); 16 CHECK(app.count("-c") == 1u); 17 CHECK(app.count("--count") == 1u); 18 } 19 20 TEST_CASE_METHOD(TApp, "OneFlagShortValues", "[app]") { 21 app.add_flag("-c{v1},--count{v2}"); 22 args = {"-c"}; 23 run(); 24 CHECK(app.count("-c") == 1u); 25 CHECK(app.count("--count") == 1u); 26 auto v = app["-c"]->results(); 27 CHECK("v1" == v[0]); 28 29 CHECK_THROWS_AS(app["--invalid"], CLI::OptionNotFound); 30 } 31 32 TEST_CASE_METHOD(TApp, "OneFlagShortValuesAs", "[app]") { 33 auto flg = app.add_flag("-c{1},--count{2}"); 34 args = {"-c"}; 35 run(); 36 auto opt = app["-c"]; 37 CHECK(1 == opt->as<int>()); 38 args = {"--count"}; 39 run(); 40 CHECK(2 == opt->as<int>()); 41 flg->take_first(); 42 args = {"-c", "--count"}; 43 run(); 44 CHECK(1 == opt->as<int>()); 45 flg->take_last(); 46 CHECK(2 == opt->as<int>()); 47 flg->multi_option_policy(CLI::MultiOptionPolicy::Throw); 48 CHECK_THROWS_AS(opt->as<int>(), CLI::ArgumentMismatch); 49 flg->multi_option_policy(CLI::MultiOptionPolicy::TakeAll); 50 auto vec = opt->as<std::vector<int>>(); 51 CHECK(1 == vec[0]); 52 CHECK(2 == vec[1]); 53 flg->multi_option_policy(CLI::MultiOptionPolicy::Join); 54 CHECK("1\n2" == opt->as<std::string>()); 55 flg->delimiter(','); 56 CHECK("1,2" == opt->as<std::string>()); 57 } 58 59 TEST_CASE_METHOD(TApp, "OneFlagShortWindows", "[app]") { 60 app.add_flag("-c,--count"); 61 args = {"/c"}; 62 app.allow_windows_style_options(); 63 run(); 64 CHECK(app.count("-c") == 1u); 65 CHECK(app.count("--count") == 1u); 66 } 67 68 TEST_CASE_METHOD(TApp, "WindowsLongShortMix1", "[app]") { 69 app.allow_windows_style_options(); 70 71 auto a = app.add_flag("-c"); 72 auto b = app.add_flag("--c"); 73 args = {"/c"}; 74 run(); 75 CHECK(a->count() == 1u); 76 CHECK(b->count() == 0u); 77 } 78 79 TEST_CASE_METHOD(TApp, "WindowsLongShortMix2", "[app]") { 80 app.allow_windows_style_options(); 81 82 auto a = app.add_flag("--c"); 83 auto b = app.add_flag("-c"); 84 args = {"/c"}; 85 run(); 86 CHECK(a->count() == 1u); 87 CHECK(b->count() == 0u); 88 } 89 90 TEST_CASE_METHOD(TApp, "CountNonExist", "[app]") { 91 app.add_flag("-c,--count"); 92 args = {"-c"}; 93 run(); 94 CHECK_THROWS_AS(app.count("--nonexist"), CLI::OptionNotFound); 95 } 96 97 TEST_CASE_METHOD(TApp, "OneFlagLong", "[app]") { 98 app.add_flag("-c,--count"); 99 args = {"--count"}; 100 run(); 101 CHECK(app.count("-c") == 1u); 102 CHECK(app.count("--count") == 1u); 103 } 104 105 TEST_CASE_METHOD(TApp, "DashedOptions", "[app]") { 106 app.add_flag("-c"); 107 app.add_flag("--q"); 108 app.add_flag("--this,--that"); 109 110 args = {"-c", "--q", "--this", "--that"}; 111 run(); 112 CHECK(app.count("-c") == 1u); 113 CHECK(app.count("--q") == 1u); 114 CHECK(app.count("--this") == 2u); 115 CHECK(app.count("--that") == 2u); 116 } 117 118 TEST_CASE_METHOD(TApp, "DashedOptionsSingleString", "[app]") { 119 app.add_flag("-c"); 120 app.add_flag("--q"); 121 app.add_flag("--this,--that"); 122 123 app.parse("-c --q --this --that"); 124 CHECK(app.count("-c") == 1u); 125 CHECK(app.count("--q") == 1u); 126 CHECK(app.count("--this") == 2u); 127 CHECK(app.count("--that") == 2u); 128 } 129 130 TEST_CASE_METHOD(TApp, "StrangeFlagNames", "[app]") { 131 app.add_flag("-="); 132 app.add_flag("--t\tt"); 133 app.add_flag("-{"); 134 CHECK_THROWS_AS(app.add_flag("--t t"), CLI::ConstructionError); 135 args = {"-=", "--t\tt"}; 136 run(); 137 CHECK(app.count("-=") == 1u); 138 CHECK(app.count("--t\tt") == 1u); 139 } 140 141 TEST_CASE_METHOD(TApp, "RequireOptionsError", "[app]") { 142 using Catch::Matchers::Contains; 143 144 app.add_flag("-c"); 145 app.add_flag("--q"); 146 app.add_flag("--this,--that"); 147 app.set_help_flag("-h,--help"); 148 app.set_help_all_flag("--help_all"); 149 app.require_option(1, 2); 150 try { 151 app.parse("-c --q --this --that"); 152 } catch(const CLI::RequiredError &re) { 153 CHECK_THAT(re.what(), !Contains("-h,--help")); 154 CHECK_THAT(re.what(), !Contains("help_all")); 155 } 156 157 CHECK_NOTHROW(app.parse("-c --q")); 158 CHECK_NOTHROW(app.parse("-c --this --that")); 159 } 160 161 TEST_CASE_METHOD(TApp, "BoolFlagOverride", "[app]") { 162 bool val{false}; 163 auto flg = app.add_flag("--this,--that", val); 164 165 app.parse("--this"); 166 CHECK(val); 167 app.parse("--this=false"); 168 CHECK(!val); 169 flg->disable_flag_override(true); 170 app.parse("--this"); 171 CHECK(val); 172 // this is allowed since the matching string is the default 173 app.parse("--this=true"); 174 CHECK(val); 175 176 CHECK_THROWS_AS(app.parse("--this=false"), CLI::ArgumentMismatch); 177 // try a string that specifies 'use default val' 178 CHECK_NOTHROW(app.parse("--this={}")); 179 } 180 181 TEST_CASE_METHOD(TApp, "OneFlagRef", "[app]") { 182 int ref{0}; 183 app.add_flag("-c,--count", ref); 184 args = {"--count"}; 185 run(); 186 CHECK(app.count("-c") == 1u); 187 CHECK(app.count("--count") == 1u); 188 CHECK(ref == 1); 189 } 190 191 TEST_CASE_METHOD(TApp, "OneFlagRefValue", "[app]") { 192 int ref{0}; 193 app.add_flag("-c,--count", ref); 194 args = {"--count=7"}; 195 run(); 196 CHECK(app.count("-c") == 1u); 197 CHECK(app.count("--count") == 1u); 198 CHECK(ref == 7); 199 } 200 201 TEST_CASE_METHOD(TApp, "OneFlagRefValueFalse", "[app]") { 202 int ref{0}; 203 auto flg = app.add_flag("-c,--count", ref); 204 args = {"--count=false"}; 205 run(); 206 CHECK(app.count("-c") == 1u); 207 CHECK(app.count("--count") == 1u); 208 CHECK(ref == -1); 209 210 CHECK(!flg->check_fname("c")); 211 args = {"--count=0"}; 212 run(); 213 CHECK(app.count("-c") == 1u); 214 CHECK(app.count("--count") == 1u); 215 CHECK(ref == -1); 216 217 args = {"--count=happy"}; 218 CHECK_THROWS_AS(run(), CLI::ConversionError); 219 } 220 221 TEST_CASE_METHOD(TApp, "FlagNegation", "[app]") { 222 int ref{0}; 223 auto flg = app.add_flag("-c,--count,--ncount{false}", ref); 224 args = {"--count", "-c", "--ncount"}; 225 CHECK(!flg->check_fname("count")); 226 CHECK(flg->check_fname("ncount")); 227 run(); 228 CHECK(app.count("-c") == 3u); 229 CHECK(app.count("--count") == 3u); 230 CHECK(app.count("--ncount") == 3u); 231 CHECK(ref == 1); 232 } 233 234 TEST_CASE_METHOD(TApp, "FlagNegationShortcutNotation", "[app]") { 235 int ref{0}; 236 app.add_flag("-c,--count{true},!--ncount", ref); 237 args = {"--count=TRUE", "-c", "--ncount"}; 238 run(); 239 CHECK(app.count("-c") == 3u); 240 CHECK(app.count("--count") == 3u); 241 CHECK(app.count("--ncount") == 3u); 242 CHECK(ref == 1); 243 } 244 245 TEST_CASE_METHOD(TApp, "FlagNegationShortcutNotationInvalid", "[app]") { 246 int ref{0}; 247 app.add_flag("-c,--count,!--ncount", ref); 248 args = {"--ncount=happy"}; 249 CHECK_THROWS_AS(run(), CLI::ConversionError); 250 } 251 252 TEST_CASE_METHOD(TApp, "OneString", "[app]") { 253 std::string str; 254 app.add_option("-s,--string", str); 255 args = {"--string", "mystring"}; 256 run(); 257 CHECK(app.count("-s") == 1u); 258 CHECK(app.count("--string") == 1u); 259 CHECK("mystring" == str); 260 } 261 262 TEST_CASE_METHOD(TApp, "OneStringWindowsStyle", "[app]") { 263 std::string str; 264 app.add_option("-s,--string", str); 265 args = {"/string", "mystring"}; 266 app.allow_windows_style_options(); 267 run(); 268 CHECK(app.count("-s") == 1u); 269 CHECK(app.count("--string") == 1u); 270 CHECK("mystring" == str); 271 } 272 273 TEST_CASE_METHOD(TApp, "OneStringSingleStringInput", "[app]") { 274 std::string str; 275 app.add_option("-s,--string", str); 276 277 app.parse("--string mystring"); 278 CHECK(app.count("-s") == 1u); 279 CHECK(app.count("--string") == 1u); 280 CHECK("mystring" == str); 281 } 282 283 TEST_CASE_METHOD(TApp, "OneStringEqualVersion", "[app]") { 284 std::string str; 285 app.add_option("-s,--string", str); 286 args = {"--string=mystring"}; 287 run(); 288 CHECK(app.count("-s") == 1u); 289 CHECK(app.count("--string") == 1u); 290 CHECK("mystring" == str); 291 } 292 293 TEST_CASE_METHOD(TApp, "OneStringEqualVersionWindowsStyle", "[app]") { 294 std::string str; 295 app.add_option("-s,--string", str); 296 args = {"/string:mystring"}; 297 app.allow_windows_style_options(); 298 run(); 299 CHECK(app.count("-s") == 1u); 300 CHECK(app.count("--string") == 1u); 301 CHECK("mystring" == str); 302 } 303 304 TEST_CASE_METHOD(TApp, "OneStringEqualVersionSingleString", "[app]") { 305 std::string str; 306 app.add_option("-s,--string", str); 307 app.parse("--string=mystring"); 308 CHECK(app.count("-s") == 1u); 309 CHECK(app.count("--string") == 1u); 310 CHECK("mystring" == str); 311 } 312 313 TEST_CASE_METHOD(TApp, "OneStringEqualVersionSingleStringQuoted", "[app]") { 314 std::string str; 315 app.add_option("-s,--string", str); 316 app.parse(R"raw(--string="this is my quoted string")raw"); 317 CHECK(app.count("-s") == 1u); 318 CHECK(app.count("--string") == 1u); 319 CHECK("this is my quoted string" == str); 320 } 321 322 TEST_CASE_METHOD(TApp, "OneStringEqualVersionSingleStringQuotedMultiple", "[app]") { 323 std::string str, str2, str3; 324 app.add_option("-s,--string", str); 325 app.add_option("-t,--tstr", str2); 326 app.add_option("-m,--mstr", str3); 327 app.parse(R"raw(--string="this is my quoted string" -t 'qstring 2' -m=`"quoted string"`)raw"); 328 CHECK("this is my quoted string" == str); 329 CHECK("qstring 2" == str2); 330 CHECK("\"quoted string\"" == str3); 331 } 332 333 TEST_CASE_METHOD(TApp, "OneStringEqualVersionSingleStringEmbeddedEqual", "[app]") { 334 std::string str, str2, str3; 335 app.add_option("-s,--string", str); 336 app.add_option("-t,--tstr", str2); 337 app.add_option("-m,--mstr", str3); 338 app.parse(R"raw(--string="app=\"test1 b\" test2=\"frogs\"" -t 'qstring 2' -m=`"quoted string"`)raw"); 339 CHECK("app=\"test1 b\" test2=\"frogs\"" == str); 340 CHECK("qstring 2" == str2); 341 CHECK("\"quoted string\"" == str3); 342 343 app.parse(R"raw(--string="app='test1 b' test2='frogs'" -t 'qstring 2' -m=`"quoted string"`)raw"); 344 CHECK("app='test1 b' test2='frogs'" == str); 345 CHECK("qstring 2" == str2); 346 CHECK("\"quoted string\"" == str3); 347 } 348 349 TEST_CASE_METHOD(TApp, "OneStringEqualVersionSingleStringEmbeddedEqualWindowsStyle", "[app]") { 350 std::string str, str2, str3; 351 app.add_option("-s,--string", str); 352 app.add_option("-t,--tstr", str2); 353 app.add_option("--mstr", str3); 354 app.allow_windows_style_options(); 355 app.parse(R"raw(/string:"app:\"test1 b\" test2:\"frogs\"" /t 'qstring 2' /mstr:`"quoted string"`)raw"); 356 CHECK("app:\"test1 b\" test2:\"frogs\"" == str); 357 CHECK("qstring 2" == str2); 358 CHECK("\"quoted string\"" == str3); 359 360 app.parse(R"raw(/string:"app:'test1 b' test2:'frogs'" /t 'qstring 2' /mstr:`"quoted string"`)raw"); 361 CHECK("app:'test1 b' test2:'frogs'" == str); 362 CHECK("qstring 2" == str2); 363 CHECK("\"quoted string\"" == str3); 364 } 365 366 TEST_CASE_METHOD(TApp, "OneStringEqualVersionSingleStringQuotedMultipleMixedStyle", "[app]") { 367 std::string str, str2, str3; 368 app.add_option("-s,--string", str); 369 app.add_option("-t,--tstr", str2); 370 app.add_option("-m,--mstr", str3); 371 app.allow_windows_style_options(); 372 app.parse(R"raw(/string:"this is my quoted string" /t 'qstring 2' -m=`"quoted string"`)raw"); 373 CHECK("this is my quoted string" == str); 374 CHECK("qstring 2" == str2); 375 CHECK("\"quoted string\"" == str3); 376 } 377 378 TEST_CASE_METHOD(TApp, "OneStringEqualVersionSingleStringQuotedMultipleInMiddle", "[app]") { 379 std::string str, str2, str3; 380 app.add_option("-s,--string", str); 381 app.add_option("-t,--tstr", str2); 382 app.add_option("-m,--mstr", str3); 383 app.parse(R"raw(--string="this is my quoted string" -t "qst\"ring 2" -m=`"quoted string"`)raw"); 384 CHECK("this is my quoted string" == str); 385 CHECK("qst\"ring 2" == str2); 386 CHECK("\"quoted string\"" == str3); 387 } 388 389 TEST_CASE_METHOD(TApp, "OneStringEqualVersionSingleStringQuotedEscapedCharacters", "[app]") { 390 std::string str, str2, str3; 391 app.add_option("-s,--string", str); 392 app.add_option("-t,--tstr", str2); 393 app.add_option("-m,--mstr", str3); 394 app.parse(R"raw(--string="this is my \"quoted\" string" -t 'qst\'ring 2' -m=`"quoted\` string"`")raw"); 395 CHECK("this is my \"quoted\" string" == str); 396 CHECK("qst\'ring 2" == str2); 397 CHECK("\"quoted` string\"" == str3); 398 } 399 400 TEST_CASE_METHOD(TApp, "OneStringEqualVersionSingleStringQuotedMultipleWithEqual", "[app]") { 401 std::string str, str2, str3, str4; 402 app.add_option("-s,--string", str); 403 app.add_option("-t,--tstr", str2); 404 app.add_option("-m,--mstr", str3); 405 app.add_option("-j,--jstr", str4); 406 app.parse(R"raw(--string="this is my quoted string" -t 'qstring 2' -m=`"quoted string"` --jstr=Unquoted)raw"); 407 CHECK("this is my quoted string" == str); 408 CHECK("qstring 2" == str2); 409 CHECK("\"quoted string\"" == str3); 410 CHECK("Unquoted" == str4); 411 } 412 413 TEST_CASE_METHOD(TApp, "OneStringEqualVersionSingleStringQuotedMultipleWithEqualAndProgram", "[app]") { 414 std::string str, str2, str3, str4; 415 app.add_option("-s,--string", str); 416 app.add_option("-t,--tstr", str2); 417 app.add_option("-m,--mstr", str3); 418 app.add_option("-j,--jstr", str4); 419 app.parse( 420 R"raw(program --string="this is my quoted string" -t 'qstring 2' -m=`"quoted string"` --jstr=Unquoted)raw", 421 true); 422 CHECK("this is my quoted string" == str); 423 CHECK("qstring 2" == str2); 424 CHECK("\"quoted string\"" == str3); 425 CHECK("Unquoted" == str4); 426 } 427 428 TEST_CASE_METHOD(TApp, "OneStringFlagLike", "[app]") { 429 std::string str{"something"}; 430 app.add_option("-s,--string", str)->expected(0, 1); 431 args = {"--string"}; 432 run(); 433 CHECK(app.count("-s") == 1u); 434 CHECK(app.count("--string") == 1u); 435 CHECK(str.empty()); 436 } 437 438 TEST_CASE_METHOD(TApp, "OneIntFlagLike", "[app]") { 439 int val{0}; 440 auto opt = app.add_option("-i", val)->expected(0, 1); 441 args = {"-i"}; 442 run(); 443 CHECK(app.count("-i") == 1u); 444 opt->default_str("7"); 445 run(); 446 CHECK(7 == val); 447 448 opt->default_val(9); 449 run(); 450 CHECK(9 == val); 451 } 452 453 TEST_CASE_METHOD(TApp, "TogetherInt", "[app]") { 454 int i{0}; 455 app.add_option("-i,--int", i); 456 args = {"-i4"}; 457 run(); 458 CHECK(app.count("--int") == 1u); 459 CHECK(app.count("-i") == 1u); 460 CHECK(4 == i); 461 CHECK("4" == app["-i"]->as<std::string>()); 462 CHECK(4.0 == app["--int"]->as<double>()); 463 } 464 465 TEST_CASE_METHOD(TApp, "SepInt", "[app]") { 466 int i{0}; 467 app.add_option("-i,--int", i); 468 args = {"-i", "4"}; 469 run(); 470 CHECK(app.count("--int") == 1u); 471 CHECK(app.count("-i") == 1u); 472 CHECK(4 == i); 473 } 474 475 TEST_CASE_METHOD(TApp, "DefaultStringAgain", "[app]") { 476 std::string str = "previous"; 477 app.add_option("-s,--string", str); 478 run(); 479 CHECK(app.count("-s") == 0u); 480 CHECK(app.count("--string") == 0u); 481 CHECK("previous" == str); 482 } 483 484 TEST_CASE_METHOD(TApp, "DefaultStringAgainEmpty", "[app]") { 485 std::string str = "previous"; 486 app.add_option("-s,--string", str); 487 app.parse(" "); 488 CHECK(app.count("-s") == 0u); 489 CHECK(app.count("--string") == 0u); 490 CHECK("previous" == str); 491 } 492 493 TEST_CASE_METHOD(TApp, "DualOptions", "[app]") { 494 495 std::string str = "previous"; 496 std::vector<std::string> vstr = {"previous"}; 497 std::vector<std::string> ans = {"one", "two"}; 498 app.add_option("-s,--string", str); 499 app.add_option("-v,--vector", vstr); 500 501 args = {"--vector=one", "--vector=two"}; 502 run(); 503 CHECK(vstr == ans); 504 505 args = {"--string=one", "--string=two"}; 506 CHECK_THROWS_AS(run(), CLI::ArgumentMismatch); 507 } 508 509 TEST_CASE_METHOD(TApp, "LotsOfFlags", "[app]") { 510 511 app.add_flag("-a"); 512 app.add_flag("-A"); 513 app.add_flag("-b"); 514 515 args = {"-a", "-b", "-aA"}; 516 run(); 517 CHECK(app.count("-a") == 2u); 518 CHECK(app.count("-b") == 1u); 519 CHECK(app.count("-A") == 1u); 520 CHECK(4u == app.count_all()); 521 } 522 523 TEST_CASE_METHOD(TApp, "NumberFlags", "[app]") { 524 525 int val{0}; 526 app.add_flag("-1{1},-2{2},-3{3},-4{4},-5{5},-6{6}, -7{7}, -8{8}, -9{9}", val); 527 528 args = {"-7"}; 529 run(); 530 CHECK(app.count("-1") == 1u); 531 CHECK(7 == val); 532 } 533 534 TEST_CASE_METHOD(TApp, "DisableFlagOverrideTest", "[app]") { 535 536 int val{0}; 537 auto opt = app.add_flag("--1{1},--2{2},--3{3},--4{4},--5{5},--6{6}, --7{7}, --8{8}, --9{9}", val); 538 CHECK(!opt->get_disable_flag_override()); 539 opt->disable_flag_override(); 540 args = {"--7=5"}; 541 CHECK_THROWS_AS(run(), CLI::ArgumentMismatch); 542 CHECK(opt->get_disable_flag_override()); 543 opt->disable_flag_override(false); 544 CHECK(!opt->get_disable_flag_override()); 545 CHECK_NOTHROW(run()); 546 CHECK(5 == val); 547 opt->disable_flag_override(); 548 args = {"--7=7"}; 549 CHECK_NOTHROW(run()); 550 } 551 552 TEST_CASE_METHOD(TApp, "LotsOfFlagsSingleString", "[app]") { 553 554 app.add_flag("-a"); 555 app.add_flag("-A"); 556 app.add_flag("-b"); 557 558 app.parse("-a -b -aA"); 559 CHECK(app.count("-a") == 2u); 560 CHECK(app.count("-b") == 1u); 561 CHECK(app.count("-A") == 1u); 562 } 563 564 TEST_CASE_METHOD(TApp, "LotsOfFlagsSingleStringExtraSpace", "[app]") { 565 566 app.add_flag("-a"); 567 app.add_flag("-A"); 568 app.add_flag("-b"); 569 570 app.parse(" -a -b -aA "); 571 CHECK(app.count("-a") == 2u); 572 CHECK(app.count("-b") == 1u); 573 CHECK(app.count("-A") == 1u); 574 } 575 576 TEST_CASE_METHOD(TApp, "SingleArgVector", "[app]") { 577 578 std::vector<std::string> channels; 579 std::vector<std::string> iargs; 580 std::string path; 581 app.add_option("-c", channels)->type_size(1)->allow_extra_args(false); 582 app.add_option("args", iargs); 583 app.add_option("-p", path); 584 585 app.parse("-c t1 -c t2 -c t3 a1 a2 a3 a4 -p happy"); 586 CHECK(channels.size() == 3u); 587 CHECK(iargs.size() == 4u); 588 CHECK("happy" == path); 589 590 app.parse("-c t1 a1 -c t2 -c t3 a2 a3 a4 -p happy"); 591 CHECK(channels.size() == 3u); 592 CHECK(iargs.size() == 4u); 593 CHECK("happy" == path); 594 } 595 596 TEST_CASE_METHOD(TApp, "StrangeOptionNames", "[app]") { 597 app.add_option("-:"); 598 app.add_option("--t\tt"); 599 app.add_option("--{}"); 600 app.add_option("--:)"); 601 CHECK_THROWS_AS(app.add_option("--t t"), CLI::ConstructionError); 602 args = {"-:)", "--{}", "5"}; 603 run(); 604 CHECK(app.count("-:") == 1u); 605 CHECK(app.count("--{}") == 1u); 606 CHECK(app["-:"]->as<char>() == ')'); 607 CHECK(app["--{}"]->as<int>() == 5); 608 } 609 610 TEST_CASE_METHOD(TApp, "FlagLikeOption", "[app]") { 611 bool val{false}; 612 auto opt = app.add_option("--flag", val)->type_size(0)->default_str("true"); 613 args = {"--flag"}; 614 run(); 615 CHECK(app.count("--flag") == 1u); 616 CHECK(val); 617 val = false; 618 opt->type_size(0, 0); // should be the same as above 619 CHECK(0 == opt->get_type_size_min()); 620 CHECK(0 == opt->get_type_size_max()); 621 run(); 622 CHECK(app.count("--flag") == 1u); 623 CHECK(val); 624 } 625 626 TEST_CASE_METHOD(TApp, "FlagLikeIntOption", "[app]") { 627 int val{-47}; 628 auto opt = app.add_option("--flag", val)->expected(0, 1); 629 // normally some default value should be set, but this test is for some paths in the validators checks to skip 630 // validation on empty string if nothing is expected 631 opt->check(CLI::PositiveNumber); 632 args = {"--flag"}; 633 CHECK(opt->as<std::string>().empty()); 634 run(); 635 CHECK(app.count("--flag") == 1u); 636 CHECK(-47 != val); 637 args = {"--flag", "12"}; 638 run(); 639 640 CHECK(12 == val); 641 args.clear(); 642 run(); 643 CHECK(opt->as<std::string>().empty()); 644 } 645 646 TEST_CASE_METHOD(TApp, "BoolOnlyFlag", "[app]") { 647 bool bflag{false}; 648 app.add_flag("-b", bflag)->multi_option_policy(CLI::MultiOptionPolicy::Throw); 649 650 args = {"-b"}; 651 REQUIRE_NOTHROW(run()); 652 CHECK(bflag); 653 654 args = {"-b", "-b"}; 655 CHECK_THROWS_AS(run(), CLI::ArgumentMismatch); 656 } 657 658 TEST_CASE_METHOD(TApp, "ShortOpts", "[app]") { 659 660 std::uint64_t funnyint{0}; 661 std::string someopt; 662 app.add_flag("-z", funnyint); 663 app.add_option("-y", someopt); 664 665 args = { 666 "-zzyzyz", 667 }; 668 669 run(); 670 671 CHECK(app.count("-z") == 2u); 672 CHECK(app.count("-y") == 1u); 673 CHECK(funnyint == std::uint64_t{2}); 674 CHECK(someopt == "zyz"); 675 CHECK(3u == app.count_all()); 676 } 677 678 TEST_CASE_METHOD(TApp, "TwoParamTemplateOpts", "[app]") { 679 680 double funnyint{0.0}; 681 auto opt = app.add_option<double, unsigned int>("-y", funnyint); 682 683 args = {"-y", "32"}; 684 685 run(); 686 687 CHECK(funnyint == 32.0); 688 689 args = {"-y", "32.3"}; 690 CHECK_THROWS_AS(run(), CLI::ConversionError); 691 692 args = {"-y", "-19"}; 693 CHECK_THROWS_AS(run(), CLI::ConversionError); 694 695 opt->capture_default_str(); 696 CHECK(opt->get_default_str().empty()); 697 } 698 699 TEST_CASE_METHOD(TApp, "DefaultOpts", "[app]") { 700 701 int i{3}; 702 std::string s = "HI"; 703 704 app.add_option("-i,i", i); 705 app.add_option("-s,s", s)->capture_default_str(); // Used to be different 706 707 args = {"-i2", "9"}; 708 709 run(); 710 711 CHECK(app.count("i") == 1u); 712 CHECK(app.count("-s") == 1u); 713 CHECK(i == 2); 714 CHECK(s == "9"); 715 } 716 717 TEST_CASE_METHOD(TApp, "TakeLastOpt", "[app]") { 718 719 std::string str; 720 app.add_option("--str", str)->multi_option_policy(CLI::MultiOptionPolicy::TakeLast); 721 722 args = {"--str=one", "--str=two"}; 723 724 run(); 725 726 CHECK("two" == str); 727 } 728 729 TEST_CASE_METHOD(TApp, "TakeLastOpt2", "[app]") { 730 731 std::string str; 732 app.add_option("--str", str)->take_last(); 733 734 args = {"--str=one", "--str=two"}; 735 736 run(); 737 738 CHECK("two" == str); 739 } 740 741 TEST_CASE_METHOD(TApp, "TakeFirstOpt", "[app]") { 742 743 std::string str; 744 app.add_option("--str", str)->multi_option_policy(CLI::MultiOptionPolicy::TakeFirst); 745 746 args = {"--str=one", "--str=two"}; 747 748 run(); 749 750 CHECK("one" == str); 751 } 752 753 TEST_CASE_METHOD(TApp, "TakeFirstOpt2", "[app]") { 754 755 std::string str; 756 app.add_option("--str", str)->take_first(); 757 758 args = {"--str=one", "--str=two"}; 759 760 run(); 761 762 CHECK("one" == str); 763 } 764 765 TEST_CASE_METHOD(TApp, "JoinOpt", "[app]") { 766 767 std::string str; 768 app.add_option("--str", str)->multi_option_policy(CLI::MultiOptionPolicy::Join); 769 770 args = {"--str=one", "--str=two"}; 771 772 run(); 773 774 CHECK("one\ntwo" == str); 775 } 776 777 TEST_CASE_METHOD(TApp, "JoinOpt2", "[app]") { 778 779 std::string str; 780 app.add_option("--str", str)->join(); 781 782 args = {"--str=one", "--str=two"}; 783 784 run(); 785 786 CHECK("one\ntwo" == str); 787 } 788 789 TEST_CASE_METHOD(TApp, "TakeLastOptMulti", "[app]") { 790 std::vector<int> vals; 791 app.add_option("--long", vals)->expected(2)->take_last(); 792 793 args = {"--long", "1", "2", "3"}; 794 795 run(); 796 797 CHECK(std::vector<int>({2, 3}) == vals); 798 } 799 800 TEST_CASE_METHOD(TApp, "TakeLastOptMulti_alternative_path", "[app]") { 801 std::vector<int> vals; 802 app.add_option("--long", vals)->expected(2, -1)->take_last(); 803 804 args = {"--long", "1", "2", "3"}; 805 806 run(); 807 808 CHECK(std::vector<int>({2, 3}) == vals); 809 } 810 811 TEST_CASE_METHOD(TApp, "TakeLastOptMultiCheck", "[app]") { 812 std::vector<int> vals; 813 auto opt = app.add_option("--long", vals)->expected(-2)->take_last(); 814 815 opt->check(CLI::Validator(CLI::PositiveNumber).application_index(0)); 816 opt->check((!CLI::PositiveNumber).application_index(1)); 817 args = {"--long", "-1", "2", "-3"}; 818 819 CHECK_NOTHROW(run()); 820 821 CHECK(std::vector<int>({2, -3}) == vals); 822 } 823 824 TEST_CASE_METHOD(TApp, "TakeFirstOptMulti", "[app]") { 825 std::vector<int> vals; 826 app.add_option("--long", vals)->expected(2)->take_first(); 827 828 args = {"--long", "1", "2", "3"}; 829 830 run(); 831 832 CHECK(std::vector<int>({1, 2}) == vals); 833 } 834 835 TEST_CASE_METHOD(TApp, "ComplexOptMulti", "[app]") { 836 std::complex<double> val; 837 app.add_option("--long", val)->take_first()->allow_extra_args(); 838 839 args = {"--long", "1", "2", "3", "4"}; 840 841 run(); 842 843 CHECK(1 == Approx(val.real())); 844 CHECK(2 == Approx(val.imag())); 845 } 846 847 TEST_CASE_METHOD(TApp, "MissingValueNonRequiredOpt", "[app]") { 848 int count{0}; 849 app.add_option("-c,--count", count); 850 851 args = {"-c"}; 852 CHECK_THROWS_AS(run(), CLI::ArgumentMismatch); 853 854 args = {"--count"}; 855 CHECK_THROWS_AS(run(), CLI::ArgumentMismatch); 856 } 857 858 TEST_CASE_METHOD(TApp, "MissingValueMoreThan", "[app]") { 859 std::vector<int> vals1; 860 std::vector<int> vals2; 861 app.add_option("-v", vals1)->expected(-2); 862 app.add_option("--vals", vals2)->expected(-2); 863 864 args = {"-v", "2"}; 865 CHECK_THROWS_AS(run(), CLI::ArgumentMismatch); 866 867 args = {"--vals", "4"}; 868 CHECK_THROWS_AS(run(), CLI::ArgumentMismatch); 869 } 870 871 TEST_CASE_METHOD(TApp, "NoMissingValueMoreThan", "[app]") { 872 std::vector<int> vals1; 873 std::vector<int> vals2; 874 app.add_option("-v", vals1)->expected(-2); 875 app.add_option("--vals", vals2)->expected(-2); 876 877 args = {"-v", "2", "3", "4"}; 878 run(); 879 CHECK(std::vector<int>({2, 3, 4}) == vals1); 880 881 args = {"--vals", "2", "3", "4"}; 882 run(); 883 CHECK(std::vector<int>({2, 3, 4}) == vals2); 884 } 885 886 TEST_CASE_METHOD(TApp, "NotRequiredOptsSingle", "[app]") { 887 888 std::string str; 889 app.add_option("--str", str); 890 891 args = {"--str"}; 892 893 CHECK_THROWS_AS(run(), CLI::ArgumentMismatch); 894 } 895 896 TEST_CASE_METHOD(TApp, "NotRequiredOptsSingleShort", "[app]") { 897 898 std::string str; 899 app.add_option("-s", str); 900 901 args = {"-s"}; 902 903 CHECK_THROWS_AS(run(), CLI::ArgumentMismatch); 904 } 905 906 TEST_CASE_METHOD(TApp, "RequiredOptsSingle", "[app]") { 907 908 std::string str; 909 app.add_option("--str", str)->required(); 910 911 args = {"--str"}; 912 913 CHECK_THROWS_AS(run(), CLI::ArgumentMismatch); 914 } 915 916 TEST_CASE_METHOD(TApp, "RequiredOptsSingleShort", "[app]") { 917 918 std::string str; 919 app.add_option("-s", str)->required(); 920 921 args = {"-s"}; 922 923 CHECK_THROWS_AS(run(), CLI::ArgumentMismatch); 924 } 925 926 TEST_CASE_METHOD(TApp, "RequiredOptsDouble", "[app]") { 927 928 std::vector<std::string> strs; 929 app.add_option("--str", strs)->required()->expected(2); 930 931 args = {"--str", "one"}; 932 933 CHECK_THROWS_AS(run(), CLI::ArgumentMismatch); 934 935 args = {"--str", "one", "two"}; 936 937 run(); 938 939 CHECK(std::vector<std::string>({"one", "two"}) == strs); 940 } 941 942 TEST_CASE_METHOD(TApp, "RequiredOptsDoubleShort", "[app]") { 943 944 std::vector<std::string> strs; 945 app.add_option("-s", strs)->required()->expected(2); 946 947 args = {"-s", "one"}; 948 949 CHECK_THROWS_AS(run(), CLI::ArgumentMismatch); 950 951 args = {"-s", "one", "-s", "one", "-s", "one"}; 952 953 CHECK_THROWS_AS(run(), CLI::ArgumentMismatch); 954 } 955 956 TEST_CASE_METHOD(TApp, "RequiredOptsDoubleNeg", "[app]") { 957 std::vector<std::string> strs; 958 app.add_option("-s", strs)->required()->expected(-2); 959 960 args = {"-s", "one"}; 961 962 CHECK_THROWS_AS(run(), CLI::ArgumentMismatch); 963 964 args = {"-s", "one", "two", "-s", "three"}; 965 966 REQUIRE_NOTHROW(run()); 967 CHECK(std::vector<std::string>({"one", "two", "three"}) == strs); 968 969 args = {"-s", "one", "two"}; 970 REQUIRE_NOTHROW(run()); 971 CHECK(std::vector<std::string>({"one", "two"}) == strs); 972 } 973 974 // This makes sure unlimited option priority is 975 // correct for space vs. no space #90 976 TEST_CASE_METHOD(TApp, "PositionalNoSpace", "[app]") { 977 std::vector<std::string> options; 978 std::string foo, bar; 979 980 app.add_option("-O", options); 981 app.add_option("foo", foo)->required(); 982 app.add_option("bar", bar)->required(); 983 984 args = {"-O", "Test", "param1", "param2"}; 985 run(); 986 987 CHECK(1u == options.size()); 988 CHECK("Test" == options.at(0)); 989 990 args = {"-OTest", "param1", "param2"}; 991 run(); 992 993 CHECK(1u == options.size()); 994 CHECK("Test" == options.at(0)); 995 } 996 997 // Tests positionals at end 998 TEST_CASE_METHOD(TApp, "PositionalAtEnd", "[app]") { 999 std::string options; 1000 std::string foo; 1001 1002 app.add_option("-O", options); 1003 app.add_option("foo", foo); 1004 app.positionals_at_end(); 1005 CHECK(app.get_positionals_at_end()); 1006 args = {"-O", "Test", "param1"}; 1007 run(); 1008 1009 CHECK("Test" == options); 1010 CHECK("param1" == foo); 1011 1012 args = {"param2", "-O", "Test"}; 1013 CHECK_THROWS_AS(run(), CLI::ExtrasError); 1014 } 1015 1016 // Tests positionals at end 1017 TEST_CASE_METHOD(TApp, "RequiredPositionals", "[app]") { 1018 std::vector<std::string> sources; 1019 std::string dest; 1020 app.add_option("src", sources); 1021 app.add_option("dest", dest)->required(); 1022 app.positionals_at_end(); 1023 1024 args = {"1", "2", "3"}; 1025 run(); 1026 1027 CHECK(2u == sources.size()); 1028 CHECK("3" == dest); 1029 1030 args = {"a"}; 1031 sources.clear(); 1032 run(); 1033 1034 CHECK(0u == sources.size()); 1035 CHECK("a" == dest); 1036 } 1037 1038 TEST_CASE_METHOD(TApp, "RequiredPositionalVector", "[app]") { 1039 std::string d1; 1040 std::string d2; 1041 std::string d3; 1042 std::vector<std::string> sources; 1043 1044 app.add_option("dest1", d1); 1045 app.add_option("dest2", d2); 1046 app.add_option("dest3", d3); 1047 app.add_option("src", sources)->required(); 1048 1049 app.positionals_at_end(); 1050 1051 args = {"1", "2", "3"}; 1052 run(); 1053 1054 CHECK(1u == sources.size()); 1055 CHECK("1" == d1); 1056 CHECK("2" == d2); 1057 CHECK(d3.empty()); 1058 args = {"a"}; 1059 sources.clear(); 1060 run(); 1061 1062 CHECK(1u == sources.size()); 1063 } 1064 1065 // Tests positionals at end 1066 TEST_CASE_METHOD(TApp, "RequiredPositionalValidation", "[app]") { 1067 std::vector<std::string> sources; 1068 int dest; // required 1069 std::string d2; 1070 app.add_option("src", sources); 1071 app.add_option("dest", dest)->required()->check(CLI::PositiveNumber); 1072 app.add_option("dest2", d2)->required(); 1073 app.positionals_at_end()->validate_positionals(); 1074 1075 args = {"1", "2", "string", "3"}; 1076 run(); 1077 1078 CHECK(2u == sources.size()); 1079 CHECK(3 == dest); 1080 CHECK("string" == d2); 1081 } 1082 1083 // Tests positionals at end 1084 TEST_CASE_METHOD(TApp, "PositionalValidation", "[app]") { 1085 std::string options; 1086 std::string foo; 1087 1088 app.add_option("bar", options)->check(CLI::Number.name("valbar")); 1089 // disable the check on foo 1090 app.add_option("foo", foo)->check(CLI::Number.active(false)); 1091 app.validate_positionals(); 1092 args = {"1", "param1"}; 1093 run(); 1094 1095 CHECK("1" == options); 1096 CHECK("param1" == foo); 1097 1098 args = {"param1", "1"}; 1099 CHECK_NOTHROW(run()); 1100 1101 CHECK("1" == options); 1102 CHECK("param1" == foo); 1103 1104 CHECK(nullptr != app.get_option("bar")->get_validator("valbar")); 1105 } 1106 1107 TEST_CASE_METHOD(TApp, "PositionalNoSpaceLong", "[app]") { 1108 std::vector<std::string> options; 1109 std::string foo, bar; 1110 1111 app.add_option("--option", options); 1112 app.add_option("foo", foo)->required(); 1113 app.add_option("bar", bar)->required(); 1114 1115 args = {"--option", "Test", "param1", "param2"}; 1116 run(); 1117 1118 CHECK(1u == options.size()); 1119 CHECK("Test" == options.at(0)); 1120 1121 args = {"--option=Test", "param1", "param2"}; 1122 run(); 1123 1124 CHECK(1u == options.size()); 1125 CHECK("Test" == options.at(0)); 1126 } 1127 1128 TEST_CASE_METHOD(TApp, "RequiredOptsUnlimited", "[app]") { 1129 1130 std::vector<std::string> strs; 1131 app.add_option("--str", strs)->required(); 1132 1133 args = {"--str"}; 1134 CHECK_THROWS_AS(run(), CLI::ArgumentMismatch); 1135 1136 args = {"--str", "one", "--str", "two"}; 1137 run(); 1138 CHECK(std::vector<std::string>({"one", "two"}) == strs); 1139 1140 args = {"--str", "one", "two"}; 1141 run(); 1142 CHECK(std::vector<std::string>({"one", "two"}) == strs); 1143 1144 // It's better to feed a hungry option than to feed allow_extras 1145 app.allow_extras(); 1146 run(); 1147 CHECK(std::vector<std::string>({"one", "two"}) == strs); 1148 CHECK(std::vector<std::string>({}) == app.remaining()); 1149 1150 app.allow_extras(false); 1151 std::vector<std::string> remain; 1152 auto popt = app.add_option("positional", remain); 1153 run(); 1154 CHECK(std::vector<std::string>({"one", "two"}) == strs); 1155 CHECK(std::vector<std::string>() == remain); 1156 1157 args = {"--str", "one", "--", "two"}; 1158 1159 run(); 1160 CHECK(std::vector<std::string>({"one"}) == strs); 1161 CHECK(std::vector<std::string>({"two"}) == remain); 1162 1163 args = {"one", "--str", "two"}; 1164 1165 run(); 1166 CHECK(std::vector<std::string>({"two"}) == strs); 1167 CHECK(std::vector<std::string>({"one"}) == remain); 1168 1169 args = {"--str", "one", "two"}; 1170 popt->required(); 1171 run(); 1172 CHECK(std::vector<std::string>({"one"}) == strs); 1173 CHECK(std::vector<std::string>({"two"}) == remain); 1174 } 1175 1176 TEST_CASE_METHOD(TApp, "RequiredOptsUnlimitedShort", "[app]") { 1177 1178 std::vector<std::string> strs; 1179 app.add_option("-s", strs)->required(); 1180 1181 args = {"-s"}; 1182 CHECK_THROWS_AS(run(), CLI::ArgumentMismatch); 1183 1184 args = {"-s", "one", "-s", "two"}; 1185 run(); 1186 CHECK(std::vector<std::string>({"one", "two"}) == strs); 1187 1188 args = {"-s", "one", "two"}; 1189 run(); 1190 CHECK(std::vector<std::string>({"one", "two"}) == strs); 1191 1192 // It's better to feed a hungry option than to feed allow_extras 1193 app.allow_extras(); 1194 run(); 1195 CHECK(std::vector<std::string>({"one", "two"}) == strs); 1196 CHECK(std::vector<std::string>({}) == app.remaining()); 1197 1198 app.allow_extras(false); 1199 std::vector<std::string> remain; 1200 app.add_option("positional", remain); 1201 run(); 1202 CHECK(std::vector<std::string>({"one", "two"}) == strs); 1203 CHECK(std::vector<std::string>() == remain); 1204 1205 args = {"-s", "one", "--", "two"}; 1206 1207 run(); 1208 CHECK(std::vector<std::string>({"one"}) == strs); 1209 CHECK(std::vector<std::string>({"two"}) == remain); 1210 1211 args = {"one", "-s", "two"}; 1212 1213 run(); 1214 CHECK(std::vector<std::string>({"two"}) == strs); 1215 CHECK(std::vector<std::string>({"one"}) == remain); 1216 } 1217 1218 TEST_CASE_METHOD(TApp, "OptsUnlimitedEnd", "[app]") { 1219 std::vector<std::string> strs; 1220 app.add_option("-s,--str", strs); 1221 app.allow_extras(); 1222 1223 args = {"one", "-s", "two", "three", "--", "four"}; 1224 1225 run(); 1226 1227 CHECK(std::vector<std::string>({"two", "three"}) == strs); 1228 CHECK(std::vector<std::string>({"one", "four"}) == app.remaining()); 1229 } 1230 1231 TEST_CASE_METHOD(TApp, "RequireOptPriority", "[app]") { 1232 1233 std::vector<std::string> strs; 1234 app.add_option("--str", strs); 1235 std::vector<std::string> remain; 1236 app.add_option("positional", remain)->expected(2)->required(); 1237 1238 args = {"--str", "one", "two", "three"}; 1239 run(); 1240 1241 CHECK(std::vector<std::string>({"one"}) == strs); 1242 CHECK(std::vector<std::string>({"two", "three"}) == remain); 1243 1244 args = {"two", "three", "--str", "one", "four"}; 1245 run(); 1246 1247 CHECK(std::vector<std::string>({"one", "four"}) == strs); 1248 CHECK(std::vector<std::string>({"two", "three"}) == remain); 1249 } 1250 1251 TEST_CASE_METHOD(TApp, "RequireOptPriorityShort", "[app]") { 1252 1253 std::vector<std::string> strs; 1254 app.add_option("-s", strs)->required(); 1255 std::vector<std::string> remain; 1256 app.add_option("positional", remain)->expected(2)->required(); 1257 1258 args = {"-s", "one", "two", "three"}; 1259 run(); 1260 1261 CHECK(std::vector<std::string>({"one"}) == strs); 1262 CHECK(std::vector<std::string>({"two", "three"}) == remain); 1263 1264 args = {"two", "three", "-s", "one", "four"}; 1265 run(); 1266 1267 CHECK(std::vector<std::string>({"one", "four"}) == strs); 1268 CHECK(std::vector<std::string>({"two", "three"}) == remain); 1269 } 1270 1271 TEST_CASE_METHOD(TApp, "NotRequiredExpectedDouble", "[app]") { 1272 1273 std::vector<std::string> strs; 1274 app.add_option("--str", strs)->expected(2); 1275 1276 args = {"--str", "one"}; 1277 1278 CHECK_THROWS_AS(run(), CLI::ArgumentMismatch); 1279 } 1280 1281 TEST_CASE_METHOD(TApp, "NotRequiredExpectedDoubleShort", "[app]") { 1282 1283 std::vector<std::string> strs; 1284 app.add_option("-s", strs)->expected(2); 1285 1286 args = {"-s", "one"}; 1287 1288 CHECK_THROWS_AS(run(), CLI::ArgumentMismatch); 1289 } 1290 1291 TEST_CASE_METHOD(TApp, "RequiredFlags", "[app]") { 1292 app.add_flag("-a")->required(); 1293 app.add_flag("-b")->mandatory(); // Alternate term 1294 1295 CHECK_THROWS_AS(run(), CLI::RequiredError); 1296 1297 args = {"-a"}; 1298 CHECK_THROWS_AS(run(), CLI::RequiredError); 1299 1300 args = {"-b"}; 1301 CHECK_THROWS_AS(run(), CLI::RequiredError); 1302 1303 args = {"-a", "-b"}; 1304 run(); 1305 } 1306 1307 TEST_CASE_METHOD(TApp, "CallbackFlags", "[app]") { 1308 1309 std::int64_t value{0}; 1310 __anon9f71efcd0102(std::int64_t x) 1311 auto func = [&value](std::int64_t x) { value = x; }; 1312 1313 app.add_flag_function("-v", func); 1314 1315 run(); 1316 CHECK(0u == value); 1317 1318 args = {"-v"}; 1319 run(); 1320 CHECK(1u == value); 1321 1322 args = {"-vv"}; 1323 run(); 1324 CHECK(2u == value); 1325 1326 CHECK_THROWS_AS(app.add_flag_function("hi", func), CLI::IncorrectConstruction); 1327 } 1328 1329 TEST_CASE_METHOD(TApp, "CallbackFlagsFalse", "[app]") { 1330 std::int64_t value = 0; 1331 __anon9f71efcd0202(std::int64_t x) 1332 auto func = [&value](std::int64_t x) { value = x; }; 1333 1334 app.add_flag_function("-v,-f{false},--val,--fval{false}", func); 1335 1336 run(); 1337 CHECK(0 == value); 1338 1339 args = {"-f"}; 1340 run(); 1341 CHECK(-1 == value); 1342 1343 args = {"-vfv"}; 1344 run(); 1345 CHECK(1 == value); 1346 1347 args = {"--fval"}; 1348 run(); 1349 CHECK(-1 == value); 1350 1351 args = {"--fval=2"}; 1352 run(); 1353 CHECK(-2 == value); 1354 1355 CHECK_THROWS_AS(app.add_flag_function("hi", func), CLI::IncorrectConstruction); 1356 } 1357 1358 TEST_CASE_METHOD(TApp, "CallbackFlagsFalseShortcut", "[app]") { 1359 std::int64_t value = 0; 1360 __anon9f71efcd0302(std::int64_t x) 1361 auto func = [&value](std::int64_t x) { value = x; }; 1362 1363 app.add_flag_function("-v,!-f,--val,!--fval", func); 1364 1365 run(); 1366 CHECK(0 == value); 1367 1368 args = {"-f"}; 1369 run(); 1370 CHECK(-1 == value); 1371 1372 args = {"-vfv"}; 1373 run(); 1374 CHECK(1 == value); 1375 1376 args = {"--fval"}; 1377 run(); 1378 CHECK(-1 == value); 1379 1380 args = {"--fval=2"}; 1381 run(); 1382 CHECK(-2 == value); 1383 1384 CHECK_THROWS_AS(app.add_flag_function("hi", func), CLI::IncorrectConstruction); 1385 } 1386 1387 #if __cplusplus >= 201402L || _MSC_VER >= 1900 1388 TEST_CASE_METHOD(TApp, "CallbackFlagsAuto", "[app]") { 1389 1390 std::int64_t value{0}; 1391 __anon9f71efcd0402(std::int64_t x) 1392 auto func = [&value](std::int64_t x) { value = x; }; 1393 1394 app.add_flag("-v", func); 1395 1396 run(); 1397 CHECK(0u == value); 1398 1399 args = {"-v"}; 1400 run(); 1401 CHECK(1u == value); 1402 1403 args = {"-vv"}; 1404 run(); 1405 CHECK(2u == value); 1406 1407 CHECK_THROWS_AS(app.add_flag("hi", func), CLI::IncorrectConstruction); 1408 } 1409 #endif 1410 1411 TEST_CASE_METHOD(TApp, "Positionals", "[app]") { 1412 1413 std::string posit1; 1414 std::string posit2; 1415 app.add_option("posit1", posit1); 1416 app.add_option("posit2", posit2); 1417 1418 args = {"thing1", "thing2"}; 1419 1420 run(); 1421 1422 CHECK(app.count("posit1") == 1u); 1423 CHECK(app.count("posit2") == 1u); 1424 CHECK(posit1 == "thing1"); 1425 CHECK(posit2 == "thing2"); 1426 } 1427 1428 TEST_CASE_METHOD(TApp, "ForcedPositional", "[app]") { 1429 std::vector<std::string> posit; 1430 auto one = app.add_flag("--one"); 1431 app.add_option("posit", posit); 1432 1433 args = {"--one", "two", "three"}; 1434 run(); 1435 std::vector<std::string> answers1 = {"two", "three"}; 1436 CHECK(one->count()); 1437 CHECK(posit == answers1); 1438 1439 args = {"--", "--one", "two", "three"}; 1440 std::vector<std::string> answers2 = {"--one", "two", "three"}; 1441 run(); 1442 1443 CHECK(!one->count()); 1444 CHECK(posit == answers2); 1445 } 1446 1447 TEST_CASE_METHOD(TApp, "MixedPositionals", "[app]") { 1448 1449 int positional_int{0}; 1450 std::string positional_string; 1451 app.add_option("posit1,--posit1", positional_int, ""); 1452 app.add_option("posit2,--posit2", positional_string, ""); 1453 1454 args = {"--posit2", "thing2", "7"}; 1455 1456 run(); 1457 1458 CHECK(app.count("posit2") == 1u); 1459 CHECK(app.count("--posit1") == 1u); 1460 CHECK(positional_int == 7); 1461 CHECK(positional_string == "thing2"); 1462 } 1463 1464 TEST_CASE_METHOD(TApp, "BigPositional", "[app]") { 1465 std::vector<std::string> vec; 1466 app.add_option("pos", vec); 1467 1468 args = {"one"}; 1469 1470 run(); 1471 CHECK(vec == args); 1472 1473 args = {"one", "two"}; 1474 run(); 1475 1476 CHECK(vec == args); 1477 } 1478 1479 TEST_CASE_METHOD(TApp, "Reset", "[app]") { 1480 1481 app.add_flag("--simple"); 1482 double doub{0.0}; 1483 app.add_option("-d,--double", doub); 1484 1485 args = {"--simple", "--double", "1.2"}; 1486 1487 run(); 1488 1489 CHECK(app.count("--simple") == 1u); 1490 CHECK(app.count("-d") == 1u); 1491 CHECK(doub == Approx(1.2)); 1492 1493 app.clear(); 1494 1495 CHECK(app.count("--simple") == 0u); 1496 CHECK(app.count("-d") == 0u); 1497 1498 run(); 1499 1500 CHECK(app.count("--simple") == 1u); 1501 CHECK(app.count("-d") == 1u); 1502 CHECK(doub == Approx(1.2)); 1503 } 1504 1505 TEST_CASE_METHOD(TApp, "RemoveOption", "[app]") { 1506 app.add_flag("--one"); 1507 auto opt = app.add_flag("--two"); 1508 1509 CHECK(app.remove_option(opt)); 1510 CHECK(!app.remove_option(opt)); 1511 1512 args = {"--two"}; 1513 1514 CHECK_THROWS_AS(run(), CLI::ExtrasError); 1515 } 1516 1517 TEST_CASE_METHOD(TApp, "RemoveNeedsLinks", "[app]") { 1518 auto one = app.add_flag("--one"); 1519 auto two = app.add_flag("--two"); 1520 1521 two->needs(one); 1522 one->needs(two); 1523 1524 CHECK(app.remove_option(one)); 1525 1526 args = {"--two"}; 1527 1528 run(); 1529 } 1530 1531 TEST_CASE_METHOD(TApp, "RemoveExcludesLinks", "[app]") { 1532 auto one = app.add_flag("--one"); 1533 auto two = app.add_flag("--two"); 1534 1535 two->excludes(one); 1536 one->excludes(two); 1537 1538 CHECK(app.remove_option(one)); 1539 1540 args = {"--two"}; 1541 1542 run(); // Mostly hoping it does not crash 1543 } 1544 1545 TEST_CASE_METHOD(TApp, "FileNotExists", "[app]") { 1546 std::string myfile{"TestNonFileNotUsed.txt"}; 1547 REQUIRE_NOTHROW(CLI::NonexistentPath(myfile)); 1548 1549 std::string filename; 1550 auto opt = app.add_option("--file", filename)->check(CLI::NonexistentPath, "path_check"); 1551 args = {"--file", myfile}; 1552 1553 run(); 1554 CHECK(filename == myfile); 1555 1556 bool ok = static_cast<bool>(std::ofstream(myfile.c_str()).put('a')); // create file 1557 CHECK(ok); 1558 CHECK_THROWS_AS(run(), CLI::ValidationError); 1559 // deactivate the check, so it should run now 1560 opt->get_validator("path_check")->active(false); 1561 CHECK_NOTHROW(run()); 1562 std::remove(myfile.c_str()); 1563 CHECK(!CLI::ExistingFile(myfile).empty()); 1564 } 1565 1566 TEST_CASE_METHOD(TApp, "FileExists", "[app]") { 1567 std::string myfile{"TestNonFileNotUsed.txt"}; 1568 CHECK(!CLI::ExistingFile(myfile).empty()); 1569 1570 std::string filename = "Failed"; 1571 app.add_option("--file", filename)->check(CLI::ExistingFile); 1572 args = {"--file", myfile}; 1573 1574 CHECK_THROWS_AS(run(), CLI::ValidationError); 1575 1576 bool ok = static_cast<bool>(std::ofstream(myfile.c_str()).put('a')); // create file 1577 CHECK(ok); 1578 run(); 1579 CHECK(filename == myfile); 1580 1581 std::remove(myfile.c_str()); 1582 CHECK(!CLI::ExistingFile(myfile).empty()); 1583 } 1584 1585 TEST_CASE_METHOD(TApp, "NotFileExists", "[app]") { 1586 std::string myfile{"TestNonFileNotUsed.txt"}; 1587 CHECK(!CLI::ExistingFile(myfile).empty()); 1588 1589 std::string filename = "Failed"; 1590 app.add_option("--file", filename)->check(!CLI::ExistingFile); 1591 args = {"--file", myfile}; 1592 1593 CHECK_NOTHROW(run()); 1594 1595 bool ok = static_cast<bool>(std::ofstream(myfile.c_str()).put('a')); // create file 1596 CHECK(ok); 1597 CHECK_THROWS_AS(run(), CLI::ValidationError); 1598 1599 std::remove(myfile.c_str()); 1600 CHECK(!CLI::ExistingFile(myfile).empty()); 1601 } 1602 1603 TEST_CASE_METHOD(TApp, "DefaultedResult", "[app]") { 1604 std::string sval = "NA"; 1605 int ival{0}; 1606 auto opts = app.add_option("--string", sval)->capture_default_str(); 1607 auto optv = app.add_option("--val", ival); 1608 args = {}; 1609 run(); 1610 CHECK("NA" == sval); 1611 std::string nString; 1612 opts->results(nString); 1613 CHECK("NA" == nString); 1614 int newIval; 1615 // CHECK_THROWS_AS (optv->results(newIval), CLI::ConversionError); 1616 optv->default_str("442"); 1617 optv->results(newIval); 1618 CHECK(442 == newIval); 1619 } 1620 1621 TEST_CASE_METHOD(TApp, "OriginalOrder", "[app]") { 1622 std::vector<int> st1; 1623 CLI::Option *op1 = app.add_option("-a", st1); 1624 std::vector<int> st2; 1625 CLI::Option *op2 = app.add_option("-b", st2); 1626 1627 args = {"-a", "1", "-b", "2", "-a3", "-a", "4"}; 1628 1629 run(); 1630 1631 CHECK(std::vector<int>({1, 3, 4}) == st1); 1632 CHECK(std::vector<int>({2}) == st2); 1633 1634 CHECK(std::vector<CLI::Option *>({op1, op2, op1, op1}) == app.parse_order()); 1635 } 1636 1637 TEST_CASE_METHOD(TApp, "NeedsFlags", "[app]") { 1638 CLI::Option *opt = app.add_flag("-s,--string"); 1639 app.add_flag("--both")->needs(opt); 1640 1641 run(); 1642 1643 args = {"-s"}; 1644 run(); 1645 1646 args = {"-s", "--both"}; 1647 run(); 1648 1649 args = {"--both"}; 1650 CHECK_THROWS_AS(run(), CLI::RequiresError); 1651 1652 CHECK_NOTHROW(opt->needs(opt)); 1653 } 1654 1655 TEST_CASE_METHOD(TApp, "ExcludesFlags", "[app]") { 1656 CLI::Option *opt = app.add_flag("-s,--string"); 1657 app.add_flag("--nostr")->excludes(opt); 1658 1659 run(); 1660 1661 args = {"-s"}; 1662 run(); 1663 1664 args = {"--nostr"}; 1665 run(); 1666 1667 args = {"--nostr", "-s"}; 1668 CHECK_THROWS_AS(run(), CLI::ExcludesError); 1669 1670 args = {"--string", "--nostr"}; 1671 CHECK_THROWS_AS(run(), CLI::ExcludesError); 1672 1673 CHECK_THROWS_AS(opt->excludes(opt), CLI::IncorrectConstruction); 1674 } 1675 1676 TEST_CASE_METHOD(TApp, "ExcludesMixedFlags", "[app]") { 1677 CLI::Option *opt1 = app.add_flag("--opt1"); 1678 app.add_flag("--opt2"); 1679 CLI::Option *opt3 = app.add_flag("--opt3"); 1680 app.add_flag("--no")->excludes(opt1, "--opt2", opt3); 1681 1682 run(); 1683 1684 args = {"--no"}; 1685 run(); 1686 1687 args = {"--opt2"}; 1688 run(); 1689 1690 args = {"--no", "--opt1"}; 1691 CHECK_THROWS_AS(run(), CLI::ExcludesError); 1692 1693 args = {"--no", "--opt2"}; 1694 CHECK_THROWS_AS(run(), CLI::ExcludesError); 1695 } 1696 1697 TEST_CASE_METHOD(TApp, "NeedsMultiFlags", "[app]") { 1698 CLI::Option *opt1 = app.add_flag("--opt1"); 1699 CLI::Option *opt2 = app.add_flag("--opt2"); 1700 CLI::Option *opt3 = app.add_flag("--opt3"); 1701 app.add_flag("--optall")->needs(opt1, opt2, opt3); 1702 1703 run(); 1704 1705 args = {"--opt1"}; 1706 run(); 1707 1708 args = {"--opt2"}; 1709 run(); 1710 1711 args = {"--optall"}; 1712 CHECK_THROWS_AS(run(), CLI::RequiresError); 1713 1714 args = {"--optall", "--opt1"}; 1715 CHECK_THROWS_AS(run(), CLI::RequiresError); 1716 1717 args = {"--optall", "--opt2", "--opt1"}; 1718 CHECK_THROWS_AS(run(), CLI::RequiresError); 1719 1720 args = {"--optall", "--opt1", "--opt2", "--opt3"}; 1721 run(); 1722 } 1723 1724 TEST_CASE_METHOD(TApp, "NeedsMixedFlags", "[app]") { 1725 CLI::Option *opt1 = app.add_flag("--opt1"); 1726 app.add_flag("--opt2"); 1727 app.add_flag("--opt3"); 1728 app.add_flag("--optall")->needs(opt1, "--opt2", "--opt3"); 1729 1730 run(); 1731 1732 args = {"--opt1"}; 1733 run(); 1734 1735 args = {"--opt2"}; 1736 run(); 1737 1738 args = {"--optall"}; 1739 CHECK_THROWS_AS(run(), CLI::RequiresError); 1740 1741 args = {"--optall", "--opt1"}; 1742 CHECK_THROWS_AS(run(), CLI::RequiresError); 1743 1744 args = {"--optall", "--opt2", "--opt1"}; 1745 CHECK_THROWS_AS(run(), CLI::RequiresError); 1746 1747 args = {"--optall", "--opt1", "--opt2", "--opt3"}; 1748 run(); 1749 } 1750 1751 TEST_CASE_METHOD(TApp, "NeedsChainedFlags", "[app]") { 1752 CLI::Option *opt1 = app.add_flag("--opt1"); 1753 CLI::Option *opt2 = app.add_flag("--opt2")->needs(opt1); 1754 app.add_flag("--opt3")->needs(opt2); 1755 1756 run(); 1757 1758 args = {"--opt1"}; 1759 run(); 1760 1761 args = {"--opt2"}; 1762 CHECK_THROWS_AS(run(), CLI::RequiresError); 1763 1764 args = {"--opt3"}; 1765 CHECK_THROWS_AS(run(), CLI::RequiresError); 1766 1767 args = {"--opt3", "--opt2"}; 1768 CHECK_THROWS_AS(run(), CLI::RequiresError); 1769 1770 args = {"--opt3", "--opt1"}; 1771 CHECK_THROWS_AS(run(), CLI::RequiresError); 1772 1773 args = {"--opt2", "--opt1"}; 1774 run(); 1775 1776 args = {"--opt1", "--opt2", "--opt3"}; 1777 run(); 1778 } 1779 1780 TEST_CASE_METHOD(TApp, "Env", "[app]") { 1781 1782 put_env("CLI11_TEST_ENV_TMP", "2"); 1783 1784 int val{1}; 1785 CLI::Option *vopt = app.add_option("--tmp", val)->envname("CLI11_TEST_ENV_TMP"); 1786 1787 run(); 1788 1789 CHECK(val == 2); 1790 CHECK(vopt->count() == 1u); 1791 1792 vopt->required(); 1793 run(); 1794 1795 unset_env("CLI11_TEST_ENV_TMP"); 1796 CHECK_THROWS_AS(run(), CLI::RequiredError); 1797 } 1798 1799 // curiously check if an environmental only option works 1800 TEST_CASE_METHOD(TApp, "EnvOnly", "[app]") { 1801 1802 put_env("CLI11_TEST_ENV_TMP", "2"); 1803 1804 int val{1}; 1805 CLI::Option *vopt = app.add_option("", val)->envname("CLI11_TEST_ENV_TMP"); 1806 1807 run(); 1808 1809 CHECK(val == 2); 1810 CHECK(vopt->count() == 1u); 1811 1812 vopt->required(); 1813 run(); 1814 1815 unset_env("CLI11_TEST_ENV_TMP"); 1816 CHECK_THROWS_AS(run(), CLI::RequiredError); 1817 } 1818 1819 TEST_CASE_METHOD(TApp, "RangeInt", "[app]") { 1820 int x{0}; 1821 app.add_option("--one", x)->check(CLI::Range(3, 6)); 1822 1823 args = {"--one=1"}; 1824 CHECK_THROWS_AS(run(), CLI::ValidationError); 1825 1826 args = {"--one=7"}; 1827 CHECK_THROWS_AS(run(), CLI::ValidationError); 1828 1829 args = {"--one=3"}; 1830 run(); 1831 1832 args = {"--one=5"}; 1833 run(); 1834 1835 args = {"--one=6"}; 1836 run(); 1837 } 1838 1839 TEST_CASE_METHOD(TApp, "RangeDouble", "[app]") { 1840 1841 double x{0.0}; 1842 /// Note that this must be a double in Range, too 1843 app.add_option("--one", x)->check(CLI::Range(3.0, 6.0)); 1844 1845 args = {"--one=1"}; 1846 CHECK_THROWS_AS(run(), CLI::ValidationError); 1847 1848 args = {"--one=7"}; 1849 CHECK_THROWS_AS(run(), CLI::ValidationError); 1850 1851 args = {"--one=3"}; 1852 run(); 1853 1854 args = {"--one=5"}; 1855 run(); 1856 1857 args = {"--one=6"}; 1858 run(); 1859 } 1860 1861 TEST_CASE_METHOD(TApp, "typeCheck", "[app]") { 1862 1863 /// Note that this must be a double in Range, too 1864 app.add_option("--one")->check(CLI::TypeValidator<unsigned int>()); 1865 1866 args = {"--one=1"}; 1867 CHECK_NOTHROW(run()); 1868 1869 args = {"--one=-7"}; 1870 CHECK_THROWS_AS(run(), CLI::ValidationError); 1871 1872 args = {"--one=error"}; 1873 CHECK_THROWS_AS(run(), CLI::ValidationError); 1874 1875 args = {"--one=4.568"}; 1876 CHECK_THROWS_AS(run(), CLI::ValidationError); 1877 } 1878 1879 // Check to make sure programmatic access to left over is available 1880 TEST_CASE_METHOD(TApp, "AllowExtras", "[app]") { 1881 1882 app.allow_extras(); 1883 1884 bool val{true}; 1885 app.add_flag("-f", val); 1886 1887 args = {"-x", "-f"}; 1888 1889 REQUIRE_NOTHROW(run()); 1890 CHECK(val); 1891 CHECK(std::vector<std::string>({"-x"}) == app.remaining()); 1892 } 1893 1894 TEST_CASE_METHOD(TApp, "AllowExtrasOrder", "[app]") { 1895 1896 app.allow_extras(); 1897 1898 args = {"-x", "-f"}; 1899 REQUIRE_NOTHROW(run()); 1900 CHECK(std::vector<std::string>({"-x", "-f"}) == app.remaining()); 1901 1902 std::vector<std::string> left_over = app.remaining(); 1903 app.parse(left_over); 1904 CHECK(std::vector<std::string>({"-f", "-x"}) == app.remaining()); 1905 CHECK(left_over == app.remaining_for_passthrough()); 1906 } 1907 1908 TEST_CASE_METHOD(TApp, "AllowExtrasCascade", "[app]") { 1909 1910 app.allow_extras(); 1911 1912 args = {"-x", "45", "-f", "27"}; 1913 REQUIRE_NOTHROW(run()); 1914 CHECK(std::vector<std::string>({"-x", "45", "-f", "27"}) == app.remaining()); 1915 1916 std::vector<std::string> left_over = app.remaining_for_passthrough(); 1917 1918 CLI::App capp{"cascade_program"}; 1919 int v1 = 0; 1920 int v2 = 0; 1921 capp.add_option("-x", v1); 1922 capp.add_option("-f", v2); 1923 1924 capp.parse(left_over); 1925 CHECK(45 == v1); 1926 CHECK(27 == v2); 1927 } 1928 // makes sure the error throws on the rValue version of the parse 1929 TEST_CASE_METHOD(TApp, "ExtrasErrorRvalueParse", "[app]") { 1930 1931 args = {"-x", "45", "-f", "27"}; 1932 CHECK_THROWS_AS(app.parse(std::vector<std::string>({"-x", "45", "-f", "27"})), CLI::ExtrasError); 1933 } 1934 1935 TEST_CASE_METHOD(TApp, "AllowExtrasCascadeDirect", "[app]") { 1936 1937 app.allow_extras(); 1938 1939 args = {"-x", "45", "-f", "27"}; 1940 REQUIRE_NOTHROW(run()); 1941 CHECK(std::vector<std::string>({"-x", "45", "-f", "27"}) == app.remaining()); 1942 1943 CLI::App capp{"cascade_program"}; 1944 int v1{0}; 1945 int v2{0}; 1946 capp.add_option("-x", v1); 1947 capp.add_option("-f", v2); 1948 1949 capp.parse(app.remaining_for_passthrough()); 1950 CHECK(45 == v1); 1951 CHECK(27 == v2); 1952 } 1953 1954 TEST_CASE_METHOD(TApp, "AllowExtrasArgModify", "[app]") { 1955 1956 int v1{0}; 1957 int v2{0}; 1958 app.allow_extras(); 1959 app.add_option("-f", v2); 1960 args = {"27", "-f", "45", "-x"}; 1961 app.parse(args); 1962 CHECK(std::vector<std::string>({"45", "-x"}) == args); 1963 1964 CLI::App capp{"cascade_program"}; 1965 1966 capp.add_option("-x", v1); 1967 1968 capp.parse(args); 1969 CHECK(45 == v1); 1970 CHECK(27 == v2); 1971 } 1972 1973 // Test horrible error 1974 TEST_CASE_METHOD(TApp, "CheckShortFail", "[app]") { 1975 args = {"--two"}; 1976 1977 CHECK_THROWS_AS(CLI::detail::AppFriend::parse_arg(&app, args, CLI::detail::Classifier::SHORT), CLI::HorribleError); 1978 } 1979 1980 // Test horrible error 1981 TEST_CASE_METHOD(TApp, "CheckLongFail", "[app]") { 1982 args = {"-t"}; 1983 1984 CHECK_THROWS_AS(CLI::detail::AppFriend::parse_arg(&app, args, CLI::detail::Classifier::LONG), CLI::HorribleError); 1985 } 1986 1987 // Test horrible error 1988 TEST_CASE_METHOD(TApp, "CheckWindowsFail", "[app]") { 1989 args = {"-t"}; 1990 1991 CHECK_THROWS_AS(CLI::detail::AppFriend::parse_arg(&app, args, CLI::detail::Classifier::WINDOWS_STYLE), 1992 CLI::HorribleError); 1993 } 1994 1995 // Test horrible error 1996 TEST_CASE_METHOD(TApp, "CheckOtherFail", "[app]") { 1997 args = {"-t"}; 1998 1999 CHECK_THROWS_AS(CLI::detail::AppFriend::parse_arg(&app, args, CLI::detail::Classifier::NONE), CLI::HorribleError); 2000 } 2001 2002 // Test horrible error 2003 TEST_CASE_METHOD(TApp, "CheckSubcomFail", "[app]") { 2004 args = {"subcom"}; 2005 2006 CHECK_THROWS_AS(CLI::detail::AppFriend::parse_subcommand(&app, args), CLI::HorribleError); 2007 } 2008 2009 TEST_CASE_METHOD(TApp, "FallthroughParentFail", "[app]") { 2010 CHECK_THROWS_AS(CLI::detail::AppFriend::get_fallthrough_parent(&app), CLI::HorribleError); 2011 } 2012 2013 TEST_CASE_METHOD(TApp, "FallthroughParents", "[app]") { 2014 auto sub = app.add_subcommand("test"); 2015 CHECK(&app == CLI::detail::AppFriend::get_fallthrough_parent(sub)); 2016 2017 auto ssub = sub->add_subcommand("sub2"); 2018 CHECK(sub == CLI::detail::AppFriend::get_fallthrough_parent(ssub)); 2019 2020 auto og1 = app.add_option_group("g1"); 2021 auto og2 = og1->add_option_group("g2"); 2022 auto og3 = og2->add_option_group("g3"); 2023 CHECK(&app == CLI::detail::AppFriend::get_fallthrough_parent(og3)); 2024 2025 auto ogb1 = sub->add_option_group("g1"); 2026 auto ogb2 = ogb1->add_option_group("g2"); 2027 auto ogb3 = ogb2->add_option_group("g3"); 2028 CHECK(sub == CLI::detail::AppFriend::get_fallthrough_parent(ogb3)); 2029 2030 ogb2->name("groupb"); 2031 CHECK(ogb2 == CLI::detail::AppFriend::get_fallthrough_parent(ogb3)); 2032 } 2033 2034 TEST_CASE_METHOD(TApp, "OptionWithDefaults", "[app]") { 2035 int someint{2}; 2036 app.add_option("-a", someint)->capture_default_str(); 2037 2038 args = {"-a1", "-a2"}; 2039 2040 CHECK_THROWS_AS(run(), CLI::ArgumentMismatch); 2041 } 2042 2043 // Added to test ->transform 2044 TEST_CASE_METHOD(TApp, "OrderedModifyingTransforms", "[app]") { 2045 std::vector<std::string> val; 2046 auto m = app.add_option("-m", val); __anon9f71efcd0502(std::string x) 2047 m->transform([](std::string x) { return x + "1"; }); __anon9f71efcd0602(std::string x) 2048 m->transform([](std::string x) { return x + "2"; }); 2049 2050 args = {"-mone", "-mtwo"}; 2051 2052 run(); 2053 2054 CHECK(std::vector<std::string>({"one21", "two21"}) == val); 2055 } 2056 2057 TEST_CASE_METHOD(TApp, "ThrowingTransform", "[app]") { 2058 std::string val; 2059 auto m = app.add_option("-m,--mess", val); __anon9f71efcd0702(std::string) 2060 m->transform([](std::string) -> std::string { throw CLI::ValidationError("My Message"); }); 2061 2062 REQUIRE_NOTHROW(run()); 2063 2064 args = {"-mone"}; 2065 2066 REQUIRE_THROWS_AS(run(), CLI::ValidationError); 2067 2068 try { 2069 run(); 2070 } catch(const CLI::ValidationError &e) { 2071 CHECK(std::string("--mess: My Message") == e.what()); 2072 } 2073 } 2074 2075 // This was added to make running a simple function on each item easier 2076 TEST_CASE_METHOD(TApp, "EachItem", "[app]") { 2077 2078 std::vector<std::string> results; 2079 std::vector<std::string> dummy; 2080 2081 auto opt = app.add_option("--vec", dummy); 2082 __anon9f71efcd0802(std::string item) 2083 opt->each([&results](std::string item) { results.push_back(item); }); 2084 2085 args = {"--vec", "one", "two", "three"}; 2086 2087 run(); 2088 2089 CHECK(dummy == results); 2090 } 2091 2092 // #128 2093 TEST_CASE_METHOD(TApp, "RepeatingMultiArgumentOptions", "[app]") { 2094 std::vector<std::string> entries; 2095 app.add_option("--entry", entries, "set a key and value")->type_name("KEY VALUE")->type_size(-2); 2096 2097 args = {"--entry", "key1", "value1", "--entry", "key2", "value2"}; 2098 REQUIRE_NOTHROW(run()); 2099 CHECK(std::vector<std::string>({"key1", "value1", "key2", "value2"}) == entries); 2100 2101 args.pop_back(); 2102 REQUIRE_THROWS_AS(run(), CLI::ArgumentMismatch); 2103 } 2104 2105 // #122 2106 TEST_CASE_METHOD(TApp, "EmptyOptionEach", "[app]") { 2107 std::string q; __anon9f71efcd0902(std::string s) 2108 app.add_option("--each")->each([&q](std::string s) { q = s; }); 2109 2110 args = {"--each", "that"}; 2111 run(); 2112 2113 CHECK("that" == q); 2114 } 2115 2116 // #122 2117 TEST_CASE_METHOD(TApp, "EmptyOptionFail", "[app]") { 2118 std::string q; 2119 app.add_option("--each"); 2120 2121 args = {"--each", "that"}; 2122 run(); 2123 } 2124 2125 TEST_CASE_METHOD(TApp, "BeforeRequirements", "[app]") { __anon9f71efcd0a02(std::int64_t) 2126 app.add_flag_function("-a", [](std::int64_t) { throw CLI::Success(); }); __anon9f71efcd0b02(std::int64_t) 2127 app.add_flag_function("-b", [](std::int64_t) { throw CLI::CallForHelp(); }); 2128 2129 args = {"extra"}; 2130 CHECK_THROWS_AS(run(), CLI::ExtrasError); 2131 2132 args = {"-a", "extra"}; 2133 CHECK_THROWS_AS(run(), CLI::Success); 2134 2135 args = {"-b", "extra"}; 2136 CHECK_THROWS_AS(run(), CLI::CallForHelp); 2137 2138 // These run in definition order. 2139 args = {"-a", "-b", "extra"}; 2140 CHECK_THROWS_AS(run(), CLI::Success); 2141 2142 // Currently, the original order is not preserved when calling callbacks 2143 // args = {"-b", "-a", "extra"}; 2144 // CHECK_THROWS_AS (run(), CLI::CallForHelp); 2145 } 2146 2147 // #209 2148 TEST_CASE_METHOD(TApp, "CustomUserSepParse", "[app]") { 2149 2150 std::vector<int> vals{1, 2, 3}; 2151 args = {"--idx", "1,2,3"}; 2152 auto opt = app.add_option("--idx", vals)->delimiter(','); 2153 run(); 2154 CHECK(std::vector<int>({1, 2, 3}) == vals); 2155 std::vector<int> vals2; 2156 // check that the results vector gets the results in the same way 2157 opt->results(vals2); 2158 CHECK(vals == vals2); 2159 2160 app.remove_option(opt); 2161 2162 app.add_option("--idx", vals)->delimiter(',')->capture_default_str(); 2163 run(); 2164 CHECK(std::vector<int>({1, 2, 3}) == vals); 2165 } 2166 2167 // #209 2168 TEST_CASE_METHOD(TApp, "DefaultUserSepParse", "[app]") { 2169 2170 std::vector<std::string> vals; 2171 args = {"--idx", "1 2 3", "4 5 6"}; 2172 auto opt = app.add_option("--idx", vals, ""); 2173 run(); 2174 CHECK(std::vector<std::string>({"1 2 3", "4 5 6"}) == vals); 2175 opt->delimiter(','); 2176 run(); 2177 CHECK(std::vector<std::string>({"1 2 3", "4 5 6"}) == vals); 2178 } 2179 2180 // #209 2181 TEST_CASE_METHOD(TApp, "BadUserSepParse", "[app]") { 2182 2183 std::vector<int> vals; 2184 app.add_option("--idx", vals); 2185 2186 args = {"--idx", "1,2,3"}; 2187 2188 CHECK_THROWS_AS(run(), CLI::ConversionError); 2189 } 2190 2191 // #209 2192 TEST_CASE_METHOD(TApp, "CustomUserSepParse2", "[app]") { 2193 2194 std::vector<int> vals{1, 2, 3}; 2195 args = {"--idx", "1,2,"}; 2196 auto opt = app.add_option("--idx", vals)->delimiter(','); 2197 run(); 2198 CHECK(std::vector<int>({1, 2}) == vals); 2199 2200 app.remove_option(opt); 2201 2202 app.add_option("--idx", vals, "")->delimiter(',')->capture_default_str(); 2203 run(); 2204 CHECK(std::vector<int>({1, 2}) == vals); 2205 } 2206 2207 TEST_CASE_METHOD(TApp, "CustomUserSepParseFunction", "[app]") { 2208 2209 std::vector<int> vals{1, 2, 3}; 2210 args = {"--idx", "1,2,3"}; __anon9f71efcd0c02(std::vector<int> v) 2211 app.add_option_function<std::vector<int>>("--idx", [&vals](std::vector<int> v) { vals = std::move(v); }) 2212 ->delimiter(','); 2213 run(); 2214 CHECK(std::vector<int>({1, 2, 3}) == vals); 2215 } 2216 2217 // delimiter removal 2218 TEST_CASE_METHOD(TApp, "CustomUserSepParseToggle", "[app]") { 2219 2220 std::vector<std::string> vals; 2221 args = {"--idx", "1,2,3"}; 2222 auto opt = app.add_option("--idx", vals)->delimiter(','); 2223 run(); 2224 CHECK(std::vector<std::string>({"1", "2", "3"}) == vals); 2225 opt->delimiter('\0'); 2226 run(); 2227 CHECK(std::vector<std::string>({"1,2,3"}) == vals); 2228 opt->delimiter(','); 2229 run(); 2230 CHECK(std::vector<std::string>({"1", "2", "3"}) == vals); 2231 } 2232 2233 // #209 2234 TEST_CASE_METHOD(TApp, "CustomUserSepParse3", "[app]") { 2235 2236 std::vector<int> vals = {1, 2, 3}; 2237 args = {"--idx", 2238 "1", 2239 "," 2240 "2"}; 2241 auto opt = app.add_option("--idx", vals)->delimiter(','); 2242 run(); 2243 CHECK(std::vector<int>({1, 2}) == vals); 2244 app.remove_option(opt); 2245 2246 app.add_option("--idx", vals)->delimiter(','); 2247 run(); 2248 CHECK(std::vector<int>({1, 2}) == vals); 2249 } 2250 2251 // #209 2252 TEST_CASE_METHOD(TApp, "CustomUserSepParse4", "[app]") { 2253 2254 std::vector<int> vals; 2255 args = {"--idx", "1, 2"}; 2256 auto opt = app.add_option("--idx", vals)->delimiter(',')->capture_default_str(); 2257 run(); 2258 CHECK(std::vector<int>({1, 2}) == vals); 2259 2260 app.remove_option(opt); 2261 2262 app.add_option("--idx", vals)->delimiter(','); 2263 run(); 2264 CHECK(std::vector<int>({1, 2}) == vals); 2265 } 2266 2267 // #218 2268 TEST_CASE_METHOD(TApp, "CustomUserSepParse5", "[app]") { 2269 2270 std::vector<std::string> bar; 2271 args = {"this", "is", "a", "test"}; 2272 auto opt = app.add_option("bar", bar, "bar"); 2273 run(); 2274 CHECK(std::vector<std::string>({"this", "is", "a", "test"}) == bar); 2275 2276 app.remove_option(opt); 2277 args = {"this", "is", "a", "test"}; 2278 app.add_option("bar", bar, "bar")->capture_default_str(); 2279 run(); 2280 CHECK(std::vector<std::string>({"this", "is", "a", "test"}) == bar); 2281 } 2282 2283 // #218 2284 TEST_CASE_METHOD(TApp, "logFormSingleDash", "[app]") { 2285 bool verbose{false}; 2286 bool veryverbose{false}; 2287 bool veryveryverbose{false}; 2288 app.name("testargs"); 2289 app.allow_extras(); 2290 args = {"-v", "-vv", "-vvv"}; __anon9f71efcd0d02() 2291 app.final_callback([&]() { 2292 auto rem = app.remaining(); 2293 for(auto &arg : rem) { 2294 if(arg == "-v") { 2295 verbose = true; 2296 } 2297 if(arg == "-vv") { 2298 veryverbose = true; 2299 } 2300 if(arg == "-vvv") { 2301 veryveryverbose = true; 2302 } 2303 } 2304 }); 2305 run(); 2306 CHECK(app.remaining().size() == 3U); 2307 CHECK(verbose); 2308 CHECK(veryverbose); 2309 CHECK(veryveryverbose); 2310 } 2311