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