1 //===- unittest/Support/OptionParsingTest.cpp - OptTable tests ------------===//
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
7 //===----------------------------------------------------------------------===//
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"
16 using namespace llvm::opt
;
19 OPT_INVALID
= 0, // This is not an option ID.
20 #define OPTION(PREFIX, NAME, ID, KIND, GROUP, ALIAS, ALIASARGS, FLAGS, PARAM, \
21 HELPTEXT, METAVAR, VALUES) \
28 #define PREFIX(NAME, VALUE) const char *const NAME[] = VALUE;
38 static const OptTable::Info InfoTable
[] = {
39 #define OPTION(PREFIX, NAME, ID, KIND, GROUP, ALIAS, ALIASARGS, FLAGS, PARAM, \
40 HELPTEXT, METAVAR, VALUES) \
41 {PREFIX, NAME, HELPTEXT, METAVAR, OPT_##ID, Option::KIND##Class, \
42 PARAM, FLAGS, OPT_##GROUP, OPT_##ALIAS, ALIASARGS, VALUES},
48 class TestOptTable
: public OptTable
{
50 TestOptTable(bool IgnoreCase
= false)
51 : OptTable(InfoTable
, IgnoreCase
) {}
55 const char *Args
[] = {
61 "-E", "apple", "bloom",
67 TEST(Option
, OptionParsing
) {
70 InputArgList AL
= T
.ParseArgs(Args
, MAI
, MAC
);
72 // Check they all exist.
73 EXPECT_TRUE(AL
.hasArg(OPT_A
));
74 EXPECT_TRUE(AL
.hasArg(OPT_B
));
75 EXPECT_TRUE(AL
.hasArg(OPT_C
));
76 EXPECT_TRUE(AL
.hasArg(OPT_D
));
77 EXPECT_TRUE(AL
.hasArg(OPT_E
));
78 EXPECT_TRUE(AL
.hasArg(OPT_F
));
79 EXPECT_TRUE(AL
.hasArg(OPT_G
));
82 EXPECT_EQ("hi", AL
.getLastArgValue(OPT_B
));
83 EXPECT_EQ("bye", AL
.getLastArgValue(OPT_C
));
84 EXPECT_EQ("adena", AL
.getLastArgValue(OPT_D
));
85 std::vector
<std::string
> Es
= AL
.getAllArgValues(OPT_E
);
86 EXPECT_EQ("apple", Es
[0]);
87 EXPECT_EQ("bloom", Es
[1]);
88 EXPECT_EQ("42", AL
.getLastArgValue(OPT_F
));
89 std::vector
<std::string
> Gs
= AL
.getAllArgValues(OPT_G
);
90 EXPECT_EQ("chuu", Gs
[0]);
91 EXPECT_EQ("2", Gs
[1]);
93 // Check the help text.
95 raw_string_ostream
RSO(Help
);
96 T
.PrintHelp(RSO
, "test", "title!");
97 EXPECT_NE(std::string::npos
, Help
.find("-A"));
100 T
.PrintHelp(RSO
, "name [options] file...", "title!");
101 EXPECT_NE(std::string::npos
, Help
.find("USAGE: name [options] file...\n"));
104 auto Cs
= AL
.filtered(OPT_C
);
105 ASSERT_NE(Cs
.begin(), Cs
.end());
106 EXPECT_EQ("desu", StringRef((*Cs
.begin())->getValue()));
108 (*Cs
.begin())->render(AL
, ASL
);
109 ASSERT_EQ(2u, ASL
.size());
110 EXPECT_EQ("-C", StringRef(ASL
[0]));
111 EXPECT_EQ("desu", StringRef(ASL
[1]));
114 TEST(Option
, ParseWithFlagExclusions
) {
118 // Exclude flag3 to avoid parsing as OPT_SLASH_C.
119 InputArgList AL
= T
.ParseArgs(Args
, MAI
, MAC
,
120 /*FlagsToInclude=*/0,
121 /*FlagsToExclude=*/OptFlag3
);
122 EXPECT_TRUE(AL
.hasArg(OPT_A
));
123 EXPECT_TRUE(AL
.hasArg(OPT_C
));
124 EXPECT_FALSE(AL
.hasArg(OPT_SLASH_C
));
126 // Exclude flag1 to avoid parsing as OPT_C.
127 AL
= T
.ParseArgs(Args
, MAI
, MAC
,
128 /*FlagsToInclude=*/0,
129 /*FlagsToExclude=*/OptFlag1
);
130 EXPECT_TRUE(AL
.hasArg(OPT_B
));
131 EXPECT_FALSE(AL
.hasArg(OPT_C
));
132 EXPECT_TRUE(AL
.hasArg(OPT_SLASH_C
));
134 const char *NewArgs
[] = { "/C", "foo", "--C=bar" };
135 AL
= T
.ParseArgs(NewArgs
, MAI
, MAC
);
136 EXPECT_TRUE(AL
.hasArg(OPT_SLASH_C
));
137 EXPECT_TRUE(AL
.hasArg(OPT_C
));
138 EXPECT_EQ("foo", AL
.getLastArgValue(OPT_SLASH_C
));
139 EXPECT_EQ("bar", AL
.getLastArgValue(OPT_C
));
142 TEST(Option
, ParseAliasInGroup
) {
146 const char *MyArgs
[] = { "-I" };
147 InputArgList AL
= T
.ParseArgs(MyArgs
, MAI
, MAC
);
148 EXPECT_TRUE(AL
.hasArg(OPT_H
));
151 TEST(Option
, AliasArgs
) {
155 const char *MyArgs
[] = { "-J", "-Joo" };
156 InputArgList AL
= T
.ParseArgs(MyArgs
, MAI
, MAC
);
157 EXPECT_TRUE(AL
.hasArg(OPT_B
));
158 EXPECT_EQ("foo", AL
.getAllArgValues(OPT_B
)[0]);
159 EXPECT_EQ("bar", AL
.getAllArgValues(OPT_B
)[1]);
162 TEST(Option
, IgnoreCase
) {
163 TestOptTable
T(true);
166 const char *MyArgs
[] = { "-a", "-joo" };
167 InputArgList AL
= T
.ParseArgs(MyArgs
, MAI
, MAC
);
168 EXPECT_TRUE(AL
.hasArg(OPT_A
));
169 EXPECT_TRUE(AL
.hasArg(OPT_B
));
172 TEST(Option
, DoNotIgnoreCase
) {
176 const char *MyArgs
[] = { "-a", "-joo" };
177 InputArgList AL
= T
.ParseArgs(MyArgs
, MAI
, MAC
);
178 EXPECT_FALSE(AL
.hasArg(OPT_A
));
179 EXPECT_FALSE(AL
.hasArg(OPT_B
));
182 TEST(Option
, SlurpEmpty
) {
186 const char *MyArgs
[] = { "-A", "-slurp" };
187 InputArgList AL
= T
.ParseArgs(MyArgs
, MAI
, MAC
);
188 EXPECT_TRUE(AL
.hasArg(OPT_A
));
189 EXPECT_TRUE(AL
.hasArg(OPT_Slurp
));
190 EXPECT_EQ(0U, AL
.getAllArgValues(OPT_Slurp
).size());
193 TEST(Option
, Slurp
) {
197 const char *MyArgs
[] = { "-A", "-slurp", "-B", "--", "foo" };
198 InputArgList AL
= T
.ParseArgs(MyArgs
, MAI
, MAC
);
199 EXPECT_EQ(AL
.size(), 2U);
200 EXPECT_TRUE(AL
.hasArg(OPT_A
));
201 EXPECT_FALSE(AL
.hasArg(OPT_B
));
202 EXPECT_TRUE(AL
.hasArg(OPT_Slurp
));
203 EXPECT_EQ(3U, AL
.getAllArgValues(OPT_Slurp
).size());
204 EXPECT_EQ("-B", AL
.getAllArgValues(OPT_Slurp
)[0]);
205 EXPECT_EQ("--", AL
.getAllArgValues(OPT_Slurp
)[1]);
206 EXPECT_EQ("foo", AL
.getAllArgValues(OPT_Slurp
)[2]);
209 TEST(Option
, SlurpJoinedEmpty
) {
213 const char *MyArgs
[] = { "-A", "-slurpjoined" };
214 InputArgList AL
= T
.ParseArgs(MyArgs
, MAI
, MAC
);
215 EXPECT_TRUE(AL
.hasArg(OPT_A
));
216 EXPECT_TRUE(AL
.hasArg(OPT_SlurpJoined
));
217 EXPECT_EQ(AL
.getAllArgValues(OPT_SlurpJoined
).size(), 0U);
220 TEST(Option
, SlurpJoinedOneJoined
) {
224 const char *MyArgs
[] = { "-A", "-slurpjoinedfoo" };
225 InputArgList AL
= T
.ParseArgs(MyArgs
, MAI
, MAC
);
226 EXPECT_TRUE(AL
.hasArg(OPT_A
));
227 EXPECT_TRUE(AL
.hasArg(OPT_SlurpJoined
));
228 EXPECT_EQ(AL
.getAllArgValues(OPT_SlurpJoined
).size(), 1U);
229 EXPECT_EQ(AL
.getAllArgValues(OPT_SlurpJoined
)[0], "foo");
232 TEST(Option
, SlurpJoinedAndSeparate
) {
236 const char *MyArgs
[] = { "-A", "-slurpjoinedfoo", "bar", "baz" };
237 InputArgList AL
= T
.ParseArgs(MyArgs
, MAI
, MAC
);
238 EXPECT_TRUE(AL
.hasArg(OPT_A
));
239 EXPECT_TRUE(AL
.hasArg(OPT_SlurpJoined
));
240 EXPECT_EQ(3U, AL
.getAllArgValues(OPT_SlurpJoined
).size());
241 EXPECT_EQ("foo", AL
.getAllArgValues(OPT_SlurpJoined
)[0]);
242 EXPECT_EQ("bar", AL
.getAllArgValues(OPT_SlurpJoined
)[1]);
243 EXPECT_EQ("baz", AL
.getAllArgValues(OPT_SlurpJoined
)[2]);
246 TEST(Option
, SlurpJoinedButSeparate
) {
250 const char *MyArgs
[] = { "-A", "-slurpjoined", "foo", "bar", "baz" };
251 InputArgList AL
= T
.ParseArgs(MyArgs
, MAI
, MAC
);
252 EXPECT_TRUE(AL
.hasArg(OPT_A
));
253 EXPECT_TRUE(AL
.hasArg(OPT_SlurpJoined
));
254 EXPECT_EQ(3U, AL
.getAllArgValues(OPT_SlurpJoined
).size());
255 EXPECT_EQ("foo", AL
.getAllArgValues(OPT_SlurpJoined
)[0]);
256 EXPECT_EQ("bar", AL
.getAllArgValues(OPT_SlurpJoined
)[1]);
257 EXPECT_EQ("baz", AL
.getAllArgValues(OPT_SlurpJoined
)[2]);
260 TEST(Option
, FlagAliasToJoined
) {
264 // Check that a flag alias provides an empty argument to a joined option.
265 const char *MyArgs
[] = { "-K" };
266 InputArgList AL
= T
.ParseArgs(MyArgs
, MAI
, MAC
);
267 EXPECT_EQ(AL
.size(), 1U);
268 EXPECT_TRUE(AL
.hasArg(OPT_B
));
269 EXPECT_EQ(1U, AL
.getAllArgValues(OPT_B
).size());
270 EXPECT_EQ("", AL
.getAllArgValues(OPT_B
)[0]);
273 TEST(Option
, FindNearest
) {
277 // Options that are too short should not be considered
278 // "near" other short options.
279 EXPECT_GT(T
.findNearest("-A", Nearest
), 4U);
280 EXPECT_GT(T
.findNearest("/C", Nearest
), 4U);
281 EXPECT_GT(T
.findNearest("--C=foo", Nearest
), 4U);
283 // The nearest candidate should mirror the amount of prefix
284 // characters used in the original string.
285 EXPECT_EQ(1U, T
.findNearest("-blorb", Nearest
));
286 EXPECT_EQ(Nearest
, "-blorp");
287 EXPECT_EQ(1U, T
.findNearest("--blorm", Nearest
));
288 EXPECT_EQ(Nearest
, "--blorp");
289 EXPECT_EQ(1U, T
.findNearest("-blarg", Nearest
));
290 EXPECT_EQ(Nearest
, "-blarn");
291 EXPECT_EQ(1U, T
.findNearest("--blarm", Nearest
));
292 EXPECT_EQ(Nearest
, "--blarn");
293 EXPECT_EQ(1U, T
.findNearest("-fjormp", Nearest
));
294 EXPECT_EQ(Nearest
, "--fjormp");
296 // The nearest candidate respects the prefix and value delimiter
297 // of the original string.
298 EXPECT_EQ(1U, T
.findNearest("/framb:foo", Nearest
));
299 EXPECT_EQ(Nearest
, "/cramb:foo");
301 // `--glormp` should have an editing distance > 0 from `--glormp=`.
302 EXPECT_GT(T
.findNearest("--glorrmp", Nearest
), 0U);
303 EXPECT_EQ(Nearest
, "--glorrmp=");
304 EXPECT_EQ(0U, T
.findNearest("--glorrmp=foo", Nearest
));
306 // `--blurmps` should correct to `--blurmp`, not `--blurmp=`, even though
307 // both naively have an editing distance of 1.
308 EXPECT_EQ(1U, T
.findNearest("--blurmps", Nearest
));
309 EXPECT_EQ(Nearest
, "--blurmp");
311 // ...but `--blurmps=foo` should correct to `--blurmp=foo`.
312 EXPECT_EQ(1U, T
.findNearest("--blurmps=foo", Nearest
));
313 EXPECT_EQ(Nearest
, "--blurmp=foo");
315 // Flags should be included and excluded as specified.
316 EXPECT_EQ(1U, T
.findNearest("-doopf", Nearest
, /*FlagsToInclude=*/OptFlag2
));
317 EXPECT_EQ(Nearest
, "-doopf2");
318 EXPECT_EQ(1U, T
.findNearest("-doopf", Nearest
,
319 /*FlagsToInclude=*/0,
320 /*FlagsToExclude=*/OptFlag2
));
321 EXPECT_EQ(Nearest
, "-doopf1");
324 TEST(DISABLED_Option
, FindNearestFIXME
) {
328 // FIXME: Options with joined values should not have those values considered
329 // when calculating distance. The test below would fail if run, but it should
331 EXPECT_EQ(1U, T
.findNearest("--erbghFoo", Nearest
));
332 EXPECT_EQ(Nearest
, "--ermghFoo");