1 //===- unittest/Support/OptionParsingTest.cpp - OptTable 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/ADT/STLExtras.h" 10 #include "llvm/Option/Arg.h" 11 #include "llvm/Option/ArgList.h" 12 #include "llvm/Option/OptTable.h" 13 #include "llvm/Option/Option.h" 14 #include "gtest/gtest.h" 15 16 using namespace llvm; 17 using namespace llvm::opt; 18 19 #if defined(__clang__) 20 #pragma clang diagnostic ignored "-Wdeprecated-declarations" 21 #endif 22 23 #define OPTTABLE_STR_TABLE_CODE 24 #include "Opts.inc" 25 #undef OPTTABLE_STR_TABLE_CODE 26 27 enum ID { 28 OPT_INVALID = 0, // This is not an option ID. 29 #define OPTION(...) LLVM_MAKE_OPT_ID(__VA_ARGS__), 30 #include "Opts.inc" 31 LastOption 32 #undef OPTION 33 }; 34 35 #define OPTTABLE_PREFIXES_TABLE_CODE 36 #include "Opts.inc" 37 #undef OPTTABLE_PREFIXES_TABLE_CODE 38 39 #define OPTTABLE_PREFIXES_UNION_CODE 40 #include "Opts.inc" 41 #undef OPTTABLE_PREFIXES_UNION_CODE 42 43 enum OptionFlags { 44 OptFlag1 = (1 << 4), 45 OptFlag2 = (1 << 5), 46 OptFlag3 = (1 << 6) 47 }; 48 49 enum OptionVisibility { 50 SubtoolVis = (1 << 2), 51 MultiLineVis = (1 << 3), 52 }; 53 54 static constexpr OptTable::Info InfoTable[] = { 55 #define OPTION(...) LLVM_CONSTRUCT_OPT_INFO(__VA_ARGS__), 56 #include "Opts.inc" 57 #undef OPTION 58 }; 59 60 namespace { 61 class TestOptTable : public GenericOptTable { 62 public: 63 TestOptTable(bool IgnoreCase = false) 64 : GenericOptTable(OptionStrTable, OptionPrefixesTable, InfoTable, 65 IgnoreCase) {} 66 }; 67 68 class TestPrecomputedOptTable : public PrecomputedOptTable { 69 public: 70 TestPrecomputedOptTable(bool IgnoreCase = false) 71 : PrecomputedOptTable(OptionStrTable, OptionPrefixesTable, InfoTable, 72 OptionPrefixesUnion, IgnoreCase) {} 73 }; 74 } 75 76 const char *Args[] = { 77 "-A", 78 "-Bhi", 79 "--C=desu", 80 "-C", "bye", 81 "-D,adena", 82 "-E", "apple", "bloom", 83 "-Fblarg", 84 "-F", "42", 85 "-Gchuu", "2" 86 }; 87 88 // Test fixture 89 template <typename T> class OptTableTest : public ::testing::Test {}; 90 91 template <typename T> class DISABLED_OptTableTest : public ::testing::Test {}; 92 93 // Test both precomputed and computed OptTables with the same suite of tests. 94 using OptTableTestTypes = 95 ::testing::Types<TestOptTable, TestPrecomputedOptTable>; 96 97 TYPED_TEST_SUITE(OptTableTest, OptTableTestTypes, ); 98 TYPED_TEST_SUITE(DISABLED_OptTableTest, OptTableTestTypes, ); 99 100 TYPED_TEST(OptTableTest, OptionParsing) { 101 TypeParam T; 102 unsigned MAI, MAC; 103 InputArgList AL = T.ParseArgs(Args, MAI, MAC); 104 105 // Check they all exist. 106 EXPECT_TRUE(AL.hasArg(OPT_A)); 107 EXPECT_TRUE(AL.hasArg(OPT_B)); 108 EXPECT_TRUE(AL.hasArg(OPT_C)); 109 EXPECT_TRUE(AL.hasArg(OPT_D)); 110 EXPECT_TRUE(AL.hasArg(OPT_E)); 111 EXPECT_TRUE(AL.hasArg(OPT_F)); 112 EXPECT_TRUE(AL.hasArg(OPT_G)); 113 114 // Check the values. 115 EXPECT_EQ("hi", AL.getLastArgValue(OPT_B)); 116 EXPECT_EQ("bye", AL.getLastArgValue(OPT_C)); 117 EXPECT_EQ("adena", AL.getLastArgValue(OPT_D)); 118 std::vector<std::string> Es = AL.getAllArgValues(OPT_E); 119 EXPECT_EQ("apple", Es[0]); 120 EXPECT_EQ("bloom", Es[1]); 121 EXPECT_EQ("42", AL.getLastArgValue(OPT_F)); 122 std::vector<std::string> Gs = AL.getAllArgValues(OPT_G); 123 EXPECT_EQ("chuu", Gs[0]); 124 EXPECT_EQ("2", Gs[1]); 125 126 // Check the help text. 127 std::string Help; 128 raw_string_ostream RSO(Help); 129 T.printHelp(RSO, "test", "title!"); 130 EXPECT_NE(std::string::npos, Help.find("-A")); 131 132 // Check usage line. 133 T.printHelp(RSO, "name [options] file...", "title!"); 134 EXPECT_NE(std::string::npos, Help.find("USAGE: name [options] file...\n")); 135 136 // Test aliases. 137 auto Cs = AL.filtered(OPT_C); 138 ASSERT_NE(Cs.begin(), Cs.end()); 139 EXPECT_EQ("desu", StringRef((*Cs.begin())->getValue())); 140 ArgStringList ASL; 141 (*Cs.begin())->render(AL, ASL); 142 ASSERT_EQ(2u, ASL.size()); 143 EXPECT_EQ("-C", StringRef(ASL[0])); 144 EXPECT_EQ("desu", StringRef(ASL[1])); 145 } 146 147 TYPED_TEST(OptTableTest, ParseWithFlagExclusions) { 148 TypeParam T; 149 unsigned MAI, MAC; 150 151 // Exclude flag3 to avoid parsing as OPT_SLASH_C. 152 InputArgList AL = T.ParseArgs(Args, MAI, MAC, 153 /*FlagsToInclude=*/0, 154 /*FlagsToExclude=*/OptFlag3); 155 EXPECT_TRUE(AL.hasArg(OPT_A)); 156 EXPECT_TRUE(AL.hasArg(OPT_C)); 157 EXPECT_FALSE(AL.hasArg(OPT_SLASH_C)); 158 159 // Exclude flag1 to avoid parsing as OPT_C. 160 AL = T.ParseArgs(Args, MAI, MAC, 161 /*FlagsToInclude=*/0, 162 /*FlagsToExclude=*/OptFlag1); 163 EXPECT_TRUE(AL.hasArg(OPT_B)); 164 EXPECT_FALSE(AL.hasArg(OPT_C)); 165 EXPECT_TRUE(AL.hasArg(OPT_SLASH_C)); 166 167 const char *NewArgs[] = { "/C", "foo", "--C=bar" }; 168 AL = T.ParseArgs(NewArgs, MAI, MAC); 169 EXPECT_TRUE(AL.hasArg(OPT_SLASH_C)); 170 EXPECT_TRUE(AL.hasArg(OPT_C)); 171 EXPECT_EQ("foo", AL.getLastArgValue(OPT_SLASH_C)); 172 EXPECT_EQ("bar", AL.getLastArgValue(OPT_C)); 173 } 174 175 TYPED_TEST(OptTableTest, ParseWithVisibility) { 176 TypeParam T; 177 unsigned MAI, MAC; 178 179 const char *STArgs[] = {"-A", "-Q", "-R"}; 180 181 // With no visibility specified, we find all of the arguments. 182 InputArgList AL = T.ParseArgs(STArgs, MAI, MAC); 183 EXPECT_TRUE(AL.hasArg(OPT_A)); 184 EXPECT_TRUE(AL.hasArg(OPT_Q)); 185 EXPECT_TRUE(AL.hasArg(OPT_R)); 186 187 // Default visibility omits SubtoolVis. 188 AL = T.ParseArgs(STArgs, MAI, MAC, Visibility(DefaultVis)); 189 EXPECT_TRUE(AL.hasArg(OPT_A)); 190 EXPECT_FALSE(AL.hasArg(OPT_Q)); 191 EXPECT_TRUE(AL.hasArg(OPT_R)); 192 193 // ~SubtoolVis still finds arguments that are visible in Default. 194 AL = T.ParseArgs(STArgs, MAI, MAC, Visibility(~SubtoolVis)); 195 EXPECT_TRUE(AL.hasArg(OPT_A)); 196 EXPECT_FALSE(AL.hasArg(OPT_Q)); 197 EXPECT_TRUE(AL.hasArg(OPT_R)); 198 199 // Only SubtoolVis. 200 AL = T.ParseArgs(STArgs, MAI, MAC, Visibility(SubtoolVis)); 201 EXPECT_FALSE(AL.hasArg(OPT_A)); 202 EXPECT_TRUE(AL.hasArg(OPT_Q)); 203 EXPECT_TRUE(AL.hasArg(OPT_R)); 204 205 // Both Default and SubtoolVis are found. 206 AL = T.ParseArgs(STArgs, MAI, MAC, Visibility(DefaultVis | SubtoolVis)); 207 EXPECT_TRUE(AL.hasArg(OPT_A)); 208 EXPECT_TRUE(AL.hasArg(OPT_Q)); 209 EXPECT_TRUE(AL.hasArg(OPT_R)); 210 } 211 212 TYPED_TEST(OptTableTest, ParseAliasInGroup) { 213 TypeParam T; 214 unsigned MAI, MAC; 215 216 const char *MyArgs[] = { "-I" }; 217 InputArgList AL = T.ParseArgs(MyArgs, MAI, MAC); 218 EXPECT_TRUE(AL.hasArg(OPT_H)); 219 } 220 221 TYPED_TEST(OptTableTest, AliasArgs) { 222 TypeParam T; 223 unsigned MAI, MAC; 224 225 const char *MyArgs[] = { "-J", "-Joo" }; 226 InputArgList AL = T.ParseArgs(MyArgs, MAI, MAC); 227 EXPECT_TRUE(AL.hasArg(OPT_B)); 228 EXPECT_EQ("foo", AL.getAllArgValues(OPT_B)[0]); 229 EXPECT_EQ("bar", AL.getAllArgValues(OPT_B)[1]); 230 } 231 232 TYPED_TEST(OptTableTest, IgnoreCase) { 233 TypeParam T(true); 234 unsigned MAI, MAC; 235 236 const char *MyArgs[] = { "-a", "-joo" }; 237 InputArgList AL = T.ParseArgs(MyArgs, MAI, MAC); 238 EXPECT_TRUE(AL.hasArg(OPT_A)); 239 EXPECT_TRUE(AL.hasArg(OPT_B)); 240 } 241 242 #if defined(__clang__) 243 // Disable the warning that triggers on exactly what is being tested. 244 #pragma clang diagnostic push 245 #pragma clang diagnostic ignored "-Wself-move" 246 #endif 247 248 TYPED_TEST(OptTableTest, InputArgListSelfAssign) { 249 TypeParam T; 250 unsigned MAI, MAC; 251 InputArgList AL = T.ParseArgs(Args, MAI, MAC, 252 /*FlagsToInclude=*/0, 253 /*FlagsToExclude=*/OptFlag3); 254 EXPECT_TRUE(AL.hasArg(OPT_A)); 255 EXPECT_TRUE(AL.hasArg(OPT_C)); 256 EXPECT_FALSE(AL.hasArg(OPT_SLASH_C)); 257 258 AL = std::move(AL); 259 260 EXPECT_TRUE(AL.hasArg(OPT_A)); 261 EXPECT_TRUE(AL.hasArg(OPT_C)); 262 EXPECT_FALSE(AL.hasArg(OPT_SLASH_C)); 263 } 264 265 #if defined(__clang__) 266 #pragma clang diagnostic pop 267 #endif 268 269 TYPED_TEST(OptTableTest, DoNotIgnoreCase) { 270 TypeParam T; 271 unsigned MAI, MAC; 272 273 const char *MyArgs[] = { "-a", "-joo" }; 274 InputArgList AL = T.ParseArgs(MyArgs, MAI, MAC); 275 EXPECT_FALSE(AL.hasArg(OPT_A)); 276 EXPECT_FALSE(AL.hasArg(OPT_B)); 277 } 278 279 TYPED_TEST(OptTableTest, SlurpEmpty) { 280 TypeParam T; 281 unsigned MAI, MAC; 282 283 const char *MyArgs[] = { "-A", "-slurp" }; 284 InputArgList AL = T.ParseArgs(MyArgs, MAI, MAC); 285 EXPECT_TRUE(AL.hasArg(OPT_A)); 286 EXPECT_TRUE(AL.hasArg(OPT_Slurp)); 287 EXPECT_EQ(0U, AL.getAllArgValues(OPT_Slurp).size()); 288 } 289 290 TYPED_TEST(OptTableTest, Slurp) { 291 TypeParam T; 292 unsigned MAI, MAC; 293 294 const char *MyArgs[] = { "-A", "-slurp", "-B", "--", "foo" }; 295 InputArgList AL = T.ParseArgs(MyArgs, MAI, MAC); 296 EXPECT_EQ(AL.size(), 2U); 297 EXPECT_TRUE(AL.hasArg(OPT_A)); 298 EXPECT_FALSE(AL.hasArg(OPT_B)); 299 EXPECT_TRUE(AL.hasArg(OPT_Slurp)); 300 EXPECT_EQ(3U, AL.getAllArgValues(OPT_Slurp).size()); 301 EXPECT_EQ("-B", AL.getAllArgValues(OPT_Slurp)[0]); 302 EXPECT_EQ("--", AL.getAllArgValues(OPT_Slurp)[1]); 303 EXPECT_EQ("foo", AL.getAllArgValues(OPT_Slurp)[2]); 304 } 305 306 TYPED_TEST(OptTableTest, SlurpJoinedEmpty) { 307 TypeParam T; 308 unsigned MAI, MAC; 309 310 const char *MyArgs[] = { "-A", "-slurpjoined" }; 311 InputArgList AL = T.ParseArgs(MyArgs, MAI, MAC); 312 EXPECT_TRUE(AL.hasArg(OPT_A)); 313 EXPECT_TRUE(AL.hasArg(OPT_SlurpJoined)); 314 EXPECT_EQ(AL.getAllArgValues(OPT_SlurpJoined).size(), 0U); 315 } 316 317 TYPED_TEST(OptTableTest, SlurpJoinedOneJoined) { 318 TypeParam T; 319 unsigned MAI, MAC; 320 321 const char *MyArgs[] = { "-A", "-slurpjoinedfoo" }; 322 InputArgList AL = T.ParseArgs(MyArgs, MAI, MAC); 323 EXPECT_TRUE(AL.hasArg(OPT_A)); 324 EXPECT_TRUE(AL.hasArg(OPT_SlurpJoined)); 325 EXPECT_EQ(AL.getAllArgValues(OPT_SlurpJoined).size(), 1U); 326 EXPECT_EQ(AL.getAllArgValues(OPT_SlurpJoined)[0], "foo"); 327 } 328 329 TYPED_TEST(OptTableTest, SlurpJoinedAndSeparate) { 330 TypeParam T; 331 unsigned MAI, MAC; 332 333 const char *MyArgs[] = { "-A", "-slurpjoinedfoo", "bar", "baz" }; 334 InputArgList AL = T.ParseArgs(MyArgs, MAI, MAC); 335 EXPECT_TRUE(AL.hasArg(OPT_A)); 336 EXPECT_TRUE(AL.hasArg(OPT_SlurpJoined)); 337 EXPECT_EQ(3U, AL.getAllArgValues(OPT_SlurpJoined).size()); 338 EXPECT_EQ("foo", AL.getAllArgValues(OPT_SlurpJoined)[0]); 339 EXPECT_EQ("bar", AL.getAllArgValues(OPT_SlurpJoined)[1]); 340 EXPECT_EQ("baz", AL.getAllArgValues(OPT_SlurpJoined)[2]); 341 } 342 343 TYPED_TEST(OptTableTest, SlurpJoinedButSeparate) { 344 TypeParam T; 345 unsigned MAI, MAC; 346 347 const char *MyArgs[] = { "-A", "-slurpjoined", "foo", "bar", "baz" }; 348 InputArgList AL = T.ParseArgs(MyArgs, MAI, MAC); 349 EXPECT_TRUE(AL.hasArg(OPT_A)); 350 EXPECT_TRUE(AL.hasArg(OPT_SlurpJoined)); 351 EXPECT_EQ(3U, AL.getAllArgValues(OPT_SlurpJoined).size()); 352 EXPECT_EQ("foo", AL.getAllArgValues(OPT_SlurpJoined)[0]); 353 EXPECT_EQ("bar", AL.getAllArgValues(OPT_SlurpJoined)[1]); 354 EXPECT_EQ("baz", AL.getAllArgValues(OPT_SlurpJoined)[2]); 355 } 356 357 TYPED_TEST(OptTableTest, FlagAliasToJoined) { 358 TypeParam T; 359 unsigned MAI, MAC; 360 361 // Check that a flag alias provides an empty argument to a joined option. 362 const char *MyArgs[] = { "-K" }; 363 InputArgList AL = T.ParseArgs(MyArgs, MAI, MAC); 364 EXPECT_EQ(AL.size(), 1U); 365 EXPECT_TRUE(AL.hasArg(OPT_B)); 366 EXPECT_EQ(1U, AL.getAllArgValues(OPT_B).size()); 367 EXPECT_EQ("", AL.getAllArgValues(OPT_B)[0]); 368 } 369 370 TYPED_TEST(OptTableTest, FindNearest) { 371 TypeParam T; 372 std::string Nearest; 373 374 // Options that are too short should not be considered 375 // "near" other short options. 376 EXPECT_GT(T.findNearest("-A", Nearest), 4U); 377 EXPECT_GT(T.findNearest("/C", Nearest), 4U); 378 EXPECT_GT(T.findNearest("--C=foo", Nearest), 4U); 379 380 // The nearest candidate should mirror the amount of prefix 381 // characters used in the original string. 382 EXPECT_EQ(1U, T.findNearest("-blorb", Nearest)); 383 EXPECT_EQ(Nearest, "-blorp"); 384 EXPECT_EQ(1U, T.findNearest("--blorm", Nearest)); 385 EXPECT_EQ(Nearest, "--blorp"); 386 EXPECT_EQ(1U, T.findNearest("-blarg", Nearest)); 387 EXPECT_EQ(Nearest, "-blarn"); 388 EXPECT_EQ(1U, T.findNearest("--blarm", Nearest)); 389 EXPECT_EQ(Nearest, "--blarn"); 390 EXPECT_EQ(1U, T.findNearest("-fjormp", Nearest)); 391 EXPECT_EQ(Nearest, "--fjormp"); 392 393 // The nearest candidate respects the prefix and value delimiter 394 // of the original string. 395 EXPECT_EQ(1U, T.findNearest("/framb:foo", Nearest)); 396 EXPECT_EQ(Nearest, "/cramb:foo"); 397 398 // `--glormp` should have an editing distance > 0 from `--glormp=`. 399 EXPECT_GT(T.findNearest("--glorrmp", Nearest), 0U); 400 EXPECT_EQ(Nearest, "--glorrmp="); 401 EXPECT_EQ(0U, T.findNearest("--glorrmp=foo", Nearest)); 402 403 // `--blurmps` should correct to `--blurmp`, not `--blurmp=`, even though 404 // both naively have an editing distance of 1. 405 EXPECT_EQ(1U, T.findNearest("--blurmps", Nearest)); 406 EXPECT_EQ(Nearest, "--blurmp"); 407 408 // ...but `--blurmps=foo` should correct to `--blurmp=foo`. 409 EXPECT_EQ(1U, T.findNearest("--blurmps=foo", Nearest)); 410 EXPECT_EQ(Nearest, "--blurmp=foo"); 411 412 // Flags should be included and excluded as specified. 413 EXPECT_EQ(1U, T.findNearest("-doopf", Nearest, 414 /*FlagsToInclude=*/OptFlag2, 415 /*FlagsToExclude=*/0)); 416 EXPECT_EQ(Nearest, "-doopf2"); 417 EXPECT_EQ(1U, T.findNearest("-doopf", Nearest, 418 /*FlagsToInclude=*/0, 419 /*FlagsToExclude=*/OptFlag2)); 420 EXPECT_EQ(Nearest, "-doopf1"); 421 422 // Spelling should respect visibility. 423 EXPECT_EQ(1U, T.findNearest("-xyzzy", Nearest, Visibility(DefaultVis))); 424 EXPECT_EQ(Nearest, "-xyzzy2"); 425 EXPECT_EQ(1U, T.findNearest("-xyzzy", Nearest, Visibility(SubtoolVis))); 426 EXPECT_EQ(Nearest, "-xyzzy1"); 427 } 428 429 TYPED_TEST(DISABLED_OptTableTest, FindNearestFIXME) { 430 TypeParam T; 431 std::string Nearest; 432 433 // FIXME: Options with joined values should not have those values considered 434 // when calculating distance. The test below would fail if run, but it should 435 // succeed. 436 EXPECT_EQ(1U, T.findNearest("--erbghFoo", Nearest)); 437 EXPECT_EQ(Nearest, "--ermghFoo"); 438 } 439 440 TYPED_TEST(OptTableTest, ParseGroupedShortOptions) { 441 TypeParam T; 442 T.setGroupedShortOptions(true); 443 unsigned MAI, MAC; 444 445 // Grouped short options can be followed by a long Flag (-Joo), or a non-Flag 446 // option (-C=1). 447 const char *Args1[] = {"-AIJ", "-AIJoo", "-AC=1"}; 448 InputArgList AL = T.ParseArgs(Args1, MAI, MAC); 449 EXPECT_TRUE(AL.hasArg(OPT_A)); 450 EXPECT_TRUE(AL.hasArg(OPT_H)); 451 ASSERT_EQ((size_t)2, AL.getAllArgValues(OPT_B).size()); 452 EXPECT_EQ("foo", AL.getAllArgValues(OPT_B)[0]); 453 EXPECT_EQ("bar", AL.getAllArgValues(OPT_B)[1]); 454 ASSERT_TRUE(AL.hasArg(OPT_C)); 455 EXPECT_EQ("1", AL.getAllArgValues(OPT_C)[0]); 456 457 // Prefer a long option to a short option. 458 const char *Args2[] = {"-AB"}; 459 InputArgList AL2 = T.ParseArgs(Args2, MAI, MAC); 460 EXPECT_TRUE(!AL2.hasArg(OPT_A)); 461 EXPECT_TRUE(AL2.hasArg(OPT_AB)); 462 463 // Short options followed by a long option. We probably should disallow this. 464 const char *Args3[] = {"-AIblorp"}; 465 InputArgList AL3 = T.ParseArgs(Args3, MAI, MAC); 466 EXPECT_TRUE(AL3.hasArg(OPT_A)); 467 EXPECT_TRUE(AL3.hasArg(OPT_Blorp)); 468 } 469 470 TYPED_TEST(OptTableTest, ParseDashDash) { 471 TypeParam T; 472 T.setDashDashParsing(true); 473 unsigned MAI, MAC; 474 475 const char *Args1[] = {"-A", "--"}; 476 InputArgList AL = T.ParseArgs(Args1, MAI, MAC); 477 EXPECT_TRUE(AL.hasArg(OPT_A)); 478 EXPECT_EQ(size_t(0), AL.getAllArgValues(OPT_INPUT).size()); 479 EXPECT_EQ(size_t(0), AL.getAllArgValues(OPT_UNKNOWN).size()); 480 481 const char *Args2[] = {"-A", "--", "-A", "--", "-B"}; 482 AL = T.ParseArgs(Args2, MAI, MAC); 483 EXPECT_TRUE(AL.hasArg(OPT_A)); 484 EXPECT_FALSE(AL.hasArg(OPT_B)); 485 const std::vector<std::string> Input = AL.getAllArgValues(OPT_INPUT); 486 ASSERT_EQ(size_t(3), Input.size()); 487 EXPECT_EQ("-A", Input[0]); 488 EXPECT_EQ("--", Input[1]); 489 EXPECT_EQ("-B", Input[2]); 490 EXPECT_EQ(size_t(0), AL.getAllArgValues(OPT_UNKNOWN).size()); 491 492 T.setDashDashParsing(false); 493 AL = T.ParseArgs(Args2, MAI, MAC); 494 EXPECT_TRUE(AL.hasArg(OPT_A)); 495 EXPECT_TRUE(AL.hasArg(OPT_B)); 496 EXPECT_EQ(size_t(0), AL.getAllArgValues(OPT_INPUT).size()); 497 const std::vector<std::string> Unknown = AL.getAllArgValues(OPT_UNKNOWN); 498 ASSERT_EQ(size_t(2), Unknown.size()); 499 EXPECT_EQ("--", Unknown[0]); 500 EXPECT_EQ("--", Unknown[1]); 501 } 502 503 TYPED_TEST(OptTableTest, UnknownOptions) { 504 TypeParam T; 505 unsigned MAI, MAC; 506 const char *Args[] = {"-u", "--long", "0"}; 507 for (int I = 0; I < 2; ++I) { 508 T.setGroupedShortOptions(I != 0); 509 InputArgList AL = T.ParseArgs(Args, MAI, MAC); 510 const std::vector<std::string> Unknown = AL.getAllArgValues(OPT_UNKNOWN); 511 ASSERT_EQ((size_t)2, Unknown.size()); 512 EXPECT_EQ("-u", Unknown[0]); 513 EXPECT_EQ("--long", Unknown[1]); 514 } 515 } 516 517 TYPED_TEST(OptTableTest, FlagsWithoutValues) { 518 TypeParam T; 519 T.setGroupedShortOptions(true); 520 unsigned MAI, MAC; 521 const char *Args[] = {"-A=1", "-A="}; 522 InputArgList AL = T.ParseArgs(Args, MAI, MAC); 523 const std::vector<std::string> Unknown = AL.getAllArgValues(OPT_UNKNOWN); 524 ASSERT_EQ((size_t)2, Unknown.size()); 525 EXPECT_EQ("-A=1", Unknown[0]); 526 EXPECT_EQ("-A=", Unknown[1]); 527 } 528 529 TYPED_TEST(OptTableTest, UnknownGroupedShortOptions) { 530 TypeParam T; 531 T.setGroupedShortOptions(true); 532 unsigned MAI, MAC; 533 const char *Args[] = {"-AuzK", "-AuzK"}; 534 InputArgList AL = T.ParseArgs(Args, MAI, MAC); 535 const std::vector<std::string> Unknown = AL.getAllArgValues(OPT_UNKNOWN); 536 ASSERT_EQ((size_t)4, Unknown.size()); 537 EXPECT_EQ("-u", Unknown[0]); 538 EXPECT_EQ("-z", Unknown[1]); 539 EXPECT_EQ("-u", Unknown[2]); 540 EXPECT_EQ("-z", Unknown[3]); 541 } 542 543 TYPED_TEST(OptTableTest, PrintMultilineHelpText) { 544 TypeParam T; 545 std::string Help; 546 raw_string_ostream RSO(Help); 547 T.printHelp(RSO, "usage", "title", /*ShowHidden=*/false, 548 /*ShowAllAliases=*/false, Visibility(MultiLineVis)); 549 EXPECT_STREQ(Help.c_str(), R"(OVERVIEW: title 550 551 USAGE: usage 552 553 OPTIONS: 554 -multiline-help-with-long-name 555 This a help text that has 556 multiple lines in it 557 and a long name 558 -multiline-help This a help text that has 559 multiple lines in it 560 )"); 561 } 562