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