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/StringRef.h" 13 #include "llvm/ADT/Triple.h" 14 #include "llvm/Config/config.h" 15 #include "llvm/Support/Allocator.h" 16 #include "llvm/Support/FileSystem.h" 17 #include "llvm/Support/Host.h" 18 #include "llvm/Support/InitLLVM.h" 19 #include "llvm/Support/MemoryBuffer.h" 20 #include "llvm/Support/Path.h" 21 #include "llvm/Support/Program.h" 22 #include "llvm/Support/StringSaver.h" 23 #include "llvm/Support/VirtualFileSystem.h" 24 #include "llvm/Support/raw_ostream.h" 25 #include "llvm/Testing/Support/SupportHelpers.h" 26 #include "gmock/gmock.h" 27 #include "gtest/gtest.h" 28 #include <fstream> 29 #include <stdlib.h> 30 #include <string> 31 #include <tuple> 32 33 using namespace llvm; 34 using llvm::unittest::TempDir; 35 using llvm::unittest::TempFile; 36 37 namespace { 38 39 MATCHER(StringEquality, "Checks if two char* are equal as strings") { 40 return std::string(std::get<0>(arg)) == std::string(std::get<1>(arg)); 41 } 42 43 class TempEnvVar { 44 public: 45 TempEnvVar(const char *name, const char *value) 46 : name(name) { 47 const char *old_value = getenv(name); 48 EXPECT_EQ(nullptr, old_value) << old_value; 49 #if HAVE_SETENV 50 setenv(name, value, true); 51 #endif 52 } 53 54 ~TempEnvVar() { 55 #if HAVE_SETENV 56 // Assume setenv and unsetenv come together. 57 unsetenv(name); 58 #else 59 (void)name; // Suppress -Wunused-private-field. 60 #endif 61 } 62 63 private: 64 const char *const name; 65 }; 66 67 template <typename T, typename Base = cl::opt<T>> 68 class StackOption : public Base { 69 public: 70 template <class... Ts> 71 explicit StackOption(Ts &&... Ms) : Base(std::forward<Ts>(Ms)...) {} 72 73 ~StackOption() override { this->removeArgument(); } 74 75 template <class DT> StackOption<T> &operator=(const DT &V) { 76 Base::operator=(V); 77 return *this; 78 } 79 }; 80 81 class StackSubCommand : public cl::SubCommand { 82 public: 83 StackSubCommand(StringRef Name, 84 StringRef Description = StringRef()) 85 : SubCommand(Name, Description) {} 86 87 StackSubCommand() : SubCommand() {} 88 89 ~StackSubCommand() { unregisterSubCommand(); } 90 }; 91 92 93 cl::OptionCategory TestCategory("Test Options", "Description"); 94 TEST(CommandLineTest, ModifyExisitingOption) { 95 StackOption<int> TestOption("test-option", cl::desc("old description")); 96 97 static const char Description[] = "New description"; 98 static const char ArgString[] = "new-test-option"; 99 static const char ValueString[] = "Integer"; 100 101 StringMap<cl::Option *> &Map = 102 cl::getRegisteredOptions(*cl::TopLevelSubCommand); 103 104 ASSERT_EQ(Map.count("test-option"), 1u) << "Could not find option in map."; 105 106 cl::Option *Retrieved = Map["test-option"]; 107 ASSERT_EQ(&TestOption, Retrieved) << "Retrieved wrong option."; 108 109 ASSERT_NE(Retrieved->Categories.end(), 110 find_if(Retrieved->Categories, 111 [&](const llvm::cl::OptionCategory *Cat) { 112 return Cat == &cl::getGeneralCategory(); 113 })) 114 << "Incorrect default option category."; 115 116 Retrieved->addCategory(TestCategory); 117 ASSERT_NE(Retrieved->Categories.end(), 118 find_if(Retrieved->Categories, 119 [&](const llvm::cl::OptionCategory *Cat) { 120 return Cat == &TestCategory; 121 })) 122 << "Failed to modify option's option category."; 123 124 Retrieved->setDescription(Description); 125 ASSERT_STREQ(Retrieved->HelpStr.data(), Description) 126 << "Changing option description failed."; 127 128 Retrieved->setArgStr(ArgString); 129 ASSERT_STREQ(ArgString, Retrieved->ArgStr.data()) 130 << "Failed to modify option's Argument string."; 131 132 Retrieved->setValueStr(ValueString); 133 ASSERT_STREQ(Retrieved->ValueStr.data(), ValueString) 134 << "Failed to modify option's Value string."; 135 136 Retrieved->setHiddenFlag(cl::Hidden); 137 ASSERT_EQ(cl::Hidden, TestOption.getOptionHiddenFlag()) << 138 "Failed to modify option's hidden flag."; 139 } 140 141 TEST(CommandLineTest, UseOptionCategory) { 142 StackOption<int> TestOption2("test-option", cl::cat(TestCategory)); 143 144 ASSERT_NE(TestOption2.Categories.end(), 145 find_if(TestOption2.Categories, 146 [&](const llvm::cl::OptionCategory *Cat) { 147 return Cat == &TestCategory; 148 })) 149 << "Failed to assign Option Category."; 150 } 151 152 TEST(CommandLineTest, UseMultipleCategories) { 153 StackOption<int> TestOption2("test-option2", cl::cat(TestCategory), 154 cl::cat(cl::getGeneralCategory()), 155 cl::cat(cl::getGeneralCategory())); 156 157 // Make sure cl::getGeneralCategory() wasn't added twice. 158 ASSERT_EQ(TestOption2.Categories.size(), 2U); 159 160 ASSERT_NE(TestOption2.Categories.end(), 161 find_if(TestOption2.Categories, 162 [&](const llvm::cl::OptionCategory *Cat) { 163 return Cat == &TestCategory; 164 })) 165 << "Failed to assign Option Category."; 166 ASSERT_NE(TestOption2.Categories.end(), 167 find_if(TestOption2.Categories, 168 [&](const llvm::cl::OptionCategory *Cat) { 169 return Cat == &cl::getGeneralCategory(); 170 })) 171 << "Failed to assign General Category."; 172 173 cl::OptionCategory AnotherCategory("Additional test Options", "Description"); 174 StackOption<int> TestOption("test-option", cl::cat(TestCategory), 175 cl::cat(AnotherCategory)); 176 ASSERT_EQ(TestOption.Categories.end(), 177 find_if(TestOption.Categories, 178 [&](const llvm::cl::OptionCategory *Cat) { 179 return Cat == &cl::getGeneralCategory(); 180 })) 181 << "Failed to remove General Category."; 182 ASSERT_NE(TestOption.Categories.end(), 183 find_if(TestOption.Categories, 184 [&](const llvm::cl::OptionCategory *Cat) { 185 return Cat == &TestCategory; 186 })) 187 << "Failed to assign Option Category."; 188 ASSERT_NE(TestOption.Categories.end(), 189 find_if(TestOption.Categories, 190 [&](const llvm::cl::OptionCategory *Cat) { 191 return Cat == &AnotherCategory; 192 })) 193 << "Failed to assign Another Category."; 194 } 195 196 typedef void ParserFunction(StringRef Source, StringSaver &Saver, 197 SmallVectorImpl<const char *> &NewArgv, 198 bool MarkEOLs); 199 200 void testCommandLineTokenizer(ParserFunction *parse, StringRef Input, 201 ArrayRef<const char *> Output, 202 bool MarkEOLs = false) { 203 SmallVector<const char *, 0> Actual; 204 BumpPtrAllocator A; 205 StringSaver Saver(A); 206 parse(Input, Saver, Actual, MarkEOLs); 207 EXPECT_EQ(Output.size(), Actual.size()); 208 for (unsigned I = 0, E = Actual.size(); I != E; ++I) { 209 if (I < Output.size()) { 210 EXPECT_STREQ(Output[I], Actual[I]); 211 } 212 } 213 } 214 215 TEST(CommandLineTest, TokenizeGNUCommandLine) { 216 const char Input[] = 217 "foo\\ bar \"foo bar\" \'foo bar\' 'foo\\\\bar' -DFOO=bar\\(\\) " 218 "foo\"bar\"baz C:\\\\src\\\\foo.cpp \"C:\\src\\foo.cpp\""; 219 const char *const Output[] = { 220 "foo bar", "foo bar", "foo bar", "foo\\bar", 221 "-DFOO=bar()", "foobarbaz", "C:\\src\\foo.cpp", "C:srcfoo.cpp"}; 222 testCommandLineTokenizer(cl::TokenizeGNUCommandLine, Input, Output); 223 } 224 225 TEST(CommandLineTest, TokenizeWindowsCommandLine1) { 226 const char Input[] = 227 R"(a\b c\\d e\\"f g" h\"i j\\\"k "lmn" o pqr "st \"u" \v)"; 228 const char *const Output[] = { "a\\b", "c\\\\d", "e\\f g", "h\"i", "j\\\"k", 229 "lmn", "o", "pqr", "st \"u", "\\v" }; 230 testCommandLineTokenizer(cl::TokenizeWindowsCommandLine, Input, Output); 231 } 232 233 TEST(CommandLineTest, TokenizeWindowsCommandLine2) { 234 const char Input[] = "clang -c -DFOO=\"\"\"ABC\"\"\" x.cpp"; 235 const char *const Output[] = { "clang", "-c", "-DFOO=\"ABC\"", "x.cpp"}; 236 testCommandLineTokenizer(cl::TokenizeWindowsCommandLine, Input, Output); 237 } 238 239 TEST(CommandLineTest, TokenizeWindowsCommandLineQuotedLastArgument) { 240 const char Input1[] = R"(a b c d "")"; 241 const char *const Output1[] = {"a", "b", "c", "d", ""}; 242 testCommandLineTokenizer(cl::TokenizeWindowsCommandLine, Input1, Output1); 243 const char Input2[] = R"(a b c d ")"; 244 const char *const Output2[] = {"a", "b", "c", "d"}; 245 testCommandLineTokenizer(cl::TokenizeWindowsCommandLine, Input2, Output2); 246 } 247 248 TEST(CommandLineTest, TokenizeAndMarkEOLs) { 249 // Clang uses EOL marking in response files to support options that consume 250 // the rest of the arguments on the current line, but do not consume arguments 251 // from subsequent lines. For example, given these rsp files contents: 252 // /c /Zi /O2 253 // /Oy- /link /debug /opt:ref 254 // /Zc:ThreadsafeStatics- 255 // 256 // clang-cl needs to treat "/debug /opt:ref" as linker flags, and everything 257 // else as compiler flags. The tokenizer inserts nullptr sentinels into the 258 // output so that clang-cl can find the end of the current line. 259 const char Input[] = "clang -Xclang foo\n\nfoo\"bar\"baz\n x.cpp\n"; 260 const char *const Output[] = {"clang", "-Xclang", "foo", 261 nullptr, nullptr, "foobarbaz", 262 nullptr, "x.cpp", nullptr}; 263 testCommandLineTokenizer(cl::TokenizeWindowsCommandLine, Input, Output, 264 /*MarkEOLs=*/true); 265 testCommandLineTokenizer(cl::TokenizeGNUCommandLine, Input, Output, 266 /*MarkEOLs=*/true); 267 } 268 269 TEST(CommandLineTest, TokenizeConfigFile1) { 270 const char *Input = "\\"; 271 const char *const Output[] = { "\\" }; 272 testCommandLineTokenizer(cl::tokenizeConfigFile, Input, Output); 273 } 274 275 TEST(CommandLineTest, TokenizeConfigFile2) { 276 const char *Input = "\\abc"; 277 const char *const Output[] = { "abc" }; 278 testCommandLineTokenizer(cl::tokenizeConfigFile, Input, Output); 279 } 280 281 TEST(CommandLineTest, TokenizeConfigFile3) { 282 const char *Input = "abc\\"; 283 const char *const Output[] = { "abc\\" }; 284 testCommandLineTokenizer(cl::tokenizeConfigFile, Input, Output); 285 } 286 287 TEST(CommandLineTest, TokenizeConfigFile4) { 288 const char *Input = "abc\\\n123"; 289 const char *const Output[] = { "abc123" }; 290 testCommandLineTokenizer(cl::tokenizeConfigFile, Input, Output); 291 } 292 293 TEST(CommandLineTest, TokenizeConfigFile5) { 294 const char *Input = "abc\\\r\n123"; 295 const char *const Output[] = { "abc123" }; 296 testCommandLineTokenizer(cl::tokenizeConfigFile, Input, Output); 297 } 298 299 TEST(CommandLineTest, TokenizeConfigFile6) { 300 const char *Input = "abc\\\n"; 301 const char *const Output[] = { "abc" }; 302 testCommandLineTokenizer(cl::tokenizeConfigFile, Input, Output); 303 } 304 305 TEST(CommandLineTest, TokenizeConfigFile7) { 306 const char *Input = "abc\\\r\n"; 307 const char *const Output[] = { "abc" }; 308 testCommandLineTokenizer(cl::tokenizeConfigFile, Input, 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 } 332 333 TEST(CommandLineTest, TokenizeConfigFile11) { 334 const char *Input = "\\\r\nabc"; 335 const char *const Output[] = { "abc" }; 336 testCommandLineTokenizer(cl::tokenizeConfigFile, Input, Output); 337 } 338 339 TEST(CommandLineTest, AliasesWithArguments) { 340 static const size_t ARGC = 3; 341 const char *const Inputs[][ARGC] = { 342 { "-tool", "-actual=x", "-extra" }, 343 { "-tool", "-actual", "x" }, 344 { "-tool", "-alias=x", "-extra" }, 345 { "-tool", "-alias", "x" } 346 }; 347 348 for (size_t i = 0, e = array_lengthof(Inputs); i < e; ++i) { 349 StackOption<std::string> Actual("actual"); 350 StackOption<bool> Extra("extra"); 351 StackOption<std::string> Input(cl::Positional); 352 353 cl::alias Alias("alias", llvm::cl::aliasopt(Actual)); 354 355 cl::ParseCommandLineOptions(ARGC, Inputs[i]); 356 EXPECT_EQ("x", Actual); 357 EXPECT_EQ(0, Input.getNumOccurrences()); 358 359 Alias.removeArgument(); 360 } 361 } 362 363 void testAliasRequired(int argc, const char *const *argv) { 364 StackOption<std::string> Option("option", cl::Required); 365 cl::alias Alias("o", llvm::cl::aliasopt(Option)); 366 367 cl::ParseCommandLineOptions(argc, argv); 368 EXPECT_EQ("x", Option); 369 EXPECT_EQ(1, Option.getNumOccurrences()); 370 371 Alias.removeArgument(); 372 } 373 374 TEST(CommandLineTest, AliasRequired) { 375 const char *opts1[] = { "-tool", "-option=x" }; 376 const char *opts2[] = { "-tool", "-o", "x" }; 377 testAliasRequired(array_lengthof(opts1), opts1); 378 testAliasRequired(array_lengthof(opts2), opts2); 379 } 380 381 TEST(CommandLineTest, HideUnrelatedOptions) { 382 StackOption<int> TestOption1("hide-option-1"); 383 StackOption<int> TestOption2("hide-option-2", cl::cat(TestCategory)); 384 385 cl::HideUnrelatedOptions(TestCategory); 386 387 ASSERT_EQ(cl::ReallyHidden, TestOption1.getOptionHiddenFlag()) 388 << "Failed to hide extra option."; 389 ASSERT_EQ(cl::NotHidden, TestOption2.getOptionHiddenFlag()) 390 << "Hid extra option that should be visable."; 391 392 StringMap<cl::Option *> &Map = 393 cl::getRegisteredOptions(*cl::TopLevelSubCommand); 394 ASSERT_EQ(cl::NotHidden, Map["help"]->getOptionHiddenFlag()) 395 << "Hid default option that should be visable."; 396 } 397 398 cl::OptionCategory TestCategory2("Test Options set 2", "Description"); 399 400 TEST(CommandLineTest, HideUnrelatedOptionsMulti) { 401 StackOption<int> TestOption1("multi-hide-option-1"); 402 StackOption<int> TestOption2("multi-hide-option-2", cl::cat(TestCategory)); 403 StackOption<int> TestOption3("multi-hide-option-3", cl::cat(TestCategory2)); 404 405 const cl::OptionCategory *VisibleCategories[] = {&TestCategory, 406 &TestCategory2}; 407 408 cl::HideUnrelatedOptions(makeArrayRef(VisibleCategories)); 409 410 ASSERT_EQ(cl::ReallyHidden, TestOption1.getOptionHiddenFlag()) 411 << "Failed to hide extra option."; 412 ASSERT_EQ(cl::NotHidden, TestOption2.getOptionHiddenFlag()) 413 << "Hid extra option that should be visable."; 414 ASSERT_EQ(cl::NotHidden, TestOption3.getOptionHiddenFlag()) 415 << "Hid extra option that should be visable."; 416 417 StringMap<cl::Option *> &Map = 418 cl::getRegisteredOptions(*cl::TopLevelSubCommand); 419 ASSERT_EQ(cl::NotHidden, Map["help"]->getOptionHiddenFlag()) 420 << "Hid default option that should be visable."; 421 } 422 423 TEST(CommandLineTest, SetMultiValues) { 424 StackOption<int> Option("option"); 425 const char *args[] = {"prog", "-option=1", "-option=2"}; 426 EXPECT_TRUE(cl::ParseCommandLineOptions(array_lengthof(args), args, 427 StringRef(), &llvm::nulls())); 428 EXPECT_EQ(Option, 2); 429 } 430 431 TEST(CommandLineTest, SetValueInSubcategories) { 432 cl::ResetCommandLineParser(); 433 434 StackSubCommand SC1("sc1", "First subcommand"); 435 StackSubCommand SC2("sc2", "Second subcommand"); 436 437 StackOption<bool> TopLevelOpt("top-level", cl::init(false)); 438 StackOption<bool> SC1Opt("sc1", cl::sub(SC1), cl::init(false)); 439 StackOption<bool> SC2Opt("sc2", cl::sub(SC2), cl::init(false)); 440 441 EXPECT_FALSE(TopLevelOpt); 442 EXPECT_FALSE(SC1Opt); 443 EXPECT_FALSE(SC2Opt); 444 const char *args[] = {"prog", "-top-level"}; 445 EXPECT_TRUE( 446 cl::ParseCommandLineOptions(2, args, StringRef(), &llvm::nulls())); 447 EXPECT_TRUE(TopLevelOpt); 448 EXPECT_FALSE(SC1Opt); 449 EXPECT_FALSE(SC2Opt); 450 451 TopLevelOpt = false; 452 453 cl::ResetAllOptionOccurrences(); 454 EXPECT_FALSE(TopLevelOpt); 455 EXPECT_FALSE(SC1Opt); 456 EXPECT_FALSE(SC2Opt); 457 const char *args2[] = {"prog", "sc1", "-sc1"}; 458 EXPECT_TRUE( 459 cl::ParseCommandLineOptions(3, args2, StringRef(), &llvm::nulls())); 460 EXPECT_FALSE(TopLevelOpt); 461 EXPECT_TRUE(SC1Opt); 462 EXPECT_FALSE(SC2Opt); 463 464 SC1Opt = false; 465 466 cl::ResetAllOptionOccurrences(); 467 EXPECT_FALSE(TopLevelOpt); 468 EXPECT_FALSE(SC1Opt); 469 EXPECT_FALSE(SC2Opt); 470 const char *args3[] = {"prog", "sc2", "-sc2"}; 471 EXPECT_TRUE( 472 cl::ParseCommandLineOptions(3, args3, StringRef(), &llvm::nulls())); 473 EXPECT_FALSE(TopLevelOpt); 474 EXPECT_FALSE(SC1Opt); 475 EXPECT_TRUE(SC2Opt); 476 } 477 478 TEST(CommandLineTest, LookupFailsInWrongSubCommand) { 479 cl::ResetCommandLineParser(); 480 481 StackSubCommand SC1("sc1", "First subcommand"); 482 StackSubCommand SC2("sc2", "Second subcommand"); 483 484 StackOption<bool> SC1Opt("sc1", cl::sub(SC1), cl::init(false)); 485 StackOption<bool> SC2Opt("sc2", cl::sub(SC2), cl::init(false)); 486 487 std::string Errs; 488 raw_string_ostream OS(Errs); 489 490 const char *args[] = {"prog", "sc1", "-sc2"}; 491 EXPECT_FALSE(cl::ParseCommandLineOptions(3, args, StringRef(), &OS)); 492 OS.flush(); 493 EXPECT_FALSE(Errs.empty()); 494 } 495 496 TEST(CommandLineTest, AddToAllSubCommands) { 497 cl::ResetCommandLineParser(); 498 499 StackSubCommand SC1("sc1", "First subcommand"); 500 StackOption<bool> AllOpt("everywhere", cl::sub(*cl::AllSubCommands), 501 cl::init(false)); 502 StackSubCommand SC2("sc2", "Second subcommand"); 503 504 const char *args[] = {"prog", "-everywhere"}; 505 const char *args2[] = {"prog", "sc1", "-everywhere"}; 506 const char *args3[] = {"prog", "sc2", "-everywhere"}; 507 508 std::string Errs; 509 raw_string_ostream OS(Errs); 510 511 EXPECT_FALSE(AllOpt); 512 EXPECT_TRUE(cl::ParseCommandLineOptions(2, args, StringRef(), &OS)); 513 EXPECT_TRUE(AllOpt); 514 515 AllOpt = false; 516 517 cl::ResetAllOptionOccurrences(); 518 EXPECT_FALSE(AllOpt); 519 EXPECT_TRUE(cl::ParseCommandLineOptions(3, args2, StringRef(), &OS)); 520 EXPECT_TRUE(AllOpt); 521 522 AllOpt = false; 523 524 cl::ResetAllOptionOccurrences(); 525 EXPECT_FALSE(AllOpt); 526 EXPECT_TRUE(cl::ParseCommandLineOptions(3, args3, StringRef(), &OS)); 527 EXPECT_TRUE(AllOpt); 528 529 // Since all parsing succeeded, the error message should be empty. 530 OS.flush(); 531 EXPECT_TRUE(Errs.empty()); 532 } 533 534 TEST(CommandLineTest, ReparseCommandLineOptions) { 535 cl::ResetCommandLineParser(); 536 537 StackOption<bool> TopLevelOpt("top-level", cl::sub(*cl::TopLevelSubCommand), 538 cl::init(false)); 539 540 const char *args[] = {"prog", "-top-level"}; 541 542 EXPECT_FALSE(TopLevelOpt); 543 EXPECT_TRUE( 544 cl::ParseCommandLineOptions(2, args, StringRef(), &llvm::nulls())); 545 EXPECT_TRUE(TopLevelOpt); 546 547 TopLevelOpt = false; 548 549 cl::ResetAllOptionOccurrences(); 550 EXPECT_FALSE(TopLevelOpt); 551 EXPECT_TRUE( 552 cl::ParseCommandLineOptions(2, args, StringRef(), &llvm::nulls())); 553 EXPECT_TRUE(TopLevelOpt); 554 } 555 556 TEST(CommandLineTest, RemoveFromRegularSubCommand) { 557 cl::ResetCommandLineParser(); 558 559 StackSubCommand SC("sc", "Subcommand"); 560 StackOption<bool> RemoveOption("remove-option", cl::sub(SC), cl::init(false)); 561 StackOption<bool> KeepOption("keep-option", cl::sub(SC), cl::init(false)); 562 563 const char *args[] = {"prog", "sc", "-remove-option"}; 564 565 std::string Errs; 566 raw_string_ostream OS(Errs); 567 568 EXPECT_FALSE(RemoveOption); 569 EXPECT_TRUE(cl::ParseCommandLineOptions(3, args, StringRef(), &OS)); 570 EXPECT_TRUE(RemoveOption); 571 OS.flush(); 572 EXPECT_TRUE(Errs.empty()); 573 574 RemoveOption.removeArgument(); 575 576 cl::ResetAllOptionOccurrences(); 577 EXPECT_FALSE(cl::ParseCommandLineOptions(3, args, StringRef(), &OS)); 578 OS.flush(); 579 EXPECT_FALSE(Errs.empty()); 580 } 581 582 TEST(CommandLineTest, RemoveFromTopLevelSubCommand) { 583 cl::ResetCommandLineParser(); 584 585 StackOption<bool> TopLevelRemove( 586 "top-level-remove", cl::sub(*cl::TopLevelSubCommand), cl::init(false)); 587 StackOption<bool> TopLevelKeep( 588 "top-level-keep", cl::sub(*cl::TopLevelSubCommand), cl::init(false)); 589 590 const char *args[] = {"prog", "-top-level-remove"}; 591 592 EXPECT_FALSE(TopLevelRemove); 593 EXPECT_TRUE( 594 cl::ParseCommandLineOptions(2, args, StringRef(), &llvm::nulls())); 595 EXPECT_TRUE(TopLevelRemove); 596 597 TopLevelRemove.removeArgument(); 598 599 cl::ResetAllOptionOccurrences(); 600 EXPECT_FALSE( 601 cl::ParseCommandLineOptions(2, args, StringRef(), &llvm::nulls())); 602 } 603 604 TEST(CommandLineTest, RemoveFromAllSubCommands) { 605 cl::ResetCommandLineParser(); 606 607 StackSubCommand SC1("sc1", "First Subcommand"); 608 StackSubCommand SC2("sc2", "Second Subcommand"); 609 StackOption<bool> RemoveOption("remove-option", cl::sub(*cl::AllSubCommands), 610 cl::init(false)); 611 StackOption<bool> KeepOption("keep-option", cl::sub(*cl::AllSubCommands), 612 cl::init(false)); 613 614 const char *args0[] = {"prog", "-remove-option"}; 615 const char *args1[] = {"prog", "sc1", "-remove-option"}; 616 const char *args2[] = {"prog", "sc2", "-remove-option"}; 617 618 // It should work for all subcommands including the top-level. 619 EXPECT_FALSE(RemoveOption); 620 EXPECT_TRUE( 621 cl::ParseCommandLineOptions(2, args0, StringRef(), &llvm::nulls())); 622 EXPECT_TRUE(RemoveOption); 623 624 RemoveOption = false; 625 626 cl::ResetAllOptionOccurrences(); 627 EXPECT_FALSE(RemoveOption); 628 EXPECT_TRUE( 629 cl::ParseCommandLineOptions(3, args1, StringRef(), &llvm::nulls())); 630 EXPECT_TRUE(RemoveOption); 631 632 RemoveOption = false; 633 634 cl::ResetAllOptionOccurrences(); 635 EXPECT_FALSE(RemoveOption); 636 EXPECT_TRUE( 637 cl::ParseCommandLineOptions(3, args2, StringRef(), &llvm::nulls())); 638 EXPECT_TRUE(RemoveOption); 639 640 RemoveOption.removeArgument(); 641 642 // It should not work for any subcommands including the top-level. 643 cl::ResetAllOptionOccurrences(); 644 EXPECT_FALSE( 645 cl::ParseCommandLineOptions(2, args0, StringRef(), &llvm::nulls())); 646 cl::ResetAllOptionOccurrences(); 647 EXPECT_FALSE( 648 cl::ParseCommandLineOptions(3, args1, StringRef(), &llvm::nulls())); 649 cl::ResetAllOptionOccurrences(); 650 EXPECT_FALSE( 651 cl::ParseCommandLineOptions(3, args2, StringRef(), &llvm::nulls())); 652 } 653 654 TEST(CommandLineTest, GetRegisteredSubcommands) { 655 cl::ResetCommandLineParser(); 656 657 StackSubCommand SC1("sc1", "First Subcommand"); 658 StackOption<bool> Opt1("opt1", cl::sub(SC1), cl::init(false)); 659 StackSubCommand SC2("sc2", "Second subcommand"); 660 StackOption<bool> Opt2("opt2", cl::sub(SC2), cl::init(false)); 661 662 const char *args0[] = {"prog", "sc1"}; 663 const char *args1[] = {"prog", "sc2"}; 664 665 EXPECT_TRUE( 666 cl::ParseCommandLineOptions(2, args0, StringRef(), &llvm::nulls())); 667 EXPECT_FALSE(Opt1); 668 EXPECT_FALSE(Opt2); 669 for (auto *S : cl::getRegisteredSubcommands()) { 670 if (*S) { 671 EXPECT_EQ("sc1", S->getName()); 672 } 673 } 674 675 cl::ResetAllOptionOccurrences(); 676 EXPECT_TRUE( 677 cl::ParseCommandLineOptions(2, args1, StringRef(), &llvm::nulls())); 678 EXPECT_FALSE(Opt1); 679 EXPECT_FALSE(Opt2); 680 for (auto *S : cl::getRegisteredSubcommands()) { 681 if (*S) { 682 EXPECT_EQ("sc2", S->getName()); 683 } 684 } 685 } 686 687 TEST(CommandLineTest, DefaultOptions) { 688 cl::ResetCommandLineParser(); 689 690 StackOption<std::string> Bar("bar", cl::sub(*cl::AllSubCommands), 691 cl::DefaultOption); 692 StackOption<std::string, cl::alias> Bar_Alias( 693 "b", cl::desc("Alias for -bar"), cl::aliasopt(Bar), cl::DefaultOption); 694 695 StackOption<bool> Foo("foo", cl::init(false), cl::sub(*cl::AllSubCommands), 696 cl::DefaultOption); 697 StackOption<bool, cl::alias> Foo_Alias("f", cl::desc("Alias for -foo"), 698 cl::aliasopt(Foo), cl::DefaultOption); 699 700 StackSubCommand SC1("sc1", "First Subcommand"); 701 // Override "-b" and change type in sc1 SubCommand. 702 StackOption<bool> SC1_B("b", cl::sub(SC1), cl::init(false)); 703 StackSubCommand SC2("sc2", "Second subcommand"); 704 // Override "-foo" and change type in sc2 SubCommand. Note that this does not 705 // affect "-f" alias, which continues to work correctly. 706 StackOption<std::string> SC2_Foo("foo", cl::sub(SC2)); 707 708 const char *args0[] = {"prog", "-b", "args0 bar string", "-f"}; 709 EXPECT_TRUE(cl::ParseCommandLineOptions(sizeof(args0) / sizeof(char *), args0, 710 StringRef(), &llvm::nulls())); 711 EXPECT_EQ(Bar, "args0 bar string"); 712 EXPECT_TRUE(Foo); 713 EXPECT_FALSE(SC1_B); 714 EXPECT_TRUE(SC2_Foo.empty()); 715 716 cl::ResetAllOptionOccurrences(); 717 718 const char *args1[] = {"prog", "sc1", "-b", "-bar", "args1 bar string", "-f"}; 719 EXPECT_TRUE(cl::ParseCommandLineOptions(sizeof(args1) / sizeof(char *), args1, 720 StringRef(), &llvm::nulls())); 721 EXPECT_EQ(Bar, "args1 bar string"); 722 EXPECT_TRUE(Foo); 723 EXPECT_TRUE(SC1_B); 724 EXPECT_TRUE(SC2_Foo.empty()); 725 for (auto *S : cl::getRegisteredSubcommands()) { 726 if (*S) { 727 EXPECT_EQ("sc1", S->getName()); 728 } 729 } 730 731 cl::ResetAllOptionOccurrences(); 732 733 const char *args2[] = {"prog", "sc2", "-b", "args2 bar string", 734 "-f", "-foo", "foo string"}; 735 EXPECT_TRUE(cl::ParseCommandLineOptions(sizeof(args2) / sizeof(char *), args2, 736 StringRef(), &llvm::nulls())); 737 EXPECT_EQ(Bar, "args2 bar string"); 738 EXPECT_TRUE(Foo); 739 EXPECT_FALSE(SC1_B); 740 EXPECT_EQ(SC2_Foo, "foo string"); 741 for (auto *S : cl::getRegisteredSubcommands()) { 742 if (*S) { 743 EXPECT_EQ("sc2", S->getName()); 744 } 745 } 746 cl::ResetCommandLineParser(); 747 } 748 749 TEST(CommandLineTest, ArgumentLimit) { 750 std::string args(32 * 4096, 'a'); 751 EXPECT_FALSE(llvm::sys::commandLineFitsWithinSystemLimits("cl", args.data())); 752 std::string args2(256, 'a'); 753 EXPECT_TRUE(llvm::sys::commandLineFitsWithinSystemLimits("cl", args2.data())); 754 } 755 756 TEST(CommandLineTest, ArgumentLimitWindows) { 757 if (!Triple(sys::getProcessTriple()).isOSWindows()) 758 GTEST_SKIP(); 759 // We use 32000 as a limit for command line length. Program name ('cl'), 760 // separating spaces and termination null character occupy 5 symbols. 761 std::string long_arg(32000 - 5, 'b'); 762 EXPECT_TRUE( 763 llvm::sys::commandLineFitsWithinSystemLimits("cl", long_arg.data())); 764 long_arg += 'b'; 765 EXPECT_FALSE( 766 llvm::sys::commandLineFitsWithinSystemLimits("cl", long_arg.data())); 767 } 768 769 TEST(CommandLineTest, ResponseFileWindows) { 770 if (!Triple(sys::getProcessTriple()).isOSWindows()) 771 GTEST_SKIP(); 772 773 StackOption<std::string, cl::list<std::string>> InputFilenames( 774 cl::Positional, cl::desc("<input files>"), cl::ZeroOrMore); 775 StackOption<bool> TopLevelOpt("top-level", cl::init(false)); 776 777 // Create response file. 778 TempFile ResponseFile("resp-", ".txt", 779 "-top-level\npath\\dir\\file1\npath/dir/file2", 780 /*Unique*/ true); 781 782 llvm::SmallString<128> RspOpt; 783 RspOpt.append(1, '@'); 784 RspOpt.append(ResponseFile.path()); 785 const char *args[] = {"prog", RspOpt.c_str()}; 786 EXPECT_FALSE(TopLevelOpt); 787 EXPECT_TRUE( 788 cl::ParseCommandLineOptions(2, args, StringRef(), &llvm::nulls())); 789 EXPECT_TRUE(TopLevelOpt); 790 EXPECT_EQ(InputFilenames[0], "path\\dir\\file1"); 791 EXPECT_EQ(InputFilenames[1], "path/dir/file2"); 792 } 793 794 TEST(CommandLineTest, ResponseFiles) { 795 vfs::InMemoryFileSystem FS; 796 #ifdef _WIN32 797 const char *TestRoot = "C:\\"; 798 #else 799 const char *TestRoot = "/"; 800 #endif 801 FS.setCurrentWorkingDirectory(TestRoot); 802 803 // Create included response file of first level. 804 llvm::StringRef IncludedFileName = "resp1"; 805 FS.addFile(IncludedFileName, 0, 806 llvm::MemoryBuffer::getMemBuffer("-option_1 -option_2\n" 807 "@incdir/resp2\n" 808 "-option_3=abcd\n" 809 "@incdir/resp3\n" 810 "-option_4=efjk\n")); 811 812 // Directory for included file. 813 llvm::StringRef IncDir = "incdir"; 814 815 // Create included response file of second level. 816 llvm::SmallString<128> IncludedFileName2; 817 llvm::sys::path::append(IncludedFileName2, IncDir, "resp2"); 818 FS.addFile(IncludedFileName2, 0, 819 MemoryBuffer::getMemBuffer("-option_21 -option_22\n" 820 "-option_23=abcd\n")); 821 822 // Create second included response file of second level. 823 llvm::SmallString<128> IncludedFileName3; 824 llvm::sys::path::append(IncludedFileName3, IncDir, "resp3"); 825 FS.addFile(IncludedFileName3, 0, 826 MemoryBuffer::getMemBuffer("-option_31 -option_32\n" 827 "-option_33=abcd\n")); 828 829 // Prepare 'file' with reference to response file. 830 SmallString<128> IncRef; 831 IncRef.append(1, '@'); 832 IncRef.append(IncludedFileName); 833 llvm::SmallVector<const char *, 4> Argv = {"test/test", "-flag_1", 834 IncRef.c_str(), "-flag_2"}; 835 836 // Expand response files. 837 llvm::BumpPtrAllocator A; 838 llvm::StringSaver Saver(A); 839 ASSERT_TRUE(llvm::cl::ExpandResponseFiles( 840 Saver, llvm::cl::TokenizeGNUCommandLine, Argv, false, true, false, 841 /*CurrentDir=*/StringRef(TestRoot), FS)); 842 EXPECT_THAT(Argv, testing::Pointwise( 843 StringEquality(), 844 {"test/test", "-flag_1", "-option_1", "-option_2", 845 "-option_21", "-option_22", "-option_23=abcd", 846 "-option_3=abcd", "-option_31", "-option_32", 847 "-option_33=abcd", "-option_4=efjk", "-flag_2"})); 848 } 849 850 TEST(CommandLineTest, RecursiveResponseFiles) { 851 vfs::InMemoryFileSystem FS; 852 #ifdef _WIN32 853 const char *TestRoot = "C:\\"; 854 #else 855 const char *TestRoot = "/"; 856 #endif 857 FS.setCurrentWorkingDirectory(TestRoot); 858 859 StringRef SelfFilePath = "self.rsp"; 860 std::string SelfFileRef = ("@" + SelfFilePath).str(); 861 862 StringRef NestedFilePath = "nested.rsp"; 863 std::string NestedFileRef = ("@" + NestedFilePath).str(); 864 865 StringRef FlagFilePath = "flag.rsp"; 866 std::string FlagFileRef = ("@" + FlagFilePath).str(); 867 868 std::string SelfFileContents; 869 raw_string_ostream SelfFile(SelfFileContents); 870 SelfFile << "-option_1\n"; 871 SelfFile << FlagFileRef << "\n"; 872 SelfFile << NestedFileRef << "\n"; 873 SelfFile << SelfFileRef << "\n"; 874 FS.addFile(SelfFilePath, 0, MemoryBuffer::getMemBuffer(SelfFile.str())); 875 876 std::string NestedFileContents; 877 raw_string_ostream NestedFile(NestedFileContents); 878 NestedFile << "-option_2\n"; 879 NestedFile << FlagFileRef << "\n"; 880 NestedFile << SelfFileRef << "\n"; 881 NestedFile << NestedFileRef << "\n"; 882 FS.addFile(NestedFilePath, 0, MemoryBuffer::getMemBuffer(NestedFile.str())); 883 884 std::string FlagFileContents; 885 raw_string_ostream FlagFile(FlagFileContents); 886 FlagFile << "-option_x\n"; 887 FS.addFile(FlagFilePath, 0, MemoryBuffer::getMemBuffer(FlagFile.str())); 888 889 // Ensure: 890 // Recursive expansion terminates 891 // Recursive files never expand 892 // Non-recursive repeats are allowed 893 SmallVector<const char *, 4> Argv = {"test/test", SelfFileRef.c_str(), 894 "-option_3"}; 895 BumpPtrAllocator A; 896 StringSaver Saver(A); 897 #ifdef _WIN32 898 cl::TokenizerCallback Tokenizer = cl::TokenizeWindowsCommandLine; 899 #else 900 cl::TokenizerCallback Tokenizer = cl::TokenizeGNUCommandLine; 901 #endif 902 ASSERT_FALSE( 903 cl::ExpandResponseFiles(Saver, Tokenizer, Argv, false, false, false, 904 /*CurrentDir=*/llvm::StringRef(TestRoot), FS)); 905 906 EXPECT_THAT(Argv, 907 testing::Pointwise(StringEquality(), 908 {"test/test", "-option_1", "-option_x", 909 "-option_2", "-option_x", SelfFileRef.c_str(), 910 NestedFileRef.c_str(), SelfFileRef.c_str(), 911 "-option_3"})); 912 } 913 914 TEST(CommandLineTest, ResponseFilesAtArguments) { 915 vfs::InMemoryFileSystem FS; 916 #ifdef _WIN32 917 const char *TestRoot = "C:\\"; 918 #else 919 const char *TestRoot = "/"; 920 #endif 921 FS.setCurrentWorkingDirectory(TestRoot); 922 923 StringRef ResponseFilePath = "test.rsp"; 924 925 std::string ResponseFileContents; 926 raw_string_ostream ResponseFile(ResponseFileContents); 927 ResponseFile << "-foo" << "\n"; 928 ResponseFile << "-bar" << "\n"; 929 FS.addFile(ResponseFilePath, 0, 930 MemoryBuffer::getMemBuffer(ResponseFile.str())); 931 932 // Ensure we expand rsp files after lots of non-rsp arguments starting with @. 933 constexpr size_t NON_RSP_AT_ARGS = 64; 934 SmallVector<const char *, 4> Argv = {"test/test"}; 935 Argv.append(NON_RSP_AT_ARGS, "@non_rsp_at_arg"); 936 std::string ResponseFileRef = ("@" + ResponseFilePath).str(); 937 Argv.push_back(ResponseFileRef.c_str()); 938 939 BumpPtrAllocator A; 940 StringSaver Saver(A); 941 ASSERT_FALSE(cl::ExpandResponseFiles(Saver, cl::TokenizeGNUCommandLine, Argv, 942 false, false, false, 943 /*CurrentDir=*/StringRef(TestRoot), FS)); 944 945 // ASSERT instead of EXPECT to prevent potential out-of-bounds access. 946 ASSERT_EQ(Argv.size(), 1 + NON_RSP_AT_ARGS + 2); 947 size_t i = 0; 948 EXPECT_STREQ(Argv[i++], "test/test"); 949 for (; i < 1 + NON_RSP_AT_ARGS; ++i) 950 EXPECT_STREQ(Argv[i], "@non_rsp_at_arg"); 951 EXPECT_STREQ(Argv[i++], "-foo"); 952 EXPECT_STREQ(Argv[i++], "-bar"); 953 } 954 955 TEST(CommandLineTest, ResponseFileRelativePath) { 956 vfs::InMemoryFileSystem FS; 957 #ifdef _WIN32 958 const char *TestRoot = "C:\\"; 959 #else 960 const char *TestRoot = "//net"; 961 #endif 962 FS.setCurrentWorkingDirectory(TestRoot); 963 964 StringRef OuterFile = "dir/outer.rsp"; 965 StringRef OuterFileContents = "@inner.rsp"; 966 FS.addFile(OuterFile, 0, MemoryBuffer::getMemBuffer(OuterFileContents)); 967 968 StringRef InnerFile = "dir/inner.rsp"; 969 StringRef InnerFileContents = "-flag"; 970 FS.addFile(InnerFile, 0, MemoryBuffer::getMemBuffer(InnerFileContents)); 971 972 SmallVector<const char *, 2> Argv = {"test/test", "@dir/outer.rsp"}; 973 974 BumpPtrAllocator A; 975 StringSaver Saver(A); 976 ASSERT_TRUE(cl::ExpandResponseFiles(Saver, cl::TokenizeGNUCommandLine, Argv, 977 false, true, false, 978 /*CurrentDir=*/StringRef(TestRoot), FS)); 979 EXPECT_THAT(Argv, 980 testing::Pointwise(StringEquality(), {"test/test", "-flag"})); 981 } 982 983 TEST(CommandLineTest, ResponseFileEOLs) { 984 vfs::InMemoryFileSystem FS; 985 #ifdef _WIN32 986 const char *TestRoot = "C:\\"; 987 #else 988 const char *TestRoot = "//net"; 989 #endif 990 FS.setCurrentWorkingDirectory(TestRoot); 991 FS.addFile("eols.rsp", 0, 992 MemoryBuffer::getMemBuffer("-Xclang -Wno-whatever\n input.cpp")); 993 SmallVector<const char *, 2> Argv = {"clang", "@eols.rsp"}; 994 BumpPtrAllocator A; 995 StringSaver Saver(A); 996 ASSERT_TRUE(cl::ExpandResponseFiles(Saver, cl::TokenizeWindowsCommandLine, 997 Argv, true, true, false, 998 /*CurrentDir=*/StringRef(TestRoot), FS)); 999 const char *Expected[] = {"clang", "-Xclang", "-Wno-whatever", nullptr, 1000 "input.cpp"}; 1001 ASSERT_EQ(array_lengthof(Expected), Argv.size()); 1002 for (size_t I = 0, E = array_lengthof(Expected); I < E; ++I) { 1003 if (Expected[I] == nullptr) { 1004 ASSERT_EQ(Argv[I], nullptr); 1005 } else { 1006 ASSERT_STREQ(Expected[I], Argv[I]); 1007 } 1008 } 1009 } 1010 1011 TEST(CommandLineTest, SetDefautValue) { 1012 cl::ResetCommandLineParser(); 1013 1014 StackOption<std::string> Opt1("opt1", cl::init("true")); 1015 StackOption<bool> Opt2("opt2", cl::init(true)); 1016 cl::alias Alias("alias", llvm::cl::aliasopt(Opt2)); 1017 StackOption<int> Opt3("opt3", cl::init(3)); 1018 1019 const char *args[] = {"prog", "-opt1=false", "-opt2", "-opt3"}; 1020 1021 EXPECT_TRUE( 1022 cl::ParseCommandLineOptions(2, args, StringRef(), &llvm::nulls())); 1023 1024 EXPECT_EQ(Opt1, "false"); 1025 EXPECT_TRUE(Opt2); 1026 EXPECT_EQ(Opt3, 3); 1027 1028 Opt2 = false; 1029 Opt3 = 1; 1030 1031 cl::ResetAllOptionOccurrences(); 1032 1033 for (auto &OM : cl::getRegisteredOptions(*cl::TopLevelSubCommand)) { 1034 cl::Option *O = OM.second; 1035 if (O->ArgStr == "opt2") { 1036 continue; 1037 } 1038 O->setDefault(); 1039 } 1040 1041 EXPECT_EQ(Opt1, "true"); 1042 EXPECT_TRUE(Opt2); 1043 EXPECT_EQ(Opt3, 3); 1044 Alias.removeArgument(); 1045 } 1046 1047 TEST(CommandLineTest, ReadConfigFile) { 1048 llvm::SmallVector<const char *, 1> Argv; 1049 1050 TempDir TestDir("unittest", /*Unique*/ true); 1051 TempDir TestSubDir(TestDir.path("subdir"), /*Unique*/ false); 1052 1053 llvm::SmallString<128> TestCfg = TestDir.path("foo"); 1054 TempFile ConfigFile(TestCfg, "", 1055 "# Comment\n" 1056 "-option_1\n" 1057 "-option_2=<CFGDIR>/dir1\n" 1058 "-option_3=<CFGDIR>\n" 1059 "-option_4 <CFGDIR>\n" 1060 "-option_5=<CFG\\\n" 1061 "DIR>\n" 1062 "-option_6=<CFGDIR>/dir1,<CFGDIR>/dir2\n" 1063 "@subconfig\n" 1064 "-option_11=abcd\n" 1065 "-option_12=\\\n" 1066 "cdef\n"); 1067 1068 llvm::SmallString<128> TestCfg2 = TestDir.path("subconfig"); 1069 TempFile ConfigFile2(TestCfg2, "", 1070 "-option_7\n" 1071 "-option_8=<CFGDIR>/dir2\n" 1072 "@subdir/subfoo\n" 1073 "\n" 1074 " # comment\n"); 1075 1076 llvm::SmallString<128> TestCfg3 = TestSubDir.path("subfoo"); 1077 TempFile ConfigFile3(TestCfg3, "", 1078 "-option_9=<CFGDIR>/dir3\n" 1079 "@<CFGDIR>/subfoo2\n"); 1080 1081 llvm::SmallString<128> TestCfg4 = TestSubDir.path("subfoo2"); 1082 TempFile ConfigFile4(TestCfg4, "", "-option_10\n"); 1083 1084 // Make sure the current directory is not the directory where config files 1085 // resides. In this case the code that expands response files will not find 1086 // 'subconfig' unless it resolves nested inclusions relative to the including 1087 // file. 1088 llvm::SmallString<128> CurrDir; 1089 std::error_code EC = llvm::sys::fs::current_path(CurrDir); 1090 EXPECT_TRUE(!EC); 1091 EXPECT_NE(CurrDir.str(), TestDir.path()); 1092 1093 llvm::BumpPtrAllocator A; 1094 llvm::StringSaver Saver(A); 1095 bool Result = llvm::cl::readConfigFile(ConfigFile.path(), Saver, Argv); 1096 1097 EXPECT_TRUE(Result); 1098 EXPECT_EQ(Argv.size(), 13U); 1099 EXPECT_STREQ(Argv[0], "-option_1"); 1100 EXPECT_STREQ(Argv[1], 1101 ("-option_2=" + TestDir.path() + "/dir1").str().c_str()); 1102 EXPECT_STREQ(Argv[2], ("-option_3=" + TestDir.path()).str().c_str()); 1103 EXPECT_STREQ(Argv[3], "-option_4"); 1104 EXPECT_STREQ(Argv[4], TestDir.path().str().c_str()); 1105 EXPECT_STREQ(Argv[5], ("-option_5=" + TestDir.path()).str().c_str()); 1106 EXPECT_STREQ(Argv[6], ("-option_6=" + TestDir.path() + "/dir1," + 1107 TestDir.path() + "/dir2") 1108 .str() 1109 .c_str()); 1110 EXPECT_STREQ(Argv[7], "-option_7"); 1111 EXPECT_STREQ(Argv[8], 1112 ("-option_8=" + TestDir.path() + "/dir2").str().c_str()); 1113 EXPECT_STREQ(Argv[9], 1114 ("-option_9=" + TestSubDir.path() + "/dir3").str().c_str()); 1115 EXPECT_STREQ(Argv[10], "-option_10"); 1116 EXPECT_STREQ(Argv[11], "-option_11=abcd"); 1117 EXPECT_STREQ(Argv[12], "-option_12=cdef"); 1118 } 1119 1120 TEST(CommandLineTest, PositionalEatArgsError) { 1121 cl::ResetCommandLineParser(); 1122 1123 StackOption<std::string, cl::list<std::string>> PosEatArgs( 1124 "positional-eat-args", cl::Positional, cl::desc("<arguments>..."), 1125 cl::ZeroOrMore, cl::PositionalEatsArgs); 1126 StackOption<std::string, cl::list<std::string>> PosEatArgs2( 1127 "positional-eat-args2", cl::Positional, cl::desc("Some strings"), 1128 cl::ZeroOrMore, cl::PositionalEatsArgs); 1129 1130 const char *args[] = {"prog", "-positional-eat-args=XXXX"}; 1131 const char *args2[] = {"prog", "-positional-eat-args=XXXX", "-foo"}; 1132 const char *args3[] = {"prog", "-positional-eat-args", "-foo"}; 1133 const char *args4[] = {"prog", "-positional-eat-args", 1134 "-foo", "-positional-eat-args2", 1135 "-bar", "foo"}; 1136 1137 std::string Errs; 1138 raw_string_ostream OS(Errs); 1139 EXPECT_FALSE(cl::ParseCommandLineOptions(2, args, StringRef(), &OS)); OS.flush(); 1140 EXPECT_FALSE(Errs.empty()); Errs.clear(); 1141 EXPECT_FALSE(cl::ParseCommandLineOptions(3, args2, StringRef(), &OS)); OS.flush(); 1142 EXPECT_FALSE(Errs.empty()); Errs.clear(); 1143 EXPECT_TRUE(cl::ParseCommandLineOptions(3, args3, StringRef(), &OS)); OS.flush(); 1144 EXPECT_TRUE(Errs.empty()); Errs.clear(); 1145 1146 cl::ResetAllOptionOccurrences(); 1147 EXPECT_TRUE(cl::ParseCommandLineOptions(6, args4, StringRef(), &OS)); OS.flush(); 1148 EXPECT_EQ(PosEatArgs.size(), 1u); 1149 EXPECT_EQ(PosEatArgs2.size(), 2u); 1150 EXPECT_TRUE(Errs.empty()); 1151 } 1152 1153 #ifdef _WIN32 1154 void checkSeparators(StringRef Path) { 1155 char UndesiredSeparator = sys::path::get_separator()[0] == '/' ? '\\' : '/'; 1156 ASSERT_EQ(Path.find(UndesiredSeparator), StringRef::npos); 1157 } 1158 1159 TEST(CommandLineTest, GetCommandLineArguments) { 1160 int argc = __argc; 1161 char **argv = __argv; 1162 1163 // GetCommandLineArguments is called in InitLLVM. 1164 llvm::InitLLVM X(argc, argv); 1165 1166 EXPECT_EQ(llvm::sys::path::is_absolute(argv[0]), 1167 llvm::sys::path::is_absolute(__argv[0])); 1168 checkSeparators(argv[0]); 1169 1170 EXPECT_TRUE( 1171 llvm::sys::path::filename(argv[0]).equals_insensitive("supporttests.exe")) 1172 << "Filename of test executable is " 1173 << llvm::sys::path::filename(argv[0]); 1174 } 1175 #endif 1176 1177 class OutputRedirector { 1178 public: 1179 OutputRedirector(int RedirectFD) 1180 : RedirectFD(RedirectFD), OldFD(dup(RedirectFD)) { 1181 if (OldFD == -1 || 1182 sys::fs::createTemporaryFile("unittest-redirect", "", NewFD, 1183 FilePath) || 1184 dup2(NewFD, RedirectFD) == -1) 1185 Valid = false; 1186 } 1187 1188 ~OutputRedirector() { 1189 dup2(OldFD, RedirectFD); 1190 close(OldFD); 1191 close(NewFD); 1192 } 1193 1194 SmallVector<char, 128> FilePath; 1195 bool Valid = true; 1196 1197 private: 1198 int RedirectFD; 1199 int OldFD; 1200 int NewFD; 1201 }; 1202 1203 struct AutoDeleteFile { 1204 SmallVector<char, 128> FilePath; 1205 ~AutoDeleteFile() { 1206 if (!FilePath.empty()) 1207 sys::fs::remove(std::string(FilePath.data(), FilePath.size())); 1208 } 1209 }; 1210 1211 class PrintOptionInfoTest : public ::testing::Test { 1212 public: 1213 // Return std::string because the output of a failing EXPECT check is 1214 // unreadable for StringRef. It also avoids any lifetime issues. 1215 template <typename... Ts> std::string runTest(Ts... OptionAttributes) { 1216 outs().flush(); // flush any output from previous tests 1217 AutoDeleteFile File; 1218 { 1219 OutputRedirector Stdout(fileno(stdout)); 1220 if (!Stdout.Valid) 1221 return ""; 1222 File.FilePath = Stdout.FilePath; 1223 1224 StackOption<OptionValue> TestOption(Opt, cl::desc(HelpText), 1225 OptionAttributes...); 1226 printOptionInfo(TestOption, 26); 1227 outs().flush(); 1228 } 1229 auto Buffer = MemoryBuffer::getFile(File.FilePath); 1230 if (!Buffer) 1231 return ""; 1232 return Buffer->get()->getBuffer().str(); 1233 } 1234 1235 enum class OptionValue { Val }; 1236 const StringRef Opt = "some-option"; 1237 const StringRef HelpText = "some help"; 1238 1239 private: 1240 // This is a workaround for cl::Option sub-classes having their 1241 // printOptionInfo functions private. 1242 void printOptionInfo(const cl::Option &O, size_t Width) { 1243 O.printOptionInfo(Width); 1244 } 1245 }; 1246 1247 TEST_F(PrintOptionInfoTest, PrintOptionInfoValueOptionalWithoutSentinel) { 1248 std::string Output = 1249 runTest(cl::ValueOptional, 1250 cl::values(clEnumValN(OptionValue::Val, "v1", "desc1"))); 1251 1252 // clang-format off 1253 EXPECT_EQ(Output, (" --" + Opt + "=<value> - " + HelpText + "\n" 1254 " =v1 - desc1\n") 1255 .str()); 1256 // clang-format on 1257 } 1258 1259 TEST_F(PrintOptionInfoTest, PrintOptionInfoValueOptionalWithSentinel) { 1260 std::string Output = runTest( 1261 cl::ValueOptional, cl::values(clEnumValN(OptionValue::Val, "v1", "desc1"), 1262 clEnumValN(OptionValue::Val, "", ""))); 1263 1264 // clang-format off 1265 EXPECT_EQ(Output, 1266 (" --" + Opt + " - " + HelpText + "\n" 1267 " --" + Opt + "=<value> - " + HelpText + "\n" 1268 " =v1 - desc1\n") 1269 .str()); 1270 // clang-format on 1271 } 1272 1273 TEST_F(PrintOptionInfoTest, PrintOptionInfoValueOptionalWithSentinelWithHelp) { 1274 std::string Output = runTest( 1275 cl::ValueOptional, cl::values(clEnumValN(OptionValue::Val, "v1", "desc1"), 1276 clEnumValN(OptionValue::Val, "", "desc2"))); 1277 1278 // clang-format off 1279 EXPECT_EQ(Output, (" --" + Opt + " - " + HelpText + "\n" 1280 " --" + Opt + "=<value> - " + HelpText + "\n" 1281 " =v1 - desc1\n" 1282 " =<empty> - desc2\n") 1283 .str()); 1284 // clang-format on 1285 } 1286 1287 TEST_F(PrintOptionInfoTest, PrintOptionInfoValueRequiredWithEmptyValueName) { 1288 std::string Output = runTest( 1289 cl::ValueRequired, cl::values(clEnumValN(OptionValue::Val, "v1", "desc1"), 1290 clEnumValN(OptionValue::Val, "", ""))); 1291 1292 // clang-format off 1293 EXPECT_EQ(Output, (" --" + Opt + "=<value> - " + HelpText + "\n" 1294 " =v1 - desc1\n" 1295 " =<empty>\n") 1296 .str()); 1297 // clang-format on 1298 } 1299 1300 TEST_F(PrintOptionInfoTest, PrintOptionInfoEmptyValueDescription) { 1301 std::string Output = runTest( 1302 cl::ValueRequired, cl::values(clEnumValN(OptionValue::Val, "v1", ""))); 1303 1304 // clang-format off 1305 EXPECT_EQ(Output, 1306 (" --" + Opt + "=<value> - " + HelpText + "\n" 1307 " =v1\n").str()); 1308 // clang-format on 1309 } 1310 1311 TEST_F(PrintOptionInfoTest, PrintOptionInfoMultilineValueDescription) { 1312 std::string Output = 1313 runTest(cl::ValueRequired, 1314 cl::values(clEnumValN(OptionValue::Val, "v1", 1315 "This is the first enum value\n" 1316 "which has a really long description\n" 1317 "thus it is multi-line."), 1318 clEnumValN(OptionValue::Val, "", 1319 "This is an unnamed enum value option\n" 1320 "Should be indented as well"))); 1321 1322 // clang-format off 1323 EXPECT_EQ(Output, 1324 (" --" + Opt + "=<value> - " + HelpText + "\n" 1325 " =v1 - This is the first enum value\n" 1326 " which has a really long description\n" 1327 " thus it is multi-line.\n" 1328 " =<empty> - This is an unnamed enum value option\n" 1329 " Should be indented as well\n").str()); 1330 // clang-format on 1331 } 1332 1333 class GetOptionWidthTest : public ::testing::Test { 1334 public: 1335 enum class OptionValue { Val }; 1336 1337 template <typename... Ts> 1338 size_t runTest(StringRef ArgName, Ts... OptionAttributes) { 1339 StackOption<OptionValue> TestOption(ArgName, cl::desc("some help"), 1340 OptionAttributes...); 1341 return getOptionWidth(TestOption); 1342 } 1343 1344 private: 1345 // This is a workaround for cl::Option sub-classes having their 1346 // printOptionInfo 1347 // functions private. 1348 size_t getOptionWidth(const cl::Option &O) { return O.getOptionWidth(); } 1349 }; 1350 1351 TEST_F(GetOptionWidthTest, GetOptionWidthArgNameLonger) { 1352 StringRef ArgName("a-long-argument-name"); 1353 size_t ExpectedStrSize = (" --" + ArgName + "=<value> - ").str().size(); 1354 EXPECT_EQ( 1355 runTest(ArgName, cl::values(clEnumValN(OptionValue::Val, "v", "help"))), 1356 ExpectedStrSize); 1357 } 1358 1359 TEST_F(GetOptionWidthTest, GetOptionWidthFirstOptionNameLonger) { 1360 StringRef OptName("a-long-option-name"); 1361 size_t ExpectedStrSize = (" =" + OptName + " - ").str().size(); 1362 EXPECT_EQ( 1363 runTest("a", cl::values(clEnumValN(OptionValue::Val, OptName, "help"), 1364 clEnumValN(OptionValue::Val, "b", "help"))), 1365 ExpectedStrSize); 1366 } 1367 1368 TEST_F(GetOptionWidthTest, GetOptionWidthSecondOptionNameLonger) { 1369 StringRef OptName("a-long-option-name"); 1370 size_t ExpectedStrSize = (" =" + OptName + " - ").str().size(); 1371 EXPECT_EQ( 1372 runTest("a", cl::values(clEnumValN(OptionValue::Val, "b", "help"), 1373 clEnumValN(OptionValue::Val, OptName, "help"))), 1374 ExpectedStrSize); 1375 } 1376 1377 TEST_F(GetOptionWidthTest, GetOptionWidthEmptyOptionNameLonger) { 1378 size_t ExpectedStrSize = StringRef(" =<empty> - ").size(); 1379 // The length of a=<value> (including indentation) is actually the same as the 1380 // =<empty> string, so it is impossible to distinguish via testing the case 1381 // where the empty string is picked from where the option name is picked. 1382 EXPECT_EQ(runTest("a", cl::values(clEnumValN(OptionValue::Val, "b", "help"), 1383 clEnumValN(OptionValue::Val, "", "help"))), 1384 ExpectedStrSize); 1385 } 1386 1387 TEST_F(GetOptionWidthTest, 1388 GetOptionWidthValueOptionalEmptyOptionWithNoDescription) { 1389 StringRef ArgName("a"); 1390 // The length of a=<value> (including indentation) is actually the same as the 1391 // =<empty> string, so it is impossible to distinguish via testing the case 1392 // where the empty string is ignored from where it is not ignored. 1393 // The dash will not actually be printed, but the space it would take up is 1394 // included to ensure a consistent column width. 1395 size_t ExpectedStrSize = (" -" + ArgName + "=<value> - ").str().size(); 1396 EXPECT_EQ(runTest(ArgName, cl::ValueOptional, 1397 cl::values(clEnumValN(OptionValue::Val, "value", "help"), 1398 clEnumValN(OptionValue::Val, "", ""))), 1399 ExpectedStrSize); 1400 } 1401 1402 TEST_F(GetOptionWidthTest, 1403 GetOptionWidthValueRequiredEmptyOptionWithNoDescription) { 1404 // The length of a=<value> (including indentation) is actually the same as the 1405 // =<empty> string, so it is impossible to distinguish via testing the case 1406 // where the empty string is picked from where the option name is picked 1407 size_t ExpectedStrSize = StringRef(" =<empty> - ").size(); 1408 EXPECT_EQ(runTest("a", cl::ValueRequired, 1409 cl::values(clEnumValN(OptionValue::Val, "value", "help"), 1410 clEnumValN(OptionValue::Val, "", ""))), 1411 ExpectedStrSize); 1412 } 1413 1414 TEST(CommandLineTest, PrefixOptions) { 1415 cl::ResetCommandLineParser(); 1416 1417 StackOption<std::string, cl::list<std::string>> IncludeDirs( 1418 "I", cl::Prefix, cl::desc("Declare an include directory")); 1419 1420 // Test non-prefixed variant works with cl::Prefix options. 1421 EXPECT_TRUE(IncludeDirs.empty()); 1422 const char *args[] = {"prog", "-I=/usr/include"}; 1423 EXPECT_TRUE( 1424 cl::ParseCommandLineOptions(2, args, StringRef(), &llvm::nulls())); 1425 EXPECT_EQ(IncludeDirs.size(), 1u); 1426 EXPECT_EQ(IncludeDirs.front().compare("/usr/include"), 0); 1427 1428 IncludeDirs.erase(IncludeDirs.begin()); 1429 cl::ResetAllOptionOccurrences(); 1430 1431 // Test non-prefixed variant works with cl::Prefix options when value is 1432 // passed in following argument. 1433 EXPECT_TRUE(IncludeDirs.empty()); 1434 const char *args2[] = {"prog", "-I", "/usr/include"}; 1435 EXPECT_TRUE( 1436 cl::ParseCommandLineOptions(3, args2, StringRef(), &llvm::nulls())); 1437 EXPECT_EQ(IncludeDirs.size(), 1u); 1438 EXPECT_EQ(IncludeDirs.front().compare("/usr/include"), 0); 1439 1440 IncludeDirs.erase(IncludeDirs.begin()); 1441 cl::ResetAllOptionOccurrences(); 1442 1443 // Test prefixed variant works with cl::Prefix options. 1444 EXPECT_TRUE(IncludeDirs.empty()); 1445 const char *args3[] = {"prog", "-I/usr/include"}; 1446 EXPECT_TRUE( 1447 cl::ParseCommandLineOptions(2, args3, StringRef(), &llvm::nulls())); 1448 EXPECT_EQ(IncludeDirs.size(), 1u); 1449 EXPECT_EQ(IncludeDirs.front().compare("/usr/include"), 0); 1450 1451 StackOption<std::string, cl::list<std::string>> MacroDefs( 1452 "D", cl::AlwaysPrefix, cl::desc("Define a macro"), 1453 cl::value_desc("MACRO[=VALUE]")); 1454 1455 cl::ResetAllOptionOccurrences(); 1456 1457 // Test non-prefixed variant does not work with cl::AlwaysPrefix options: 1458 // equal sign is part of the value. 1459 EXPECT_TRUE(MacroDefs.empty()); 1460 const char *args4[] = {"prog", "-D=HAVE_FOO"}; 1461 EXPECT_TRUE( 1462 cl::ParseCommandLineOptions(2, args4, StringRef(), &llvm::nulls())); 1463 EXPECT_EQ(MacroDefs.size(), 1u); 1464 EXPECT_EQ(MacroDefs.front().compare("=HAVE_FOO"), 0); 1465 1466 MacroDefs.erase(MacroDefs.begin()); 1467 cl::ResetAllOptionOccurrences(); 1468 1469 // Test non-prefixed variant does not allow value to be passed in following 1470 // argument with cl::AlwaysPrefix options. 1471 EXPECT_TRUE(MacroDefs.empty()); 1472 const char *args5[] = {"prog", "-D", "HAVE_FOO"}; 1473 EXPECT_FALSE( 1474 cl::ParseCommandLineOptions(3, args5, StringRef(), &llvm::nulls())); 1475 EXPECT_TRUE(MacroDefs.empty()); 1476 1477 cl::ResetAllOptionOccurrences(); 1478 1479 // Test prefixed variant works with cl::AlwaysPrefix options. 1480 EXPECT_TRUE(MacroDefs.empty()); 1481 const char *args6[] = {"prog", "-DHAVE_FOO"}; 1482 EXPECT_TRUE( 1483 cl::ParseCommandLineOptions(2, args6, StringRef(), &llvm::nulls())); 1484 EXPECT_EQ(MacroDefs.size(), 1u); 1485 EXPECT_EQ(MacroDefs.front().compare("HAVE_FOO"), 0); 1486 } 1487 1488 TEST(CommandLineTest, GroupingWithValue) { 1489 cl::ResetCommandLineParser(); 1490 1491 StackOption<bool> OptF("f", cl::Grouping, cl::desc("Some flag")); 1492 StackOption<bool> OptB("b", cl::Grouping, cl::desc("Another flag")); 1493 StackOption<bool> OptD("d", cl::Grouping, cl::ValueDisallowed, 1494 cl::desc("ValueDisallowed option")); 1495 StackOption<std::string> OptV("v", cl::Grouping, 1496 cl::desc("ValueRequired option")); 1497 StackOption<std::string> OptO("o", cl::Grouping, cl::ValueOptional, 1498 cl::desc("ValueOptional option")); 1499 1500 // Should be possible to use an option which requires a value 1501 // at the end of a group. 1502 const char *args1[] = {"prog", "-fv", "val1"}; 1503 EXPECT_TRUE( 1504 cl::ParseCommandLineOptions(3, args1, StringRef(), &llvm::nulls())); 1505 EXPECT_TRUE(OptF); 1506 EXPECT_STREQ("val1", OptV.c_str()); 1507 OptV.clear(); 1508 cl::ResetAllOptionOccurrences(); 1509 1510 // Should not crash if it is accidentally used elsewhere in the group. 1511 const char *args2[] = {"prog", "-vf", "val2"}; 1512 EXPECT_FALSE( 1513 cl::ParseCommandLineOptions(3, args2, StringRef(), &llvm::nulls())); 1514 OptV.clear(); 1515 cl::ResetAllOptionOccurrences(); 1516 1517 // Should allow the "opt=value" form at the end of the group 1518 const char *args3[] = {"prog", "-fv=val3"}; 1519 EXPECT_TRUE( 1520 cl::ParseCommandLineOptions(2, args3, StringRef(), &llvm::nulls())); 1521 EXPECT_TRUE(OptF); 1522 EXPECT_STREQ("val3", OptV.c_str()); 1523 OptV.clear(); 1524 cl::ResetAllOptionOccurrences(); 1525 1526 // Should allow assigning a value for a ValueOptional option 1527 // at the end of the group 1528 const char *args4[] = {"prog", "-fo=val4"}; 1529 EXPECT_TRUE( 1530 cl::ParseCommandLineOptions(2, args4, StringRef(), &llvm::nulls())); 1531 EXPECT_TRUE(OptF); 1532 EXPECT_STREQ("val4", OptO.c_str()); 1533 OptO.clear(); 1534 cl::ResetAllOptionOccurrences(); 1535 1536 // Should assign an empty value if a ValueOptional option is used elsewhere 1537 // in the group. 1538 const char *args5[] = {"prog", "-fob"}; 1539 EXPECT_TRUE( 1540 cl::ParseCommandLineOptions(2, args5, StringRef(), &llvm::nulls())); 1541 EXPECT_TRUE(OptF); 1542 EXPECT_EQ(1, OptO.getNumOccurrences()); 1543 EXPECT_EQ(1, OptB.getNumOccurrences()); 1544 EXPECT_TRUE(OptO.empty()); 1545 cl::ResetAllOptionOccurrences(); 1546 1547 // Should not allow an assignment for a ValueDisallowed option. 1548 const char *args6[] = {"prog", "-fd=false"}; 1549 EXPECT_FALSE( 1550 cl::ParseCommandLineOptions(2, args6, StringRef(), &llvm::nulls())); 1551 } 1552 1553 TEST(CommandLineTest, GroupingAndPrefix) { 1554 cl::ResetCommandLineParser(); 1555 1556 StackOption<bool> OptF("f", cl::Grouping, cl::desc("Some flag")); 1557 StackOption<bool> OptB("b", cl::Grouping, cl::desc("Another flag")); 1558 StackOption<std::string> OptP("p", cl::Prefix, cl::Grouping, 1559 cl::desc("Prefix and Grouping")); 1560 StackOption<std::string> OptA("a", cl::AlwaysPrefix, cl::Grouping, 1561 cl::desc("AlwaysPrefix and Grouping")); 1562 1563 // Should be possible to use a cl::Prefix option without grouping. 1564 const char *args1[] = {"prog", "-pval1"}; 1565 EXPECT_TRUE( 1566 cl::ParseCommandLineOptions(2, args1, StringRef(), &llvm::nulls())); 1567 EXPECT_STREQ("val1", OptP.c_str()); 1568 OptP.clear(); 1569 cl::ResetAllOptionOccurrences(); 1570 1571 // Should be possible to pass a value in a separate argument. 1572 const char *args2[] = {"prog", "-p", "val2"}; 1573 EXPECT_TRUE( 1574 cl::ParseCommandLineOptions(3, args2, StringRef(), &llvm::nulls())); 1575 EXPECT_STREQ("val2", OptP.c_str()); 1576 OptP.clear(); 1577 cl::ResetAllOptionOccurrences(); 1578 1579 // The "-opt=value" form should work, too. 1580 const char *args3[] = {"prog", "-p=val3"}; 1581 EXPECT_TRUE( 1582 cl::ParseCommandLineOptions(2, args3, StringRef(), &llvm::nulls())); 1583 EXPECT_STREQ("val3", OptP.c_str()); 1584 OptP.clear(); 1585 cl::ResetAllOptionOccurrences(); 1586 1587 // All three previous cases should work the same way if an option with both 1588 // cl::Prefix and cl::Grouping modifiers is used at the end of a group. 1589 const char *args4[] = {"prog", "-fpval4"}; 1590 EXPECT_TRUE( 1591 cl::ParseCommandLineOptions(2, args4, StringRef(), &llvm::nulls())); 1592 EXPECT_TRUE(OptF); 1593 EXPECT_STREQ("val4", OptP.c_str()); 1594 OptP.clear(); 1595 cl::ResetAllOptionOccurrences(); 1596 1597 const char *args5[] = {"prog", "-fp", "val5"}; 1598 EXPECT_TRUE( 1599 cl::ParseCommandLineOptions(3, args5, StringRef(), &llvm::nulls())); 1600 EXPECT_TRUE(OptF); 1601 EXPECT_STREQ("val5", OptP.c_str()); 1602 OptP.clear(); 1603 cl::ResetAllOptionOccurrences(); 1604 1605 const char *args6[] = {"prog", "-fp=val6"}; 1606 EXPECT_TRUE( 1607 cl::ParseCommandLineOptions(2, args6, StringRef(), &llvm::nulls())); 1608 EXPECT_TRUE(OptF); 1609 EXPECT_STREQ("val6", OptP.c_str()); 1610 OptP.clear(); 1611 cl::ResetAllOptionOccurrences(); 1612 1613 // Should assign a value even if the part after a cl::Prefix option is equal 1614 // to the name of another option. 1615 const char *args7[] = {"prog", "-fpb"}; 1616 EXPECT_TRUE( 1617 cl::ParseCommandLineOptions(2, args7, StringRef(), &llvm::nulls())); 1618 EXPECT_TRUE(OptF); 1619 EXPECT_STREQ("b", OptP.c_str()); 1620 EXPECT_FALSE(OptB); 1621 OptP.clear(); 1622 cl::ResetAllOptionOccurrences(); 1623 1624 // Should be possible to use a cl::AlwaysPrefix option without grouping. 1625 const char *args8[] = {"prog", "-aval8"}; 1626 EXPECT_TRUE( 1627 cl::ParseCommandLineOptions(2, args8, StringRef(), &llvm::nulls())); 1628 EXPECT_STREQ("val8", OptA.c_str()); 1629 OptA.clear(); 1630 cl::ResetAllOptionOccurrences(); 1631 1632 // Should not be possible to pass a value in a separate argument. 1633 const char *args9[] = {"prog", "-a", "val9"}; 1634 EXPECT_FALSE( 1635 cl::ParseCommandLineOptions(3, args9, StringRef(), &llvm::nulls())); 1636 cl::ResetAllOptionOccurrences(); 1637 1638 // With the "-opt=value" form, the "=" symbol should be preserved. 1639 const char *args10[] = {"prog", "-a=val10"}; 1640 EXPECT_TRUE( 1641 cl::ParseCommandLineOptions(2, args10, StringRef(), &llvm::nulls())); 1642 EXPECT_STREQ("=val10", OptA.c_str()); 1643 OptA.clear(); 1644 cl::ResetAllOptionOccurrences(); 1645 1646 // All three previous cases should work the same way if an option with both 1647 // cl::AlwaysPrefix and cl::Grouping modifiers is used at the end of a group. 1648 const char *args11[] = {"prog", "-faval11"}; 1649 EXPECT_TRUE( 1650 cl::ParseCommandLineOptions(2, args11, StringRef(), &llvm::nulls())); 1651 EXPECT_TRUE(OptF); 1652 EXPECT_STREQ("val11", OptA.c_str()); 1653 OptA.clear(); 1654 cl::ResetAllOptionOccurrences(); 1655 1656 const char *args12[] = {"prog", "-fa", "val12"}; 1657 EXPECT_FALSE( 1658 cl::ParseCommandLineOptions(3, args12, StringRef(), &llvm::nulls())); 1659 cl::ResetAllOptionOccurrences(); 1660 1661 const char *args13[] = {"prog", "-fa=val13"}; 1662 EXPECT_TRUE( 1663 cl::ParseCommandLineOptions(2, args13, StringRef(), &llvm::nulls())); 1664 EXPECT_TRUE(OptF); 1665 EXPECT_STREQ("=val13", OptA.c_str()); 1666 OptA.clear(); 1667 cl::ResetAllOptionOccurrences(); 1668 1669 // Should assign a value even if the part after a cl::AlwaysPrefix option 1670 // is equal to the name of another option. 1671 const char *args14[] = {"prog", "-fab"}; 1672 EXPECT_TRUE( 1673 cl::ParseCommandLineOptions(2, args14, StringRef(), &llvm::nulls())); 1674 EXPECT_TRUE(OptF); 1675 EXPECT_STREQ("b", OptA.c_str()); 1676 EXPECT_FALSE(OptB); 1677 OptA.clear(); 1678 cl::ResetAllOptionOccurrences(); 1679 } 1680 1681 TEST(CommandLineTest, LongOptions) { 1682 cl::ResetCommandLineParser(); 1683 1684 StackOption<bool> OptA("a", cl::desc("Some flag")); 1685 StackOption<bool> OptBLong("long-flag", cl::desc("Some long flag")); 1686 StackOption<bool, cl::alias> OptB("b", cl::desc("Alias to --long-flag"), 1687 cl::aliasopt(OptBLong)); 1688 StackOption<std::string> OptAB("ab", cl::desc("Another long option")); 1689 1690 std::string Errs; 1691 raw_string_ostream OS(Errs); 1692 1693 const char *args1[] = {"prog", "-a", "-ab", "val1"}; 1694 const char *args2[] = {"prog", "-a", "--ab", "val1"}; 1695 const char *args3[] = {"prog", "-ab", "--ab", "val1"}; 1696 1697 // 1698 // The following tests treat `-` and `--` the same, and always match the 1699 // longest string. 1700 // 1701 1702 EXPECT_TRUE( 1703 cl::ParseCommandLineOptions(4, args1, StringRef(), &OS)); OS.flush(); 1704 EXPECT_TRUE(OptA); 1705 EXPECT_FALSE(OptBLong); 1706 EXPECT_STREQ("val1", OptAB.c_str()); 1707 EXPECT_TRUE(Errs.empty()); Errs.clear(); 1708 cl::ResetAllOptionOccurrences(); 1709 1710 EXPECT_TRUE( 1711 cl::ParseCommandLineOptions(4, args2, StringRef(), &OS)); OS.flush(); 1712 EXPECT_TRUE(OptA); 1713 EXPECT_FALSE(OptBLong); 1714 EXPECT_STREQ("val1", OptAB.c_str()); 1715 EXPECT_TRUE(Errs.empty()); Errs.clear(); 1716 cl::ResetAllOptionOccurrences(); 1717 1718 // Fails because `-ab` and `--ab` are treated the same and appear more than 1719 // once. Also, `val1` is unexpected. 1720 EXPECT_FALSE( 1721 cl::ParseCommandLineOptions(4, args3, StringRef(), &OS)); OS.flush(); 1722 outs()<< Errs << "\n"; 1723 EXPECT_FALSE(Errs.empty()); Errs.clear(); 1724 cl::ResetAllOptionOccurrences(); 1725 1726 // 1727 // The following tests treat `-` and `--` differently, with `-` for short, and 1728 // `--` for long options. 1729 // 1730 1731 // Fails because `-ab` is treated as `-a -b`, so `-a` is seen twice, and 1732 // `val1` is unexpected. 1733 EXPECT_FALSE(cl::ParseCommandLineOptions(4, args1, StringRef(), 1734 &OS, nullptr, true)); OS.flush(); 1735 EXPECT_FALSE(Errs.empty()); Errs.clear(); 1736 cl::ResetAllOptionOccurrences(); 1737 1738 // Works because `-a` is treated differently than `--ab`. 1739 EXPECT_TRUE(cl::ParseCommandLineOptions(4, args2, StringRef(), 1740 &OS, nullptr, true)); OS.flush(); 1741 EXPECT_TRUE(Errs.empty()); Errs.clear(); 1742 cl::ResetAllOptionOccurrences(); 1743 1744 // Works because `-ab` is treated as `-a -b`, and `--ab` is a long option. 1745 EXPECT_TRUE(cl::ParseCommandLineOptions(4, args3, StringRef(), 1746 &OS, nullptr, true)); 1747 EXPECT_TRUE(OptA); 1748 EXPECT_TRUE(OptBLong); 1749 EXPECT_STREQ("val1", OptAB.c_str()); 1750 OS.flush(); 1751 EXPECT_TRUE(Errs.empty()); Errs.clear(); 1752 cl::ResetAllOptionOccurrences(); 1753 } 1754 1755 TEST(CommandLineTest, OptionErrorMessage) { 1756 // When there is an error, we expect some error message like: 1757 // prog: for the -a option: [...] 1758 // 1759 // Test whether the "for the -a option"-part is correctly formatted. 1760 cl::ResetCommandLineParser(); 1761 1762 StackOption<bool> OptA("a", cl::desc("Some option")); 1763 StackOption<bool> OptLong("long", cl::desc("Some long option")); 1764 1765 std::string Errs; 1766 raw_string_ostream OS(Errs); 1767 1768 OptA.error("custom error", OS); 1769 OS.flush(); 1770 EXPECT_NE(Errs.find("for the -a option:"), std::string::npos); 1771 Errs.clear(); 1772 1773 OptLong.error("custom error", OS); 1774 OS.flush(); 1775 EXPECT_NE(Errs.find("for the --long option:"), std::string::npos); 1776 Errs.clear(); 1777 1778 cl::ResetAllOptionOccurrences(); 1779 } 1780 1781 TEST(CommandLineTest, OptionErrorMessageSuggest) { 1782 // When there is an error, and the edit-distance is not very large, 1783 // we expect some error message like: 1784 // prog: did you mean '--option'? 1785 // 1786 // Test whether this message is well-formatted. 1787 cl::ResetCommandLineParser(); 1788 1789 StackOption<bool> OptLong("aluminium", cl::desc("Some long option")); 1790 1791 const char *args[] = {"prog", "--aluminum"}; 1792 1793 std::string Errs; 1794 raw_string_ostream OS(Errs); 1795 1796 EXPECT_FALSE(cl::ParseCommandLineOptions(2, args, StringRef(), &OS)); 1797 OS.flush(); 1798 EXPECT_NE(Errs.find("prog: Did you mean '--aluminium'?\n"), 1799 std::string::npos); 1800 Errs.clear(); 1801 1802 cl::ResetAllOptionOccurrences(); 1803 } 1804 1805 TEST(CommandLineTest, OptionErrorMessageSuggestNoHidden) { 1806 // We expect that 'really hidden' option do not show up in option 1807 // suggestions. 1808 cl::ResetCommandLineParser(); 1809 1810 StackOption<bool> OptLong("aluminium", cl::desc("Some long option")); 1811 StackOption<bool> OptLong2("aluminum", cl::desc("Bad option"), 1812 cl::ReallyHidden); 1813 1814 const char *args[] = {"prog", "--alumnum"}; 1815 1816 std::string Errs; 1817 raw_string_ostream OS(Errs); 1818 1819 EXPECT_FALSE(cl::ParseCommandLineOptions(2, args, StringRef(), &OS)); 1820 OS.flush(); 1821 EXPECT_NE(Errs.find("prog: Did you mean '--aluminium'?\n"), 1822 std::string::npos); 1823 Errs.clear(); 1824 1825 cl::ResetAllOptionOccurrences(); 1826 } 1827 1828 TEST(CommandLineTest, Callback) { 1829 cl::ResetCommandLineParser(); 1830 1831 StackOption<bool> OptA("a", cl::desc("option a")); 1832 StackOption<bool> OptB( 1833 "b", cl::desc("option b -- This option turns on option a"), 1834 cl::callback([&](const bool &) { OptA = true; })); 1835 StackOption<bool> OptC( 1836 "c", cl::desc("option c -- This option turns on options a and b"), 1837 cl::callback([&](const bool &) { OptB = true; })); 1838 StackOption<std::string, cl::list<std::string>> List( 1839 "list", 1840 cl::desc("option list -- This option turns on options a, b, and c when " 1841 "'foo' is included in list"), 1842 cl::CommaSeparated, 1843 cl::callback([&](const std::string &Str) { 1844 if (Str == "foo") 1845 OptC = true; 1846 })); 1847 1848 const char *args1[] = {"prog", "-a"}; 1849 EXPECT_TRUE(cl::ParseCommandLineOptions(2, args1)); 1850 EXPECT_TRUE(OptA); 1851 EXPECT_FALSE(OptB); 1852 EXPECT_FALSE(OptC); 1853 EXPECT_EQ(List.size(), 0u); 1854 cl::ResetAllOptionOccurrences(); 1855 1856 const char *args2[] = {"prog", "-b"}; 1857 EXPECT_TRUE(cl::ParseCommandLineOptions(2, args2)); 1858 EXPECT_TRUE(OptA); 1859 EXPECT_TRUE(OptB); 1860 EXPECT_FALSE(OptC); 1861 EXPECT_EQ(List.size(), 0u); 1862 cl::ResetAllOptionOccurrences(); 1863 1864 const char *args3[] = {"prog", "-c"}; 1865 EXPECT_TRUE(cl::ParseCommandLineOptions(2, args3)); 1866 EXPECT_TRUE(OptA); 1867 EXPECT_TRUE(OptB); 1868 EXPECT_TRUE(OptC); 1869 EXPECT_EQ(List.size(), 0u); 1870 cl::ResetAllOptionOccurrences(); 1871 1872 const char *args4[] = {"prog", "--list=foo,bar"}; 1873 EXPECT_TRUE(cl::ParseCommandLineOptions(2, args4)); 1874 EXPECT_TRUE(OptA); 1875 EXPECT_TRUE(OptB); 1876 EXPECT_TRUE(OptC); 1877 EXPECT_EQ(List.size(), 2u); 1878 cl::ResetAllOptionOccurrences(); 1879 1880 const char *args5[] = {"prog", "--list=bar"}; 1881 EXPECT_TRUE(cl::ParseCommandLineOptions(2, args5)); 1882 EXPECT_FALSE(OptA); 1883 EXPECT_FALSE(OptB); 1884 EXPECT_FALSE(OptC); 1885 EXPECT_EQ(List.size(), 1u); 1886 1887 cl::ResetAllOptionOccurrences(); 1888 } 1889 1890 enum Enum { Val1, Val2 }; 1891 static cl::bits<Enum> ExampleBits( 1892 cl::desc("An example cl::bits to ensure it compiles"), 1893 cl::values( 1894 clEnumValN(Val1, "bits-val1", "The Val1 value"), 1895 clEnumValN(Val1, "bits-val2", "The Val2 value"))); 1896 1897 TEST(CommandLineTest, ConsumeAfterOnePositional) { 1898 cl::ResetCommandLineParser(); 1899 1900 // input [args] 1901 StackOption<std::string, cl::opt<std::string>> Input(cl::Positional, 1902 cl::Required); 1903 StackOption<std::string, cl::list<std::string>> ExtraArgs(cl::ConsumeAfter); 1904 1905 const char *Args[] = {"prog", "input", "arg1", "arg2"}; 1906 1907 std::string Errs; 1908 raw_string_ostream OS(Errs); 1909 EXPECT_TRUE(cl::ParseCommandLineOptions(4, Args, StringRef(), &OS)); 1910 OS.flush(); 1911 EXPECT_EQ("input", Input); 1912 EXPECT_EQ(ExtraArgs.size(), 2u); 1913 EXPECT_EQ(ExtraArgs[0], "arg1"); 1914 EXPECT_EQ(ExtraArgs[1], "arg2"); 1915 EXPECT_TRUE(Errs.empty()); 1916 } 1917 1918 TEST(CommandLineTest, ConsumeAfterTwoPositionals) { 1919 cl::ResetCommandLineParser(); 1920 1921 // input1 input2 [args] 1922 StackOption<std::string, cl::opt<std::string>> Input1(cl::Positional, 1923 cl::Required); 1924 StackOption<std::string, cl::opt<std::string>> Input2(cl::Positional, 1925 cl::Required); 1926 StackOption<std::string, cl::list<std::string>> ExtraArgs(cl::ConsumeAfter); 1927 1928 const char *Args[] = {"prog", "input1", "input2", "arg1", "arg2"}; 1929 1930 std::string Errs; 1931 raw_string_ostream OS(Errs); 1932 EXPECT_TRUE(cl::ParseCommandLineOptions(5, Args, StringRef(), &OS)); 1933 OS.flush(); 1934 EXPECT_EQ("input1", Input1); 1935 EXPECT_EQ("input2", Input2); 1936 EXPECT_EQ(ExtraArgs.size(), 2u); 1937 EXPECT_EQ(ExtraArgs[0], "arg1"); 1938 EXPECT_EQ(ExtraArgs[1], "arg2"); 1939 EXPECT_TRUE(Errs.empty()); 1940 } 1941 1942 TEST(CommandLineTest, ResetAllOptionOccurrences) { 1943 cl::ResetCommandLineParser(); 1944 1945 // -option -str -enableA -enableC [sink] input [args] 1946 StackOption<bool> Option("option"); 1947 StackOption<std::string> Str("str"); 1948 enum Vals { ValA, ValB, ValC }; 1949 StackOption<Vals, cl::bits<Vals>> Bits( 1950 cl::values(clEnumValN(ValA, "enableA", "Enable A"), 1951 clEnumValN(ValB, "enableB", "Enable B"), 1952 clEnumValN(ValC, "enableC", "Enable C"))); 1953 StackOption<std::string, cl::list<std::string>> Sink(cl::Sink); 1954 StackOption<std::string> Input(cl::Positional); 1955 StackOption<std::string, cl::list<std::string>> ExtraArgs(cl::ConsumeAfter); 1956 1957 const char *Args[] = {"prog", "-option", "-str=STR", "-enableA", 1958 "-enableC", "-unknown", "input", "-arg"}; 1959 1960 std::string Errs; 1961 raw_string_ostream OS(Errs); 1962 EXPECT_TRUE(cl::ParseCommandLineOptions(8, Args, StringRef(), &OS)); 1963 EXPECT_TRUE(OS.str().empty()); 1964 1965 EXPECT_TRUE(Option); 1966 EXPECT_EQ("STR", Str); 1967 EXPECT_EQ((1u << ValA) | (1u << ValC), Bits.getBits()); 1968 EXPECT_EQ(1u, Sink.size()); 1969 EXPECT_EQ("-unknown", Sink[0]); 1970 EXPECT_EQ("input", Input); 1971 EXPECT_EQ(1u, ExtraArgs.size()); 1972 EXPECT_EQ("-arg", ExtraArgs[0]); 1973 1974 cl::ResetAllOptionOccurrences(); 1975 EXPECT_FALSE(Option); 1976 EXPECT_EQ("", Str); 1977 EXPECT_EQ(0u, Bits.getBits()); 1978 EXPECT_EQ(0u, Sink.size()); 1979 EXPECT_EQ(0, Input.getNumOccurrences()); 1980 EXPECT_EQ(0u, ExtraArgs.size()); 1981 } 1982 1983 TEST(CommandLineTest, DefaultValue) { 1984 cl::ResetCommandLineParser(); 1985 1986 StackOption<bool> BoolOption("bool-option"); 1987 StackOption<std::string> StrOption("str-option"); 1988 StackOption<bool> BoolInitOption("bool-init-option", cl::init(true)); 1989 StackOption<std::string> StrInitOption("str-init-option", 1990 cl::init("str-default-value")); 1991 1992 const char *Args[] = {"prog"}; // no options 1993 1994 std::string Errs; 1995 raw_string_ostream OS(Errs); 1996 EXPECT_TRUE(cl::ParseCommandLineOptions(1, Args, StringRef(), &OS)); 1997 EXPECT_TRUE(OS.str().empty()); 1998 1999 EXPECT_TRUE(!BoolOption); 2000 EXPECT_FALSE(BoolOption.Default.hasValue()); 2001 EXPECT_EQ(0, BoolOption.getNumOccurrences()); 2002 2003 EXPECT_EQ("", StrOption); 2004 EXPECT_FALSE(StrOption.Default.hasValue()); 2005 EXPECT_EQ(0, StrOption.getNumOccurrences()); 2006 2007 EXPECT_TRUE(BoolInitOption); 2008 EXPECT_TRUE(BoolInitOption.Default.hasValue()); 2009 EXPECT_EQ(0, BoolInitOption.getNumOccurrences()); 2010 2011 EXPECT_EQ("str-default-value", StrInitOption); 2012 EXPECT_TRUE(StrInitOption.Default.hasValue()); 2013 EXPECT_EQ(0, StrInitOption.getNumOccurrences()); 2014 2015 const char *Args2[] = {"prog", "-bool-option", "-str-option=str-value", 2016 "-bool-init-option=0", 2017 "-str-init-option=str-init-value"}; 2018 2019 EXPECT_TRUE(cl::ParseCommandLineOptions(5, Args2, StringRef(), &OS)); 2020 EXPECT_TRUE(OS.str().empty()); 2021 2022 EXPECT_TRUE(BoolOption); 2023 EXPECT_FALSE(BoolOption.Default.hasValue()); 2024 EXPECT_EQ(1, BoolOption.getNumOccurrences()); 2025 2026 EXPECT_EQ("str-value", StrOption); 2027 EXPECT_FALSE(StrOption.Default.hasValue()); 2028 EXPECT_EQ(1, StrOption.getNumOccurrences()); 2029 2030 EXPECT_FALSE(BoolInitOption); 2031 EXPECT_TRUE(BoolInitOption.Default.hasValue()); 2032 EXPECT_EQ(1, BoolInitOption.getNumOccurrences()); 2033 2034 EXPECT_EQ("str-init-value", StrInitOption); 2035 EXPECT_TRUE(StrInitOption.Default.hasValue()); 2036 EXPECT_EQ(1, StrInitOption.getNumOccurrences()); 2037 } 2038 2039 } // anonymous namespace 2040