1 //===- llvm/unittest/Support/CommandLineTest.cpp - CommandLine tests ------===// 2 // 3 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 4 // See https://llvm.org/LICENSE.txt for license information. 5 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 6 // 7 //===----------------------------------------------------------------------===// 8 9 #include "llvm/Support/CommandLine.h" 10 #include "llvm/ADT/STLExtras.h" 11 #include "llvm/ADT/SmallString.h" 12 #include "llvm/ADT/Triple.h" 13 #include "llvm/Config/config.h" 14 #include "llvm/Support/FileSystem.h" 15 #include "llvm/Support/InitLLVM.h" 16 #include "llvm/Support/MemoryBuffer.h" 17 #include "llvm/Support/Path.h" 18 #include "llvm/Support/Program.h" 19 #include "llvm/Support/StringSaver.h" 20 #include "gtest/gtest.h" 21 #include <fstream> 22 #include <stdlib.h> 23 #include <string> 24 25 using namespace llvm; 26 27 namespace { 28 29 class TempEnvVar { 30 public: 31 TempEnvVar(const char *name, const char *value) 32 : name(name) { 33 const char *old_value = getenv(name); 34 EXPECT_EQ(nullptr, old_value) << old_value; 35 #if HAVE_SETENV 36 setenv(name, value, true); 37 #else 38 # define SKIP_ENVIRONMENT_TESTS 39 #endif 40 } 41 42 ~TempEnvVar() { 43 #if HAVE_SETENV 44 // Assume setenv and unsetenv come together. 45 unsetenv(name); 46 #else 47 (void)name; // Suppress -Wunused-private-field. 48 #endif 49 } 50 51 private: 52 const char *const name; 53 }; 54 55 template <typename T, typename Base = cl::opt<T>> 56 class StackOption : public Base { 57 public: 58 template <class... Ts> 59 explicit StackOption(Ts &&... Ms) : Base(std::forward<Ts>(Ms)...) {} 60 61 ~StackOption() override { this->removeArgument(); } 62 63 template <class DT> StackOption<T> &operator=(const DT &V) { 64 this->setValue(V); 65 return *this; 66 } 67 }; 68 69 class StackSubCommand : public cl::SubCommand { 70 public: 71 StackSubCommand(StringRef Name, 72 StringRef Description = StringRef()) 73 : SubCommand(Name, Description) {} 74 75 StackSubCommand() : SubCommand() {} 76 77 ~StackSubCommand() { unregisterSubCommand(); } 78 }; 79 80 81 cl::OptionCategory TestCategory("Test Options", "Description"); 82 TEST(CommandLineTest, ModifyExisitingOption) { 83 StackOption<int> TestOption("test-option", cl::desc("old description")); 84 85 static const char Description[] = "New description"; 86 static const char ArgString[] = "new-test-option"; 87 static const char ValueString[] = "Integer"; 88 89 StringMap<cl::Option *> &Map = 90 cl::getRegisteredOptions(*cl::TopLevelSubCommand); 91 92 ASSERT_TRUE(Map.count("test-option") == 1) << 93 "Could not find option in map."; 94 95 cl::Option *Retrieved = Map["test-option"]; 96 ASSERT_EQ(&TestOption, Retrieved) << "Retrieved wrong option."; 97 98 ASSERT_NE(Retrieved->getCategories().end(), 99 find_if(Retrieved->getCategories(), 100 [&](const llvm::cl::OptionCategory *Cat) { 101 return Cat == &cl::GeneralCategory; 102 })) 103 << "Incorrect default option category."; 104 105 Retrieved->addCategory(TestCategory); 106 ASSERT_NE(Retrieved->getCategories().end(), 107 find_if(Retrieved->getCategories(), 108 [&](const llvm::cl::OptionCategory *Cat) { 109 return Cat == &TestCategory; 110 })) 111 << "Failed to modify option's option category."; 112 113 Retrieved->setDescription(Description); 114 ASSERT_STREQ(Retrieved->HelpStr.data(), Description) 115 << "Changing option description failed."; 116 117 Retrieved->setArgStr(ArgString); 118 ASSERT_STREQ(ArgString, Retrieved->ArgStr.data()) 119 << "Failed to modify option's Argument string."; 120 121 Retrieved->setValueStr(ValueString); 122 ASSERT_STREQ(Retrieved->ValueStr.data(), ValueString) 123 << "Failed to modify option's Value string."; 124 125 Retrieved->setHiddenFlag(cl::Hidden); 126 ASSERT_EQ(cl::Hidden, TestOption.getOptionHiddenFlag()) << 127 "Failed to modify option's hidden flag."; 128 } 129 #ifndef SKIP_ENVIRONMENT_TESTS 130 131 const char test_env_var[] = "LLVM_TEST_COMMAND_LINE_FLAGS"; 132 133 cl::opt<std::string> EnvironmentTestOption("env-test-opt"); 134 TEST(CommandLineTest, ParseEnvironment) { 135 TempEnvVar TEV(test_env_var, "-env-test-opt=hello"); 136 EXPECT_EQ("", EnvironmentTestOption); 137 cl::ParseEnvironmentOptions("CommandLineTest", test_env_var); 138 EXPECT_EQ("hello", EnvironmentTestOption); 139 } 140 141 // This test used to make valgrind complain 142 // ("Conditional jump or move depends on uninitialised value(s)") 143 // 144 // Warning: Do not run any tests after this one that try to gain access to 145 // registered command line options because this will likely result in a 146 // SEGFAULT. This can occur because the cl::opt in the test below is declared 147 // on the stack which will be destroyed after the test completes but the 148 // command line system will still hold a pointer to a deallocated cl::Option. 149 TEST(CommandLineTest, ParseEnvironmentToLocalVar) { 150 // Put cl::opt on stack to check for proper initialization of fields. 151 StackOption<std::string> EnvironmentTestOptionLocal("env-test-opt-local"); 152 TempEnvVar TEV(test_env_var, "-env-test-opt-local=hello-local"); 153 EXPECT_EQ("", EnvironmentTestOptionLocal); 154 cl::ParseEnvironmentOptions("CommandLineTest", test_env_var); 155 EXPECT_EQ("hello-local", EnvironmentTestOptionLocal); 156 } 157 158 #endif // SKIP_ENVIRONMENT_TESTS 159 160 TEST(CommandLineTest, UseOptionCategory) { 161 StackOption<int> TestOption2("test-option", cl::cat(TestCategory)); 162 163 ASSERT_NE(TestOption2.getCategories().end(), 164 find_if(TestOption2.getCategories(), 165 [&](const llvm::cl::OptionCategory *Cat) { 166 return Cat == &TestCategory; 167 })) 168 << "Failed to assign Option Category."; 169 } 170 171 TEST(CommandLineTest, UseMultipleCategories) { 172 StackOption<int> TestOption2("test-option2", cl::cat(TestCategory), 173 cl::cat(cl::GeneralCategory), 174 cl::cat(cl::GeneralCategory)); 175 auto TestOption2Categories = TestOption2.getCategories(); 176 177 // Make sure cl::GeneralCategory wasn't added twice. 178 ASSERT_EQ(TestOption2Categories.size(), 2U); 179 180 ASSERT_NE(TestOption2Categories.end(), 181 find_if(TestOption2Categories, 182 [&](const llvm::cl::OptionCategory *Cat) { 183 return Cat == &TestCategory; 184 })) 185 << "Failed to assign Option Category."; 186 ASSERT_NE(TestOption2Categories.end(), 187 find_if(TestOption2Categories, 188 [&](const llvm::cl::OptionCategory *Cat) { 189 return Cat == &cl::GeneralCategory; 190 })) 191 << "Failed to assign General Category."; 192 193 cl::OptionCategory AnotherCategory("Additional test Options", "Description"); 194 StackOption<int> TestOption("test-option", cl::cat(TestCategory), 195 cl::cat(AnotherCategory)); 196 auto TestOptionCategories = TestOption.getCategories(); 197 ASSERT_EQ(TestOptionCategories.end(), 198 find_if(TestOptionCategories, 199 [&](const llvm::cl::OptionCategory *Cat) { 200 return Cat == &cl::GeneralCategory; 201 })) 202 << "Failed to remove General Category."; 203 ASSERT_NE(TestOptionCategories.end(), 204 find_if(TestOptionCategories, 205 [&](const llvm::cl::OptionCategory *Cat) { 206 return Cat == &TestCategory; 207 })) 208 << "Failed to assign Option Category."; 209 ASSERT_NE(TestOptionCategories.end(), 210 find_if(TestOptionCategories, 211 [&](const llvm::cl::OptionCategory *Cat) { 212 return Cat == &AnotherCategory; 213 })) 214 << "Failed to assign Another Category."; 215 } 216 217 typedef void ParserFunction(StringRef Source, StringSaver &Saver, 218 SmallVectorImpl<const char *> &NewArgv, 219 bool MarkEOLs); 220 221 void testCommandLineTokenizer(ParserFunction *parse, StringRef Input, 222 const char *const Output[], size_t OutputSize) { 223 SmallVector<const char *, 0> Actual; 224 BumpPtrAllocator A; 225 StringSaver Saver(A); 226 parse(Input, Saver, Actual, /*MarkEOLs=*/false); 227 EXPECT_EQ(OutputSize, Actual.size()); 228 for (unsigned I = 0, E = Actual.size(); I != E; ++I) { 229 if (I < OutputSize) { 230 EXPECT_STREQ(Output[I], Actual[I]); 231 } 232 } 233 } 234 235 TEST(CommandLineTest, TokenizeGNUCommandLine) { 236 const char Input[] = 237 "foo\\ bar \"foo bar\" \'foo bar\' 'foo\\\\bar' -DFOO=bar\\(\\) " 238 "foo\"bar\"baz C:\\\\src\\\\foo.cpp \"C:\\src\\foo.cpp\""; 239 const char *const Output[] = { 240 "foo bar", "foo bar", "foo bar", "foo\\bar", 241 "-DFOO=bar()", "foobarbaz", "C:\\src\\foo.cpp", "C:srcfoo.cpp"}; 242 testCommandLineTokenizer(cl::TokenizeGNUCommandLine, Input, Output, 243 array_lengthof(Output)); 244 } 245 246 TEST(CommandLineTest, TokenizeWindowsCommandLine1) { 247 const char Input[] = "a\\b c\\\\d e\\\\\"f g\" h\\\"i j\\\\\\\"k \"lmn\" o pqr " 248 "\"st \\\"u\" \\v"; 249 const char *const Output[] = { "a\\b", "c\\\\d", "e\\f g", "h\"i", "j\\\"k", 250 "lmn", "o", "pqr", "st \"u", "\\v" }; 251 testCommandLineTokenizer(cl::TokenizeWindowsCommandLine, Input, Output, 252 array_lengthof(Output)); 253 } 254 255 TEST(CommandLineTest, TokenizeWindowsCommandLine2) { 256 const char Input[] = "clang -c -DFOO=\"\"\"ABC\"\"\" x.cpp"; 257 const char *const Output[] = { "clang", "-c", "-DFOO=\"ABC\"", "x.cpp"}; 258 testCommandLineTokenizer(cl::TokenizeWindowsCommandLine, Input, Output, 259 array_lengthof(Output)); 260 } 261 262 TEST(CommandLineTest, TokenizeConfigFile1) { 263 const char *Input = "\\"; 264 const char *const Output[] = { "\\" }; 265 testCommandLineTokenizer(cl::tokenizeConfigFile, Input, Output, 266 array_lengthof(Output)); 267 } 268 269 TEST(CommandLineTest, TokenizeConfigFile2) { 270 const char *Input = "\\abc"; 271 const char *const Output[] = { "abc" }; 272 testCommandLineTokenizer(cl::tokenizeConfigFile, Input, Output, 273 array_lengthof(Output)); 274 } 275 276 TEST(CommandLineTest, TokenizeConfigFile3) { 277 const char *Input = "abc\\"; 278 const char *const Output[] = { "abc\\" }; 279 testCommandLineTokenizer(cl::tokenizeConfigFile, Input, Output, 280 array_lengthof(Output)); 281 } 282 283 TEST(CommandLineTest, TokenizeConfigFile4) { 284 const char *Input = "abc\\\n123"; 285 const char *const Output[] = { "abc123" }; 286 testCommandLineTokenizer(cl::tokenizeConfigFile, Input, Output, 287 array_lengthof(Output)); 288 } 289 290 TEST(CommandLineTest, TokenizeConfigFile5) { 291 const char *Input = "abc\\\r\n123"; 292 const char *const Output[] = { "abc123" }; 293 testCommandLineTokenizer(cl::tokenizeConfigFile, Input, Output, 294 array_lengthof(Output)); 295 } 296 297 TEST(CommandLineTest, TokenizeConfigFile6) { 298 const char *Input = "abc\\\n"; 299 const char *const Output[] = { "abc" }; 300 testCommandLineTokenizer(cl::tokenizeConfigFile, Input, Output, 301 array_lengthof(Output)); 302 } 303 304 TEST(CommandLineTest, TokenizeConfigFile7) { 305 const char *Input = "abc\\\r\n"; 306 const char *const Output[] = { "abc" }; 307 testCommandLineTokenizer(cl::tokenizeConfigFile, Input, Output, 308 array_lengthof(Output)); 309 } 310 311 TEST(CommandLineTest, TokenizeConfigFile8) { 312 SmallVector<const char *, 0> Actual; 313 BumpPtrAllocator A; 314 StringSaver Saver(A); 315 cl::tokenizeConfigFile("\\\n", Saver, Actual, /*MarkEOLs=*/false); 316 EXPECT_TRUE(Actual.empty()); 317 } 318 319 TEST(CommandLineTest, TokenizeConfigFile9) { 320 SmallVector<const char *, 0> Actual; 321 BumpPtrAllocator A; 322 StringSaver Saver(A); 323 cl::tokenizeConfigFile("\\\r\n", Saver, Actual, /*MarkEOLs=*/false); 324 EXPECT_TRUE(Actual.empty()); 325 } 326 327 TEST(CommandLineTest, TokenizeConfigFile10) { 328 const char *Input = "\\\nabc"; 329 const char *const Output[] = { "abc" }; 330 testCommandLineTokenizer(cl::tokenizeConfigFile, Input, Output, 331 array_lengthof(Output)); 332 } 333 334 TEST(CommandLineTest, TokenizeConfigFile11) { 335 const char *Input = "\\\r\nabc"; 336 const char *const Output[] = { "abc" }; 337 testCommandLineTokenizer(cl::tokenizeConfigFile, Input, Output, 338 array_lengthof(Output)); 339 } 340 341 TEST(CommandLineTest, AliasesWithArguments) { 342 static const size_t ARGC = 3; 343 const char *const Inputs[][ARGC] = { 344 { "-tool", "-actual=x", "-extra" }, 345 { "-tool", "-actual", "x" }, 346 { "-tool", "-alias=x", "-extra" }, 347 { "-tool", "-alias", "x" } 348 }; 349 350 for (size_t i = 0, e = array_lengthof(Inputs); i < e; ++i) { 351 StackOption<std::string> Actual("actual"); 352 StackOption<bool> Extra("extra"); 353 StackOption<std::string> Input(cl::Positional); 354 355 cl::alias Alias("alias", llvm::cl::aliasopt(Actual)); 356 357 cl::ParseCommandLineOptions(ARGC, Inputs[i]); 358 EXPECT_EQ("x", Actual); 359 EXPECT_EQ(0, Input.getNumOccurrences()); 360 361 Alias.removeArgument(); 362 } 363 } 364 365 void testAliasRequired(int argc, const char *const *argv) { 366 StackOption<std::string> Option("option", cl::Required); 367 cl::alias Alias("o", llvm::cl::aliasopt(Option)); 368 369 cl::ParseCommandLineOptions(argc, argv); 370 EXPECT_EQ("x", Option); 371 EXPECT_EQ(1, Option.getNumOccurrences()); 372 373 Alias.removeArgument(); 374 } 375 376 TEST(CommandLineTest, AliasRequired) { 377 const char *opts1[] = { "-tool", "-option=x" }; 378 const char *opts2[] = { "-tool", "-o", "x" }; 379 testAliasRequired(array_lengthof(opts1), opts1); 380 testAliasRequired(array_lengthof(opts2), opts2); 381 } 382 383 TEST(CommandLineTest, AliasWithSubCommand) { 384 StackSubCommand SC1("sc1", "Subcommand 1"); 385 StackOption<std::string> Option1("option", cl::value_desc("output file"), 386 cl::init("-"), cl::desc("Option"), 387 cl::sub(SC1)); 388 StackOption<std::string, cl::alias> Alias1("o", llvm::cl::aliasopt(Option1), 389 cl::desc("Alias for --option"), 390 cl::sub(SC1)); 391 } 392 393 TEST(CommandLineTest, AliasWithMultipleSubCommandsWithSameOption) { 394 StackSubCommand SC1("sc1", "Subcommand 1"); 395 StackOption<std::string> Option1("option", cl::value_desc("output file"), 396 cl::init("-"), cl::desc("Option"), 397 cl::sub(SC1)); 398 StackSubCommand SC2("sc2", "Subcommand 2"); 399 StackOption<std::string> Option2("option", cl::value_desc("output file"), 400 cl::init("-"), cl::desc("Option"), 401 cl::sub(SC2)); 402 403 StackOption<std::string, cl::alias> Alias1("o", llvm::cl::aliasopt(Option1), 404 cl::desc("Alias for --option")); 405 } 406 407 TEST(CommandLineTest, HideUnrelatedOptions) { 408 StackOption<int> TestOption1("hide-option-1"); 409 StackOption<int> TestOption2("hide-option-2", cl::cat(TestCategory)); 410 411 cl::HideUnrelatedOptions(TestCategory); 412 413 ASSERT_EQ(cl::ReallyHidden, TestOption1.getOptionHiddenFlag()) 414 << "Failed to hide extra option."; 415 ASSERT_EQ(cl::NotHidden, TestOption2.getOptionHiddenFlag()) 416 << "Hid extra option that should be visable."; 417 418 StringMap<cl::Option *> &Map = 419 cl::getRegisteredOptions(*cl::TopLevelSubCommand); 420 ASSERT_EQ(cl::NotHidden, Map["help"]->getOptionHiddenFlag()) 421 << "Hid default option that should be visable."; 422 } 423 424 cl::OptionCategory TestCategory2("Test Options set 2", "Description"); 425 426 TEST(CommandLineTest, HideUnrelatedOptionsMulti) { 427 StackOption<int> TestOption1("multi-hide-option-1"); 428 StackOption<int> TestOption2("multi-hide-option-2", cl::cat(TestCategory)); 429 StackOption<int> TestOption3("multi-hide-option-3", cl::cat(TestCategory2)); 430 431 const cl::OptionCategory *VisibleCategories[] = {&TestCategory, 432 &TestCategory2}; 433 434 cl::HideUnrelatedOptions(makeArrayRef(VisibleCategories)); 435 436 ASSERT_EQ(cl::ReallyHidden, TestOption1.getOptionHiddenFlag()) 437 << "Failed to hide extra option."; 438 ASSERT_EQ(cl::NotHidden, TestOption2.getOptionHiddenFlag()) 439 << "Hid extra option that should be visable."; 440 ASSERT_EQ(cl::NotHidden, TestOption3.getOptionHiddenFlag()) 441 << "Hid extra option that should be visable."; 442 443 StringMap<cl::Option *> &Map = 444 cl::getRegisteredOptions(*cl::TopLevelSubCommand); 445 ASSERT_EQ(cl::NotHidden, Map["help"]->getOptionHiddenFlag()) 446 << "Hid default option that should be visable."; 447 } 448 449 TEST(CommandLineTest, SetValueInSubcategories) { 450 cl::ResetCommandLineParser(); 451 452 StackSubCommand SC1("sc1", "First subcommand"); 453 StackSubCommand SC2("sc2", "Second subcommand"); 454 455 StackOption<bool> TopLevelOpt("top-level", cl::init(false)); 456 StackOption<bool> SC1Opt("sc1", cl::sub(SC1), cl::init(false)); 457 StackOption<bool> SC2Opt("sc2", cl::sub(SC2), cl::init(false)); 458 459 EXPECT_FALSE(TopLevelOpt); 460 EXPECT_FALSE(SC1Opt); 461 EXPECT_FALSE(SC2Opt); 462 const char *args[] = {"prog", "-top-level"}; 463 EXPECT_TRUE( 464 cl::ParseCommandLineOptions(2, args, StringRef(), &llvm::nulls())); 465 EXPECT_TRUE(TopLevelOpt); 466 EXPECT_FALSE(SC1Opt); 467 EXPECT_FALSE(SC2Opt); 468 469 TopLevelOpt = false; 470 471 cl::ResetAllOptionOccurrences(); 472 EXPECT_FALSE(TopLevelOpt); 473 EXPECT_FALSE(SC1Opt); 474 EXPECT_FALSE(SC2Opt); 475 const char *args2[] = {"prog", "sc1", "-sc1"}; 476 EXPECT_TRUE( 477 cl::ParseCommandLineOptions(3, args2, StringRef(), &llvm::nulls())); 478 EXPECT_FALSE(TopLevelOpt); 479 EXPECT_TRUE(SC1Opt); 480 EXPECT_FALSE(SC2Opt); 481 482 SC1Opt = false; 483 484 cl::ResetAllOptionOccurrences(); 485 EXPECT_FALSE(TopLevelOpt); 486 EXPECT_FALSE(SC1Opt); 487 EXPECT_FALSE(SC2Opt); 488 const char *args3[] = {"prog", "sc2", "-sc2"}; 489 EXPECT_TRUE( 490 cl::ParseCommandLineOptions(3, args3, StringRef(), &llvm::nulls())); 491 EXPECT_FALSE(TopLevelOpt); 492 EXPECT_FALSE(SC1Opt); 493 EXPECT_TRUE(SC2Opt); 494 } 495 496 TEST(CommandLineTest, LookupFailsInWrongSubCommand) { 497 cl::ResetCommandLineParser(); 498 499 StackSubCommand SC1("sc1", "First subcommand"); 500 StackSubCommand SC2("sc2", "Second subcommand"); 501 502 StackOption<bool> SC1Opt("sc1", cl::sub(SC1), cl::init(false)); 503 StackOption<bool> SC2Opt("sc2", cl::sub(SC2), cl::init(false)); 504 505 std::string Errs; 506 raw_string_ostream OS(Errs); 507 508 const char *args[] = {"prog", "sc1", "-sc2"}; 509 EXPECT_FALSE(cl::ParseCommandLineOptions(3, args, StringRef(), &OS)); 510 OS.flush(); 511 EXPECT_FALSE(Errs.empty()); 512 } 513 514 TEST(CommandLineTest, AddToAllSubCommands) { 515 cl::ResetCommandLineParser(); 516 517 StackSubCommand SC1("sc1", "First subcommand"); 518 StackOption<bool> AllOpt("everywhere", cl::sub(*cl::AllSubCommands), 519 cl::init(false)); 520 StackSubCommand SC2("sc2", "Second subcommand"); 521 522 const char *args[] = {"prog", "-everywhere"}; 523 const char *args2[] = {"prog", "sc1", "-everywhere"}; 524 const char *args3[] = {"prog", "sc2", "-everywhere"}; 525 526 std::string Errs; 527 raw_string_ostream OS(Errs); 528 529 EXPECT_FALSE(AllOpt); 530 EXPECT_TRUE(cl::ParseCommandLineOptions(2, args, StringRef(), &OS)); 531 EXPECT_TRUE(AllOpt); 532 533 AllOpt = false; 534 535 cl::ResetAllOptionOccurrences(); 536 EXPECT_FALSE(AllOpt); 537 EXPECT_TRUE(cl::ParseCommandLineOptions(3, args2, StringRef(), &OS)); 538 EXPECT_TRUE(AllOpt); 539 540 AllOpt = false; 541 542 cl::ResetAllOptionOccurrences(); 543 EXPECT_FALSE(AllOpt); 544 EXPECT_TRUE(cl::ParseCommandLineOptions(3, args3, StringRef(), &OS)); 545 EXPECT_TRUE(AllOpt); 546 547 // Since all parsing succeeded, the error message should be empty. 548 OS.flush(); 549 EXPECT_TRUE(Errs.empty()); 550 } 551 552 TEST(CommandLineTest, ReparseCommandLineOptions) { 553 cl::ResetCommandLineParser(); 554 555 StackOption<bool> TopLevelOpt("top-level", cl::sub(*cl::TopLevelSubCommand), 556 cl::init(false)); 557 558 const char *args[] = {"prog", "-top-level"}; 559 560 EXPECT_FALSE(TopLevelOpt); 561 EXPECT_TRUE( 562 cl::ParseCommandLineOptions(2, args, StringRef(), &llvm::nulls())); 563 EXPECT_TRUE(TopLevelOpt); 564 565 TopLevelOpt = false; 566 567 cl::ResetAllOptionOccurrences(); 568 EXPECT_FALSE(TopLevelOpt); 569 EXPECT_TRUE( 570 cl::ParseCommandLineOptions(2, args, StringRef(), &llvm::nulls())); 571 EXPECT_TRUE(TopLevelOpt); 572 } 573 574 TEST(CommandLineTest, RemoveFromRegularSubCommand) { 575 cl::ResetCommandLineParser(); 576 577 StackSubCommand SC("sc", "Subcommand"); 578 StackOption<bool> RemoveOption("remove-option", cl::sub(SC), cl::init(false)); 579 StackOption<bool> KeepOption("keep-option", cl::sub(SC), cl::init(false)); 580 581 const char *args[] = {"prog", "sc", "-remove-option"}; 582 583 std::string Errs; 584 raw_string_ostream OS(Errs); 585 586 EXPECT_FALSE(RemoveOption); 587 EXPECT_TRUE(cl::ParseCommandLineOptions(3, args, StringRef(), &OS)); 588 EXPECT_TRUE(RemoveOption); 589 OS.flush(); 590 EXPECT_TRUE(Errs.empty()); 591 592 RemoveOption.removeArgument(); 593 594 cl::ResetAllOptionOccurrences(); 595 EXPECT_FALSE(cl::ParseCommandLineOptions(3, args, StringRef(), &OS)); 596 OS.flush(); 597 EXPECT_FALSE(Errs.empty()); 598 } 599 600 TEST(CommandLineTest, RemoveFromTopLevelSubCommand) { 601 cl::ResetCommandLineParser(); 602 603 StackOption<bool> TopLevelRemove( 604 "top-level-remove", cl::sub(*cl::TopLevelSubCommand), cl::init(false)); 605 StackOption<bool> TopLevelKeep( 606 "top-level-keep", cl::sub(*cl::TopLevelSubCommand), cl::init(false)); 607 608 const char *args[] = {"prog", "-top-level-remove"}; 609 610 EXPECT_FALSE(TopLevelRemove); 611 EXPECT_TRUE( 612 cl::ParseCommandLineOptions(2, args, StringRef(), &llvm::nulls())); 613 EXPECT_TRUE(TopLevelRemove); 614 615 TopLevelRemove.removeArgument(); 616 617 cl::ResetAllOptionOccurrences(); 618 EXPECT_FALSE( 619 cl::ParseCommandLineOptions(2, args, StringRef(), &llvm::nulls())); 620 } 621 622 TEST(CommandLineTest, RemoveFromAllSubCommands) { 623 cl::ResetCommandLineParser(); 624 625 StackSubCommand SC1("sc1", "First Subcommand"); 626 StackSubCommand SC2("sc2", "Second Subcommand"); 627 StackOption<bool> RemoveOption("remove-option", cl::sub(*cl::AllSubCommands), 628 cl::init(false)); 629 StackOption<bool> KeepOption("keep-option", cl::sub(*cl::AllSubCommands), 630 cl::init(false)); 631 632 const char *args0[] = {"prog", "-remove-option"}; 633 const char *args1[] = {"prog", "sc1", "-remove-option"}; 634 const char *args2[] = {"prog", "sc2", "-remove-option"}; 635 636 // It should work for all subcommands including the top-level. 637 EXPECT_FALSE(RemoveOption); 638 EXPECT_TRUE( 639 cl::ParseCommandLineOptions(2, args0, StringRef(), &llvm::nulls())); 640 EXPECT_TRUE(RemoveOption); 641 642 RemoveOption = false; 643 644 cl::ResetAllOptionOccurrences(); 645 EXPECT_FALSE(RemoveOption); 646 EXPECT_TRUE( 647 cl::ParseCommandLineOptions(3, args1, StringRef(), &llvm::nulls())); 648 EXPECT_TRUE(RemoveOption); 649 650 RemoveOption = false; 651 652 cl::ResetAllOptionOccurrences(); 653 EXPECT_FALSE(RemoveOption); 654 EXPECT_TRUE( 655 cl::ParseCommandLineOptions(3, args2, StringRef(), &llvm::nulls())); 656 EXPECT_TRUE(RemoveOption); 657 658 RemoveOption.removeArgument(); 659 660 // It should not work for any subcommands including the top-level. 661 cl::ResetAllOptionOccurrences(); 662 EXPECT_FALSE( 663 cl::ParseCommandLineOptions(2, args0, StringRef(), &llvm::nulls())); 664 cl::ResetAllOptionOccurrences(); 665 EXPECT_FALSE( 666 cl::ParseCommandLineOptions(3, args1, StringRef(), &llvm::nulls())); 667 cl::ResetAllOptionOccurrences(); 668 EXPECT_FALSE( 669 cl::ParseCommandLineOptions(3, args2, StringRef(), &llvm::nulls())); 670 } 671 672 TEST(CommandLineTest, GetRegisteredSubcommands) { 673 cl::ResetCommandLineParser(); 674 675 StackSubCommand SC1("sc1", "First Subcommand"); 676 StackOption<bool> Opt1("opt1", cl::sub(SC1), cl::init(false)); 677 StackSubCommand SC2("sc2", "Second subcommand"); 678 StackOption<bool> Opt2("opt2", cl::sub(SC2), cl::init(false)); 679 680 const char *args0[] = {"prog", "sc1"}; 681 const char *args1[] = {"prog", "sc2"}; 682 683 EXPECT_TRUE( 684 cl::ParseCommandLineOptions(2, args0, StringRef(), &llvm::nulls())); 685 EXPECT_FALSE(Opt1); 686 EXPECT_FALSE(Opt2); 687 for (auto *S : cl::getRegisteredSubcommands()) { 688 if (*S) { 689 EXPECT_EQ("sc1", S->getName()); 690 } 691 } 692 693 cl::ResetAllOptionOccurrences(); 694 EXPECT_TRUE( 695 cl::ParseCommandLineOptions(2, args1, StringRef(), &llvm::nulls())); 696 EXPECT_FALSE(Opt1); 697 EXPECT_FALSE(Opt2); 698 for (auto *S : cl::getRegisteredSubcommands()) { 699 if (*S) { 700 EXPECT_EQ("sc2", S->getName()); 701 } 702 } 703 } 704 705 TEST(CommandLineTest, DefaultOptions) { 706 cl::ResetCommandLineParser(); 707 708 StackOption<std::string> Bar("bar", cl::sub(*cl::AllSubCommands), 709 cl::DefaultOption); 710 StackOption<std::string, cl::alias> Bar_Alias( 711 "b", cl::desc("Alias for -bar"), cl::aliasopt(Bar), cl::DefaultOption); 712 713 StackOption<bool> Foo("foo", cl::init(false), cl::sub(*cl::AllSubCommands), 714 cl::DefaultOption); 715 StackOption<bool, cl::alias> Foo_Alias("f", cl::desc("Alias for -foo"), 716 cl::aliasopt(Foo), cl::DefaultOption); 717 718 StackSubCommand SC1("sc1", "First Subcommand"); 719 // Override "-b" and change type in sc1 SubCommand. 720 StackOption<bool> SC1_B("b", cl::sub(SC1), cl::init(false)); 721 StackSubCommand SC2("sc2", "Second subcommand"); 722 // Override "-foo" and change type in sc2 SubCommand. Note that this does not 723 // affect "-f" alias, which continues to work correctly. 724 StackOption<std::string> SC2_Foo("foo", cl::sub(SC2)); 725 726 const char *args0[] = {"prog", "-b", "args0 bar string", "-f"}; 727 EXPECT_TRUE(cl::ParseCommandLineOptions(sizeof(args0) / sizeof(char *), args0, 728 StringRef(), &llvm::nulls())); 729 EXPECT_TRUE(Bar == "args0 bar string"); 730 EXPECT_TRUE(Foo); 731 EXPECT_FALSE(SC1_B); 732 EXPECT_TRUE(SC2_Foo.empty()); 733 734 cl::ResetAllOptionOccurrences(); 735 736 const char *args1[] = {"prog", "sc1", "-b", "-bar", "args1 bar string", "-f"}; 737 EXPECT_TRUE(cl::ParseCommandLineOptions(sizeof(args1) / sizeof(char *), args1, 738 StringRef(), &llvm::nulls())); 739 EXPECT_TRUE(Bar == "args1 bar string"); 740 EXPECT_TRUE(Foo); 741 EXPECT_TRUE(SC1_B); 742 EXPECT_TRUE(SC2_Foo.empty()); 743 for (auto *S : cl::getRegisteredSubcommands()) { 744 if (*S) { 745 EXPECT_EQ("sc1", S->getName()); 746 } 747 } 748 749 cl::ResetAllOptionOccurrences(); 750 751 const char *args2[] = {"prog", "sc2", "-b", "args2 bar string", 752 "-f", "-foo", "foo string"}; 753 EXPECT_TRUE(cl::ParseCommandLineOptions(sizeof(args2) / sizeof(char *), args2, 754 StringRef(), &llvm::nulls())); 755 EXPECT_TRUE(Bar == "args2 bar string"); 756 EXPECT_TRUE(Foo); 757 EXPECT_FALSE(SC1_B); 758 EXPECT_TRUE(SC2_Foo == "foo string"); 759 for (auto *S : cl::getRegisteredSubcommands()) { 760 if (*S) { 761 EXPECT_EQ("sc2", S->getName()); 762 } 763 } 764 cl::ResetCommandLineParser(); 765 } 766 767 TEST(CommandLineTest, ArgumentLimit) { 768 std::string args(32 * 4096, 'a'); 769 EXPECT_FALSE(llvm::sys::commandLineFitsWithinSystemLimits("cl", args.data())); 770 } 771 772 TEST(CommandLineTest, ResponseFileWindows) { 773 if (!Triple(sys::getProcessTriple()).isOSWindows()) 774 return; 775 776 StackOption<std::string, cl::list<std::string>> InputFilenames( 777 cl::Positional, cl::desc("<input files>"), cl::ZeroOrMore); 778 StackOption<bool> TopLevelOpt("top-level", cl::init(false)); 779 780 // Create response file. 781 int FileDescriptor; 782 SmallString<64> TempPath; 783 std::error_code EC = 784 llvm::sys::fs::createTemporaryFile("resp-", ".txt", FileDescriptor, TempPath); 785 EXPECT_TRUE(!EC); 786 787 std::ofstream RspFile(TempPath.c_str()); 788 EXPECT_TRUE(RspFile.is_open()); 789 RspFile << "-top-level\npath\\dir\\file1\npath/dir/file2"; 790 RspFile.close(); 791 792 llvm::SmallString<128> RspOpt; 793 RspOpt.append(1, '@'); 794 RspOpt.append(TempPath.c_str()); 795 const char *args[] = {"prog", RspOpt.c_str()}; 796 EXPECT_FALSE(TopLevelOpt); 797 EXPECT_TRUE( 798 cl::ParseCommandLineOptions(2, args, StringRef(), &llvm::nulls())); 799 EXPECT_TRUE(TopLevelOpt); 800 EXPECT_TRUE(InputFilenames[0] == "path\\dir\\file1"); 801 EXPECT_TRUE(InputFilenames[1] == "path/dir/file2"); 802 803 llvm::sys::fs::remove(TempPath.c_str()); 804 } 805 806 TEST(CommandLineTest, ResponseFiles) { 807 llvm::SmallString<128> TestDir; 808 std::error_code EC = 809 llvm::sys::fs::createUniqueDirectory("unittest", TestDir); 810 EXPECT_TRUE(!EC); 811 812 // Create included response file of first level. 813 llvm::SmallString<128> IncludedFileName; 814 llvm::sys::path::append(IncludedFileName, TestDir, "resp1"); 815 std::ofstream IncludedFile(IncludedFileName.c_str()); 816 EXPECT_TRUE(IncludedFile.is_open()); 817 IncludedFile << "-option_1 -option_2\n" 818 "@incdir/resp2\n" 819 "-option_3=abcd\n" 820 "@incdir/resp3\n" 821 "-option_4=efjk\n"; 822 IncludedFile.close(); 823 824 // Directory for included file. 825 llvm::SmallString<128> IncDir; 826 llvm::sys::path::append(IncDir, TestDir, "incdir"); 827 EC = llvm::sys::fs::create_directory(IncDir); 828 EXPECT_TRUE(!EC); 829 830 // Create included response file of second level. 831 llvm::SmallString<128> IncludedFileName2; 832 llvm::sys::path::append(IncludedFileName2, IncDir, "resp2"); 833 std::ofstream IncludedFile2(IncludedFileName2.c_str()); 834 EXPECT_TRUE(IncludedFile2.is_open()); 835 IncludedFile2 << "-option_21 -option_22\n"; 836 IncludedFile2 << "-option_23=abcd\n"; 837 IncludedFile2.close(); 838 839 // Create second included response file of second level. 840 llvm::SmallString<128> IncludedFileName3; 841 llvm::sys::path::append(IncludedFileName3, IncDir, "resp3"); 842 std::ofstream IncludedFile3(IncludedFileName3.c_str()); 843 EXPECT_TRUE(IncludedFile3.is_open()); 844 IncludedFile3 << "-option_31 -option_32\n"; 845 IncludedFile3 << "-option_33=abcd\n"; 846 IncludedFile3.close(); 847 848 // Prepare 'file' with reference to response file. 849 SmallString<128> IncRef; 850 IncRef.append(1, '@'); 851 IncRef.append(IncludedFileName.c_str()); 852 llvm::SmallVector<const char *, 4> Argv = 853 { "test/test", "-flag_1", IncRef.c_str(), "-flag_2" }; 854 855 // Expand response files. 856 llvm::BumpPtrAllocator A; 857 llvm::StringSaver Saver(A); 858 bool Res = llvm::cl::ExpandResponseFiles( 859 Saver, llvm::cl::TokenizeGNUCommandLine, Argv, false, true); 860 EXPECT_TRUE(Res); 861 EXPECT_EQ(Argv.size(), 13U); 862 EXPECT_STREQ(Argv[0], "test/test"); 863 EXPECT_STREQ(Argv[1], "-flag_1"); 864 EXPECT_STREQ(Argv[2], "-option_1"); 865 EXPECT_STREQ(Argv[3], "-option_2"); 866 EXPECT_STREQ(Argv[4], "-option_21"); 867 EXPECT_STREQ(Argv[5], "-option_22"); 868 EXPECT_STREQ(Argv[6], "-option_23=abcd"); 869 EXPECT_STREQ(Argv[7], "-option_3=abcd"); 870 EXPECT_STREQ(Argv[8], "-option_31"); 871 EXPECT_STREQ(Argv[9], "-option_32"); 872 EXPECT_STREQ(Argv[10], "-option_33=abcd"); 873 EXPECT_STREQ(Argv[11], "-option_4=efjk"); 874 EXPECT_STREQ(Argv[12], "-flag_2"); 875 876 llvm::sys::fs::remove(IncludedFileName3); 877 llvm::sys::fs::remove(IncludedFileName2); 878 llvm::sys::fs::remove(IncDir); 879 llvm::sys::fs::remove(IncludedFileName); 880 llvm::sys::fs::remove(TestDir); 881 } 882 883 TEST(CommandLineTest, RecursiveResponseFiles) { 884 SmallString<128> TestDir; 885 std::error_code EC = sys::fs::createUniqueDirectory("unittest", TestDir); 886 EXPECT_TRUE(!EC); 887 888 SmallString<128> SelfFilePath; 889 sys::path::append(SelfFilePath, TestDir, "self.rsp"); 890 std::string SelfFileRef = std::string("@") + SelfFilePath.c_str(); 891 892 SmallString<128> NestedFilePath; 893 sys::path::append(NestedFilePath, TestDir, "nested.rsp"); 894 std::string NestedFileRef = std::string("@") + NestedFilePath.c_str(); 895 896 SmallString<128> FlagFilePath; 897 sys::path::append(FlagFilePath, TestDir, "flag.rsp"); 898 std::string FlagFileRef = std::string("@") + FlagFilePath.c_str(); 899 900 std::ofstream SelfFile(SelfFilePath.str()); 901 EXPECT_TRUE(SelfFile.is_open()); 902 SelfFile << "-option_1\n"; 903 SelfFile << FlagFileRef << "\n"; 904 SelfFile << NestedFileRef << "\n"; 905 SelfFile << SelfFileRef << "\n"; 906 SelfFile.close(); 907 908 std::ofstream NestedFile(NestedFilePath.str()); 909 EXPECT_TRUE(NestedFile.is_open()); 910 NestedFile << "-option_2\n"; 911 NestedFile << FlagFileRef << "\n"; 912 NestedFile << SelfFileRef << "\n"; 913 NestedFile << NestedFileRef << "\n"; 914 NestedFile.close(); 915 916 std::ofstream FlagFile(FlagFilePath.str()); 917 EXPECT_TRUE(FlagFile.is_open()); 918 FlagFile << "-option_x\n"; 919 FlagFile.close(); 920 921 // Ensure: 922 // Recursive expansion terminates 923 // Recursive files never expand 924 // Non-recursive repeats are allowed 925 SmallVector<const char *, 4> Argv = {"test/test", SelfFileRef.c_str(), 926 "-option_3"}; 927 BumpPtrAllocator A; 928 StringSaver Saver(A); 929 #ifdef _WIN32 930 cl::TokenizerCallback Tokenizer = cl::TokenizeWindowsCommandLine; 931 #else 932 cl::TokenizerCallback Tokenizer = cl::TokenizeGNUCommandLine; 933 #endif 934 bool Res = cl::ExpandResponseFiles(Saver, Tokenizer, Argv, false, false); 935 EXPECT_FALSE(Res); 936 937 EXPECT_EQ(Argv.size(), 9U); 938 EXPECT_STREQ(Argv[0], "test/test"); 939 EXPECT_STREQ(Argv[1], "-option_1"); 940 EXPECT_STREQ(Argv[2], "-option_x"); 941 EXPECT_STREQ(Argv[3], "-option_2"); 942 EXPECT_STREQ(Argv[4], "-option_x"); 943 EXPECT_STREQ(Argv[5], SelfFileRef.c_str()); 944 EXPECT_STREQ(Argv[6], NestedFileRef.c_str()); 945 EXPECT_STREQ(Argv[7], SelfFileRef.c_str()); 946 EXPECT_STREQ(Argv[8], "-option_3"); 947 } 948 949 TEST(CommandLineTest, ResponseFilesAtArguments) { 950 SmallString<128> TestDir; 951 std::error_code EC = sys::fs::createUniqueDirectory("unittest", TestDir); 952 EXPECT_TRUE(!EC); 953 954 SmallString<128> ResponseFilePath; 955 sys::path::append(ResponseFilePath, TestDir, "test.rsp"); 956 957 std::ofstream ResponseFile(ResponseFilePath.c_str()); 958 EXPECT_TRUE(ResponseFile.is_open()); 959 ResponseFile << "-foo" << "\n"; 960 ResponseFile << "-bar" << "\n"; 961 ResponseFile.close(); 962 963 // Ensure we expand rsp files after lots of non-rsp arguments starting with @. 964 constexpr size_t NON_RSP_AT_ARGS = 64; 965 SmallVector<const char *, 4> Argv = {"test/test"}; 966 Argv.append(NON_RSP_AT_ARGS, "@non_rsp_at_arg"); 967 std::string ResponseFileRef = std::string("@") + ResponseFilePath.c_str(); 968 Argv.push_back(ResponseFileRef.c_str()); 969 970 BumpPtrAllocator A; 971 StringSaver Saver(A); 972 bool Res = cl::ExpandResponseFiles(Saver, cl::TokenizeGNUCommandLine, Argv, 973 false, false); 974 EXPECT_FALSE(Res); 975 976 // ASSERT instead of EXPECT to prevent potential out-of-bounds access. 977 ASSERT_EQ(Argv.size(), 1 + NON_RSP_AT_ARGS + 2); 978 size_t i = 0; 979 EXPECT_STREQ(Argv[i++], "test/test"); 980 for (; i < 1 + NON_RSP_AT_ARGS; ++i) 981 EXPECT_STREQ(Argv[i], "@non_rsp_at_arg"); 982 EXPECT_STREQ(Argv[i++], "-foo"); 983 EXPECT_STREQ(Argv[i++], "-bar"); 984 } 985 986 TEST(CommandLineTest, SetDefautValue) { 987 cl::ResetCommandLineParser(); 988 989 StackOption<std::string> Opt1("opt1", cl::init("true")); 990 StackOption<bool> Opt2("opt2", cl::init(true)); 991 cl::alias Alias("alias", llvm::cl::aliasopt(Opt2)); 992 StackOption<int> Opt3("opt3", cl::init(3)); 993 994 const char *args[] = {"prog", "-opt1=false", "-opt2", "-opt3"}; 995 996 EXPECT_TRUE( 997 cl::ParseCommandLineOptions(2, args, StringRef(), &llvm::nulls())); 998 999 EXPECT_TRUE(Opt1 == "false"); 1000 EXPECT_TRUE(Opt2); 1001 EXPECT_TRUE(Opt3 == 3); 1002 1003 Opt2 = false; 1004 Opt3 = 1; 1005 1006 cl::ResetAllOptionOccurrences(); 1007 1008 for (auto &OM : cl::getRegisteredOptions(*cl::TopLevelSubCommand)) { 1009 cl::Option *O = OM.second; 1010 if (O->ArgStr == "opt2") { 1011 continue; 1012 } 1013 O->setDefault(); 1014 } 1015 1016 EXPECT_TRUE(Opt1 == "true"); 1017 EXPECT_TRUE(Opt2); 1018 EXPECT_TRUE(Opt3 == 3); 1019 Alias.removeArgument(); 1020 } 1021 1022 TEST(CommandLineTest, ReadConfigFile) { 1023 llvm::SmallVector<const char *, 1> Argv; 1024 1025 llvm::SmallString<128> TestDir; 1026 std::error_code EC = 1027 llvm::sys::fs::createUniqueDirectory("unittest", TestDir); 1028 EXPECT_TRUE(!EC); 1029 1030 llvm::SmallString<128> TestCfg; 1031 llvm::sys::path::append(TestCfg, TestDir, "foo"); 1032 std::ofstream ConfigFile(TestCfg.c_str()); 1033 EXPECT_TRUE(ConfigFile.is_open()); 1034 ConfigFile << "# Comment\n" 1035 "-option_1\n" 1036 "@subconfig\n" 1037 "-option_3=abcd\n" 1038 "-option_4=\\\n" 1039 "cdef\n"; 1040 ConfigFile.close(); 1041 1042 llvm::SmallString<128> TestCfg2; 1043 llvm::sys::path::append(TestCfg2, TestDir, "subconfig"); 1044 std::ofstream ConfigFile2(TestCfg2.c_str()); 1045 EXPECT_TRUE(ConfigFile2.is_open()); 1046 ConfigFile2 << "-option_2\n" 1047 "\n" 1048 " # comment\n"; 1049 ConfigFile2.close(); 1050 1051 // Make sure the current directory is not the directory where config files 1052 // resides. In this case the code that expands response files will not find 1053 // 'subconfig' unless it resolves nested inclusions relative to the including 1054 // file. 1055 llvm::SmallString<128> CurrDir; 1056 EC = llvm::sys::fs::current_path(CurrDir); 1057 EXPECT_TRUE(!EC); 1058 EXPECT_TRUE(StringRef(CurrDir) != StringRef(TestDir)); 1059 1060 llvm::BumpPtrAllocator A; 1061 llvm::StringSaver Saver(A); 1062 bool Result = llvm::cl::readConfigFile(TestCfg, Saver, Argv); 1063 1064 EXPECT_TRUE(Result); 1065 EXPECT_EQ(Argv.size(), 4U); 1066 EXPECT_STREQ(Argv[0], "-option_1"); 1067 EXPECT_STREQ(Argv[1], "-option_2"); 1068 EXPECT_STREQ(Argv[2], "-option_3=abcd"); 1069 EXPECT_STREQ(Argv[3], "-option_4=cdef"); 1070 1071 llvm::sys::fs::remove(TestCfg2); 1072 llvm::sys::fs::remove(TestCfg); 1073 llvm::sys::fs::remove(TestDir); 1074 } 1075 1076 TEST(CommandLineTest, PositionalEatArgsError) { 1077 cl::ResetCommandLineParser(); 1078 1079 StackOption<std::string, cl::list<std::string>> PosEatArgs( 1080 "positional-eat-args", cl::Positional, cl::desc("<arguments>..."), 1081 cl::ZeroOrMore, cl::PositionalEatsArgs); 1082 StackOption<std::string, cl::list<std::string>> PosEatArgs2( 1083 "positional-eat-args2", cl::Positional, cl::desc("Some strings"), 1084 cl::ZeroOrMore, cl::PositionalEatsArgs); 1085 1086 const char *args[] = {"prog", "-positional-eat-args=XXXX"}; 1087 const char *args2[] = {"prog", "-positional-eat-args=XXXX", "-foo"}; 1088 const char *args3[] = {"prog", "-positional-eat-args", "-foo"}; 1089 const char *args4[] = {"prog", "-positional-eat-args", 1090 "-foo", "-positional-eat-args2", 1091 "-bar", "foo"}; 1092 1093 std::string Errs; 1094 raw_string_ostream OS(Errs); 1095 EXPECT_FALSE(cl::ParseCommandLineOptions(2, args, StringRef(), &OS)); OS.flush(); 1096 EXPECT_FALSE(Errs.empty()); Errs.clear(); 1097 EXPECT_FALSE(cl::ParseCommandLineOptions(3, args2, StringRef(), &OS)); OS.flush(); 1098 EXPECT_FALSE(Errs.empty()); Errs.clear(); 1099 EXPECT_TRUE(cl::ParseCommandLineOptions(3, args3, StringRef(), &OS)); OS.flush(); 1100 EXPECT_TRUE(Errs.empty()); Errs.clear(); 1101 1102 cl::ResetAllOptionOccurrences(); 1103 EXPECT_TRUE(cl::ParseCommandLineOptions(6, args4, StringRef(), &OS)); OS.flush(); 1104 EXPECT_TRUE(PosEatArgs.size() == 1); 1105 EXPECT_TRUE(PosEatArgs2.size() == 2); 1106 EXPECT_TRUE(Errs.empty()); 1107 } 1108 1109 #ifdef _WIN32 1110 TEST(CommandLineTest, GetCommandLineArguments) { 1111 int argc = __argc; 1112 char **argv = __argv; 1113 1114 // GetCommandLineArguments is called in InitLLVM. 1115 llvm::InitLLVM X(argc, argv); 1116 1117 EXPECT_EQ(llvm::sys::path::is_absolute(argv[0]), 1118 llvm::sys::path::is_absolute(__argv[0])); 1119 1120 EXPECT_TRUE(llvm::sys::path::filename(argv[0]) 1121 .equals_lower("supporttests.exe")) 1122 << "Filename of test executable is " 1123 << llvm::sys::path::filename(argv[0]); 1124 } 1125 #endif 1126 1127 class OutputRedirector { 1128 public: 1129 OutputRedirector(int RedirectFD) 1130 : RedirectFD(RedirectFD), OldFD(dup(RedirectFD)) { 1131 if (OldFD == -1 || 1132 sys::fs::createTemporaryFile("unittest-redirect", "", NewFD, 1133 FilePath) || 1134 dup2(NewFD, RedirectFD) == -1) 1135 Valid = false; 1136 } 1137 1138 ~OutputRedirector() { 1139 dup2(OldFD, RedirectFD); 1140 close(OldFD); 1141 close(NewFD); 1142 } 1143 1144 SmallVector<char, 128> FilePath; 1145 bool Valid = true; 1146 1147 private: 1148 int RedirectFD; 1149 int OldFD; 1150 int NewFD; 1151 }; 1152 1153 struct AutoDeleteFile { 1154 SmallVector<char, 128> FilePath; 1155 ~AutoDeleteFile() { 1156 if (!FilePath.empty()) 1157 sys::fs::remove(std::string(FilePath.data(), FilePath.size())); 1158 } 1159 }; 1160 1161 class PrintOptionInfoTest : public ::testing::Test { 1162 public: 1163 // Return std::string because the output of a failing EXPECT check is 1164 // unreadable for StringRef. It also avoids any lifetime issues. 1165 template <typename... Ts> std::string runTest(Ts... OptionAttributes) { 1166 outs().flush(); // flush any output from previous tests 1167 AutoDeleteFile File; 1168 { 1169 OutputRedirector Stdout(fileno(stdout)); 1170 if (!Stdout.Valid) 1171 return ""; 1172 File.FilePath = Stdout.FilePath; 1173 1174 StackOption<OptionValue> TestOption(Opt, cl::desc(HelpText), 1175 OptionAttributes...); 1176 printOptionInfo(TestOption, 26); 1177 outs().flush(); 1178 } 1179 auto Buffer = MemoryBuffer::getFile(File.FilePath); 1180 if (!Buffer) 1181 return ""; 1182 return Buffer->get()->getBuffer().str(); 1183 } 1184 1185 enum class OptionValue { Val }; 1186 const StringRef Opt = "some-option"; 1187 const StringRef HelpText = "some help"; 1188 1189 private: 1190 // This is a workaround for cl::Option sub-classes having their 1191 // printOptionInfo functions private. 1192 void printOptionInfo(const cl::Option &O, size_t Width) { 1193 O.printOptionInfo(Width); 1194 } 1195 }; 1196 1197 TEST_F(PrintOptionInfoTest, PrintOptionInfoValueOptionalWithoutSentinel) { 1198 std::string Output = 1199 runTest(cl::ValueOptional, 1200 cl::values(clEnumValN(OptionValue::Val, "v1", "desc1"))); 1201 1202 // clang-format off 1203 EXPECT_EQ(Output, (" --" + Opt + "=<value> - " + HelpText + "\n" 1204 " =v1 - desc1\n") 1205 .str()); 1206 // clang-format on 1207 } 1208 1209 TEST_F(PrintOptionInfoTest, PrintOptionInfoValueOptionalWithSentinel) { 1210 std::string Output = runTest( 1211 cl::ValueOptional, cl::values(clEnumValN(OptionValue::Val, "v1", "desc1"), 1212 clEnumValN(OptionValue::Val, "", ""))); 1213 1214 // clang-format off 1215 EXPECT_EQ(Output, 1216 (" --" + Opt + " - " + HelpText + "\n" 1217 " --" + Opt + "=<value> - " + HelpText + "\n" 1218 " =v1 - desc1\n") 1219 .str()); 1220 // clang-format on 1221 } 1222 1223 TEST_F(PrintOptionInfoTest, PrintOptionInfoValueOptionalWithSentinelWithHelp) { 1224 std::string Output = runTest( 1225 cl::ValueOptional, cl::values(clEnumValN(OptionValue::Val, "v1", "desc1"), 1226 clEnumValN(OptionValue::Val, "", "desc2"))); 1227 1228 // clang-format off 1229 EXPECT_EQ(Output, (" --" + Opt + " - " + HelpText + "\n" 1230 " --" + Opt + "=<value> - " + HelpText + "\n" 1231 " =v1 - desc1\n" 1232 " =<empty> - desc2\n") 1233 .str()); 1234 // clang-format on 1235 } 1236 1237 TEST_F(PrintOptionInfoTest, PrintOptionInfoValueRequiredWithEmptyValueName) { 1238 std::string Output = runTest( 1239 cl::ValueRequired, cl::values(clEnumValN(OptionValue::Val, "v1", "desc1"), 1240 clEnumValN(OptionValue::Val, "", ""))); 1241 1242 // clang-format off 1243 EXPECT_EQ(Output, (" --" + Opt + "=<value> - " + HelpText + "\n" 1244 " =v1 - desc1\n" 1245 " =<empty>\n") 1246 .str()); 1247 // clang-format on 1248 } 1249 1250 TEST_F(PrintOptionInfoTest, PrintOptionInfoEmptyValueDescription) { 1251 std::string Output = runTest( 1252 cl::ValueRequired, cl::values(clEnumValN(OptionValue::Val, "v1", ""))); 1253 1254 // clang-format off 1255 EXPECT_EQ(Output, 1256 (" --" + Opt + "=<value> - " + HelpText + "\n" 1257 " =v1\n").str()); 1258 // clang-format on 1259 } 1260 1261 class GetOptionWidthTest : public ::testing::Test { 1262 public: 1263 enum class OptionValue { Val }; 1264 1265 template <typename... Ts> 1266 size_t runTest(StringRef ArgName, Ts... OptionAttributes) { 1267 StackOption<OptionValue> TestOption(ArgName, cl::desc("some help"), 1268 OptionAttributes...); 1269 return getOptionWidth(TestOption); 1270 } 1271 1272 private: 1273 // This is a workaround for cl::Option sub-classes having their 1274 // printOptionInfo 1275 // functions private. 1276 size_t getOptionWidth(const cl::Option &O) { return O.getOptionWidth(); } 1277 }; 1278 1279 TEST_F(GetOptionWidthTest, GetOptionWidthArgNameLonger) { 1280 StringRef ArgName("a-long-argument-name"); 1281 size_t ExpectedStrSize = (" --" + ArgName + "=<value> - ").str().size(); 1282 EXPECT_EQ( 1283 runTest(ArgName, cl::values(clEnumValN(OptionValue::Val, "v", "help"))), 1284 ExpectedStrSize); 1285 } 1286 1287 TEST_F(GetOptionWidthTest, GetOptionWidthFirstOptionNameLonger) { 1288 StringRef OptName("a-long-option-name"); 1289 size_t ExpectedStrSize = (" =" + OptName + " - ").str().size(); 1290 EXPECT_EQ( 1291 runTest("a", cl::values(clEnumValN(OptionValue::Val, OptName, "help"), 1292 clEnumValN(OptionValue::Val, "b", "help"))), 1293 ExpectedStrSize); 1294 } 1295 1296 TEST_F(GetOptionWidthTest, GetOptionWidthSecondOptionNameLonger) { 1297 StringRef OptName("a-long-option-name"); 1298 size_t ExpectedStrSize = (" =" + OptName + " - ").str().size(); 1299 EXPECT_EQ( 1300 runTest("a", cl::values(clEnumValN(OptionValue::Val, "b", "help"), 1301 clEnumValN(OptionValue::Val, OptName, "help"))), 1302 ExpectedStrSize); 1303 } 1304 1305 TEST_F(GetOptionWidthTest, GetOptionWidthEmptyOptionNameLonger) { 1306 size_t ExpectedStrSize = StringRef(" =<empty> - ").size(); 1307 // The length of a=<value> (including indentation) is actually the same as the 1308 // =<empty> string, so it is impossible to distinguish via testing the case 1309 // where the empty string is picked from where the option name is picked. 1310 EXPECT_EQ(runTest("a", cl::values(clEnumValN(OptionValue::Val, "b", "help"), 1311 clEnumValN(OptionValue::Val, "", "help"))), 1312 ExpectedStrSize); 1313 } 1314 1315 TEST_F(GetOptionWidthTest, 1316 GetOptionWidthValueOptionalEmptyOptionWithNoDescription) { 1317 StringRef ArgName("a"); 1318 // The length of a=<value> (including indentation) is actually the same as the 1319 // =<empty> string, so it is impossible to distinguish via testing the case 1320 // where the empty string is ignored from where it is not ignored. 1321 // The dash will not actually be printed, but the space it would take up is 1322 // included to ensure a consistent column width. 1323 size_t ExpectedStrSize = (" -" + ArgName + "=<value> - ").str().size(); 1324 EXPECT_EQ(runTest(ArgName, cl::ValueOptional, 1325 cl::values(clEnumValN(OptionValue::Val, "value", "help"), 1326 clEnumValN(OptionValue::Val, "", ""))), 1327 ExpectedStrSize); 1328 } 1329 1330 TEST_F(GetOptionWidthTest, 1331 GetOptionWidthValueRequiredEmptyOptionWithNoDescription) { 1332 // The length of a=<value> (including indentation) is actually the same as the 1333 // =<empty> string, so it is impossible to distinguish via testing the case 1334 // where the empty string is picked from where the option name is picked 1335 size_t ExpectedStrSize = StringRef(" =<empty> - ").size(); 1336 EXPECT_EQ(runTest("a", cl::ValueRequired, 1337 cl::values(clEnumValN(OptionValue::Val, "value", "help"), 1338 clEnumValN(OptionValue::Val, "", ""))), 1339 ExpectedStrSize); 1340 } 1341 1342 TEST(CommandLineTest, PrefixOptions) { 1343 cl::ResetCommandLineParser(); 1344 1345 StackOption<std::string, cl::list<std::string>> IncludeDirs( 1346 "I", cl::Prefix, cl::desc("Declare an include directory")); 1347 1348 // Test non-prefixed variant works with cl::Prefix options. 1349 EXPECT_TRUE(IncludeDirs.empty()); 1350 const char *args[] = {"prog", "-I=/usr/include"}; 1351 EXPECT_TRUE( 1352 cl::ParseCommandLineOptions(2, args, StringRef(), &llvm::nulls())); 1353 EXPECT_TRUE(IncludeDirs.size() == 1); 1354 EXPECT_TRUE(IncludeDirs.front().compare("/usr/include") == 0); 1355 1356 IncludeDirs.erase(IncludeDirs.begin()); 1357 cl::ResetAllOptionOccurrences(); 1358 1359 // Test non-prefixed variant works with cl::Prefix options when value is 1360 // passed in following argument. 1361 EXPECT_TRUE(IncludeDirs.empty()); 1362 const char *args2[] = {"prog", "-I", "/usr/include"}; 1363 EXPECT_TRUE( 1364 cl::ParseCommandLineOptions(3, args2, StringRef(), &llvm::nulls())); 1365 EXPECT_TRUE(IncludeDirs.size() == 1); 1366 EXPECT_TRUE(IncludeDirs.front().compare("/usr/include") == 0); 1367 1368 IncludeDirs.erase(IncludeDirs.begin()); 1369 cl::ResetAllOptionOccurrences(); 1370 1371 // Test prefixed variant works with cl::Prefix options. 1372 EXPECT_TRUE(IncludeDirs.empty()); 1373 const char *args3[] = {"prog", "-I/usr/include"}; 1374 EXPECT_TRUE( 1375 cl::ParseCommandLineOptions(2, args3, StringRef(), &llvm::nulls())); 1376 EXPECT_TRUE(IncludeDirs.size() == 1); 1377 EXPECT_TRUE(IncludeDirs.front().compare("/usr/include") == 0); 1378 1379 StackOption<std::string, cl::list<std::string>> MacroDefs( 1380 "D", cl::AlwaysPrefix, cl::desc("Define a macro"), 1381 cl::value_desc("MACRO[=VALUE]")); 1382 1383 cl::ResetAllOptionOccurrences(); 1384 1385 // Test non-prefixed variant does not work with cl::AlwaysPrefix options: 1386 // equal sign is part of the value. 1387 EXPECT_TRUE(MacroDefs.empty()); 1388 const char *args4[] = {"prog", "-D=HAVE_FOO"}; 1389 EXPECT_TRUE( 1390 cl::ParseCommandLineOptions(2, args4, StringRef(), &llvm::nulls())); 1391 EXPECT_TRUE(MacroDefs.size() == 1); 1392 EXPECT_TRUE(MacroDefs.front().compare("=HAVE_FOO") == 0); 1393 1394 MacroDefs.erase(MacroDefs.begin()); 1395 cl::ResetAllOptionOccurrences(); 1396 1397 // Test non-prefixed variant does not allow value to be passed in following 1398 // argument with cl::AlwaysPrefix options. 1399 EXPECT_TRUE(MacroDefs.empty()); 1400 const char *args5[] = {"prog", "-D", "HAVE_FOO"}; 1401 EXPECT_FALSE( 1402 cl::ParseCommandLineOptions(3, args5, StringRef(), &llvm::nulls())); 1403 EXPECT_TRUE(MacroDefs.empty()); 1404 1405 cl::ResetAllOptionOccurrences(); 1406 1407 // Test prefixed variant works with cl::AlwaysPrefix options. 1408 EXPECT_TRUE(MacroDefs.empty()); 1409 const char *args6[] = {"prog", "-DHAVE_FOO"}; 1410 EXPECT_TRUE( 1411 cl::ParseCommandLineOptions(2, args6, StringRef(), &llvm::nulls())); 1412 EXPECT_TRUE(MacroDefs.size() == 1); 1413 EXPECT_TRUE(MacroDefs.front().compare("HAVE_FOO") == 0); 1414 } 1415 1416 TEST(CommandLineTest, GroupingWithValue) { 1417 cl::ResetCommandLineParser(); 1418 1419 StackOption<bool> OptF("f", cl::Grouping, cl::desc("Some flag")); 1420 StackOption<bool> OptB("b", cl::Grouping, cl::desc("Another flag")); 1421 StackOption<bool> OptD("d", cl::Grouping, cl::ValueDisallowed, 1422 cl::desc("ValueDisallowed option")); 1423 StackOption<std::string> OptV("v", cl::Grouping, 1424 cl::desc("ValueRequired option")); 1425 StackOption<std::string> OptO("o", cl::Grouping, cl::ValueOptional, 1426 cl::desc("ValueOptional option")); 1427 1428 // Should be possible to use an option which requires a value 1429 // at the end of a group. 1430 const char *args1[] = {"prog", "-fv", "val1"}; 1431 EXPECT_TRUE( 1432 cl::ParseCommandLineOptions(3, args1, StringRef(), &llvm::nulls())); 1433 EXPECT_TRUE(OptF); 1434 EXPECT_STREQ("val1", OptV.c_str()); 1435 OptV.clear(); 1436 cl::ResetAllOptionOccurrences(); 1437 1438 // Should not crash if it is accidentally used elsewhere in the group. 1439 const char *args2[] = {"prog", "-vf", "val2"}; 1440 EXPECT_FALSE( 1441 cl::ParseCommandLineOptions(3, args2, StringRef(), &llvm::nulls())); 1442 OptV.clear(); 1443 cl::ResetAllOptionOccurrences(); 1444 1445 // Should allow the "opt=value" form at the end of the group 1446 const char *args3[] = {"prog", "-fv=val3"}; 1447 EXPECT_TRUE( 1448 cl::ParseCommandLineOptions(2, args3, StringRef(), &llvm::nulls())); 1449 EXPECT_TRUE(OptF); 1450 EXPECT_STREQ("val3", OptV.c_str()); 1451 OptV.clear(); 1452 cl::ResetAllOptionOccurrences(); 1453 1454 // Should allow assigning a value for a ValueOptional option 1455 // at the end of the group 1456 const char *args4[] = {"prog", "-fo=val4"}; 1457 EXPECT_TRUE( 1458 cl::ParseCommandLineOptions(2, args4, StringRef(), &llvm::nulls())); 1459 EXPECT_TRUE(OptF); 1460 EXPECT_STREQ("val4", OptO.c_str()); 1461 OptO.clear(); 1462 cl::ResetAllOptionOccurrences(); 1463 1464 // Should assign an empty value if a ValueOptional option is used elsewhere 1465 // in the group. 1466 const char *args5[] = {"prog", "-fob"}; 1467 EXPECT_TRUE( 1468 cl::ParseCommandLineOptions(2, args5, StringRef(), &llvm::nulls())); 1469 EXPECT_TRUE(OptF); 1470 EXPECT_EQ(1, OptO.getNumOccurrences()); 1471 EXPECT_EQ(1, OptB.getNumOccurrences()); 1472 EXPECT_TRUE(OptO.empty()); 1473 cl::ResetAllOptionOccurrences(); 1474 1475 // Should not allow an assignment for a ValueDisallowed option. 1476 const char *args6[] = {"prog", "-fd=false"}; 1477 EXPECT_FALSE( 1478 cl::ParseCommandLineOptions(2, args6, StringRef(), &llvm::nulls())); 1479 } 1480 1481 TEST(CommandLineTest, GroupingAndPrefix) { 1482 cl::ResetCommandLineParser(); 1483 1484 StackOption<bool> OptF("f", cl::Grouping, cl::desc("Some flag")); 1485 StackOption<bool> OptB("b", cl::Grouping, cl::desc("Another flag")); 1486 StackOption<std::string> OptP("p", cl::Prefix, cl::Grouping, 1487 cl::desc("Prefix and Grouping")); 1488 StackOption<std::string> OptA("a", cl::AlwaysPrefix, cl::Grouping, 1489 cl::desc("AlwaysPrefix and Grouping")); 1490 1491 // Should be possible to use a cl::Prefix option without grouping. 1492 const char *args1[] = {"prog", "-pval1"}; 1493 EXPECT_TRUE( 1494 cl::ParseCommandLineOptions(2, args1, StringRef(), &llvm::nulls())); 1495 EXPECT_STREQ("val1", OptP.c_str()); 1496 OptP.clear(); 1497 cl::ResetAllOptionOccurrences(); 1498 1499 // Should be possible to pass a value in a separate argument. 1500 const char *args2[] = {"prog", "-p", "val2"}; 1501 EXPECT_TRUE( 1502 cl::ParseCommandLineOptions(3, args2, StringRef(), &llvm::nulls())); 1503 EXPECT_STREQ("val2", OptP.c_str()); 1504 OptP.clear(); 1505 cl::ResetAllOptionOccurrences(); 1506 1507 // The "-opt=value" form should work, too. 1508 const char *args3[] = {"prog", "-p=val3"}; 1509 EXPECT_TRUE( 1510 cl::ParseCommandLineOptions(2, args3, StringRef(), &llvm::nulls())); 1511 EXPECT_STREQ("val3", OptP.c_str()); 1512 OptP.clear(); 1513 cl::ResetAllOptionOccurrences(); 1514 1515 // All three previous cases should work the same way if an option with both 1516 // cl::Prefix and cl::Grouping modifiers is used at the end of a group. 1517 const char *args4[] = {"prog", "-fpval4"}; 1518 EXPECT_TRUE( 1519 cl::ParseCommandLineOptions(2, args4, StringRef(), &llvm::nulls())); 1520 EXPECT_TRUE(OptF); 1521 EXPECT_STREQ("val4", OptP.c_str()); 1522 OptP.clear(); 1523 cl::ResetAllOptionOccurrences(); 1524 1525 const char *args5[] = {"prog", "-fp", "val5"}; 1526 EXPECT_TRUE( 1527 cl::ParseCommandLineOptions(3, args5, StringRef(), &llvm::nulls())); 1528 EXPECT_TRUE(OptF); 1529 EXPECT_STREQ("val5", OptP.c_str()); 1530 OptP.clear(); 1531 cl::ResetAllOptionOccurrences(); 1532 1533 const char *args6[] = {"prog", "-fp=val6"}; 1534 EXPECT_TRUE( 1535 cl::ParseCommandLineOptions(2, args6, StringRef(), &llvm::nulls())); 1536 EXPECT_TRUE(OptF); 1537 EXPECT_STREQ("val6", OptP.c_str()); 1538 OptP.clear(); 1539 cl::ResetAllOptionOccurrences(); 1540 1541 // Should assign a value even if the part after a cl::Prefix option is equal 1542 // to the name of another option. 1543 const char *args7[] = {"prog", "-fpb"}; 1544 EXPECT_TRUE( 1545 cl::ParseCommandLineOptions(2, args7, StringRef(), &llvm::nulls())); 1546 EXPECT_TRUE(OptF); 1547 EXPECT_STREQ("b", OptP.c_str()); 1548 EXPECT_FALSE(OptB); 1549 OptP.clear(); 1550 cl::ResetAllOptionOccurrences(); 1551 1552 // Should be possible to use a cl::AlwaysPrefix option without grouping. 1553 const char *args8[] = {"prog", "-aval8"}; 1554 EXPECT_TRUE( 1555 cl::ParseCommandLineOptions(2, args8, StringRef(), &llvm::nulls())); 1556 EXPECT_STREQ("val8", OptA.c_str()); 1557 OptA.clear(); 1558 cl::ResetAllOptionOccurrences(); 1559 1560 // Should not be possible to pass a value in a separate argument. 1561 const char *args9[] = {"prog", "-a", "val9"}; 1562 EXPECT_FALSE( 1563 cl::ParseCommandLineOptions(3, args9, StringRef(), &llvm::nulls())); 1564 cl::ResetAllOptionOccurrences(); 1565 1566 // With the "-opt=value" form, the "=" symbol should be preserved. 1567 const char *args10[] = {"prog", "-a=val10"}; 1568 EXPECT_TRUE( 1569 cl::ParseCommandLineOptions(2, args10, StringRef(), &llvm::nulls())); 1570 EXPECT_STREQ("=val10", OptA.c_str()); 1571 OptA.clear(); 1572 cl::ResetAllOptionOccurrences(); 1573 1574 // All three previous cases should work the same way if an option with both 1575 // cl::AlwaysPrefix and cl::Grouping modifiers is used at the end of a group. 1576 const char *args11[] = {"prog", "-faval11"}; 1577 EXPECT_TRUE( 1578 cl::ParseCommandLineOptions(2, args11, StringRef(), &llvm::nulls())); 1579 EXPECT_TRUE(OptF); 1580 EXPECT_STREQ("val11", OptA.c_str()); 1581 OptA.clear(); 1582 cl::ResetAllOptionOccurrences(); 1583 1584 const char *args12[] = {"prog", "-fa", "val12"}; 1585 EXPECT_FALSE( 1586 cl::ParseCommandLineOptions(3, args12, StringRef(), &llvm::nulls())); 1587 cl::ResetAllOptionOccurrences(); 1588 1589 const char *args13[] = {"prog", "-fa=val13"}; 1590 EXPECT_TRUE( 1591 cl::ParseCommandLineOptions(2, args13, StringRef(), &llvm::nulls())); 1592 EXPECT_TRUE(OptF); 1593 EXPECT_STREQ("=val13", OptA.c_str()); 1594 OptA.clear(); 1595 cl::ResetAllOptionOccurrences(); 1596 1597 // Should assign a value even if the part after a cl::AlwaysPrefix option 1598 // is equal to the name of another option. 1599 const char *args14[] = {"prog", "-fab"}; 1600 EXPECT_TRUE( 1601 cl::ParseCommandLineOptions(2, args14, StringRef(), &llvm::nulls())); 1602 EXPECT_TRUE(OptF); 1603 EXPECT_STREQ("b", OptA.c_str()); 1604 EXPECT_FALSE(OptB); 1605 OptA.clear(); 1606 cl::ResetAllOptionOccurrences(); 1607 } 1608 1609 TEST(CommandLineTest, LongOptions) { 1610 cl::ResetCommandLineParser(); 1611 1612 StackOption<bool> OptA("a", cl::desc("Some flag")); 1613 StackOption<bool> OptBLong("long-flag", cl::desc("Some long flag")); 1614 StackOption<bool, cl::alias> OptB("b", cl::desc("Alias to --long-flag"), 1615 cl::aliasopt(OptBLong)); 1616 StackOption<std::string> OptAB("ab", cl::desc("Another long option")); 1617 1618 std::string Errs; 1619 raw_string_ostream OS(Errs); 1620 1621 const char *args1[] = {"prog", "-a", "-ab", "val1"}; 1622 const char *args2[] = {"prog", "-a", "--ab", "val1"}; 1623 const char *args3[] = {"prog", "-ab", "--ab", "val1"}; 1624 1625 // 1626 // The following tests treat `-` and `--` the same, and always match the 1627 // longest string. 1628 // 1629 1630 EXPECT_TRUE( 1631 cl::ParseCommandLineOptions(4, args1, StringRef(), &OS)); OS.flush(); 1632 EXPECT_TRUE(OptA); 1633 EXPECT_FALSE(OptBLong); 1634 EXPECT_STREQ("val1", OptAB.c_str()); 1635 EXPECT_TRUE(Errs.empty()); Errs.clear(); 1636 cl::ResetAllOptionOccurrences(); 1637 1638 EXPECT_TRUE( 1639 cl::ParseCommandLineOptions(4, args2, StringRef(), &OS)); OS.flush(); 1640 EXPECT_TRUE(OptA); 1641 EXPECT_FALSE(OptBLong); 1642 EXPECT_STREQ("val1", OptAB.c_str()); 1643 EXPECT_TRUE(Errs.empty()); Errs.clear(); 1644 cl::ResetAllOptionOccurrences(); 1645 1646 // Fails because `-ab` and `--ab` are treated the same and appear more than 1647 // once. Also, `val1` is unexpected. 1648 EXPECT_FALSE( 1649 cl::ParseCommandLineOptions(4, args3, StringRef(), &OS)); OS.flush(); 1650 outs()<< Errs << "\n"; 1651 EXPECT_FALSE(Errs.empty()); Errs.clear(); 1652 cl::ResetAllOptionOccurrences(); 1653 1654 // 1655 // The following tests treat `-` and `--` differently, with `-` for short, and 1656 // `--` for long options. 1657 // 1658 1659 // Fails because `-ab` is treated as `-a -b`, so `-a` is seen twice, and 1660 // `val1` is unexpected. 1661 EXPECT_FALSE(cl::ParseCommandLineOptions(4, args1, StringRef(), 1662 &OS, nullptr, true)); OS.flush(); 1663 EXPECT_FALSE(Errs.empty()); Errs.clear(); 1664 cl::ResetAllOptionOccurrences(); 1665 1666 // Works because `-a` is treated differently than `--ab`. 1667 EXPECT_TRUE(cl::ParseCommandLineOptions(4, args2, StringRef(), 1668 &OS, nullptr, true)); OS.flush(); 1669 EXPECT_TRUE(Errs.empty()); Errs.clear(); 1670 cl::ResetAllOptionOccurrences(); 1671 1672 // Works because `-ab` is treated as `-a -b`, and `--ab` is a long option. 1673 EXPECT_TRUE(cl::ParseCommandLineOptions(4, args3, StringRef(), 1674 &OS, nullptr, true)); 1675 EXPECT_TRUE(OptA); 1676 EXPECT_TRUE(OptBLong); 1677 EXPECT_STREQ("val1", OptAB.c_str()); 1678 OS.flush(); 1679 EXPECT_TRUE(Errs.empty()); Errs.clear(); 1680 cl::ResetAllOptionOccurrences(); 1681 } 1682 } // anonymous namespace 1683