xref: /llvm-project/llvm/unittests/Option/OptionParsingTest.cpp (revision dd647e3e608ed0b2bac7c588d5859b80ef4a5976)
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