blob: 230049c8bd03914d13bb4a0cb2a92974af7d6988 [file] [log] [blame]
Michael J. Spencer96a564f2012-12-05 00:29:32 +00001//===- unittest/Support/OptionParsingTest.cpp - OptTable tests ------------===//
2//
3// The LLVM Compiler Infrastructure
4//
5// This file is distributed under the University of Illinois Open Source
6// License. See LICENSE.TXT for details.
7//
8//===----------------------------------------------------------------------===//
9
Reid Kleckner75b17832013-07-19 18:05:13 +000010#include "llvm/ADT/STLExtras.h"
Michael J. Spencer96a564f2012-12-05 00:29:32 +000011#include "llvm/Option/Arg.h"
12#include "llvm/Option/ArgList.h"
13#include "llvm/Option/Option.h"
Michael J. Spencer96a564f2012-12-05 00:29:32 +000014#include "gtest/gtest.h"
15
16using namespace llvm;
17using namespace llvm::opt;
18
19enum ID {
20 OPT_INVALID = 0, // This is not an option ID.
Yuka Takahashibc5df292017-06-20 16:31:31 +000021#define OPTION(PREFIX, NAME, ID, KIND, GROUP, ALIAS, ALIASARGS, FLAGS, PARAM, \
22 HELPTEXT, METAVAR, VALUES) \
23 OPT_##ID,
Michael J. Spencer96a564f2012-12-05 00:29:32 +000024#include "Opts.inc"
25 LastOption
26#undef OPTION
27};
28
29#define PREFIX(NAME, VALUE) const char *const NAME[] = VALUE;
30#include "Opts.inc"
31#undef PREFIX
32
Reid Kleckner75b17832013-07-19 18:05:13 +000033enum OptionFlags {
34 OptFlag1 = (1 << 4),
35 OptFlag2 = (1 << 5),
36 OptFlag3 = (1 << 6)
37};
38
Michael J. Spencer96a564f2012-12-05 00:29:32 +000039static const OptTable::Info InfoTable[] = {
Yuka Takahashibc5df292017-06-20 16:31:31 +000040#define OPTION(PREFIX, NAME, ID, KIND, GROUP, ALIAS, ALIASARGS, FLAGS, PARAM, \
41 HELPTEXT, METAVAR, VALUES) \
42 {PREFIX, NAME, HELPTEXT, METAVAR, OPT_##ID, Option::KIND##Class, \
43 PARAM, FLAGS, OPT_##GROUP, OPT_##ALIAS, ALIASARGS, VALUES},
Michael J. Spencer96a564f2012-12-05 00:29:32 +000044#include "Opts.inc"
45#undef OPTION
46};
47
48namespace {
49class TestOptTable : public OptTable {
50public:
Rui Ueyama29572732013-08-28 20:04:31 +000051 TestOptTable(bool IgnoreCase = false)
Craig Topper94f8b072015-10-21 16:30:42 +000052 : OptTable(InfoTable, IgnoreCase) {}
Michael J. Spencer96a564f2012-12-05 00:29:32 +000053};
54}
55
56const char *Args[] = {
57 "-A",
58 "-Bhi",
59 "--C=desu",
60 "-C", "bye",
61 "-D,adena",
62 "-E", "apple", "bloom",
63 "-Fblarg",
64 "-F", "42",
65 "-Gchuu", "2"
66 };
67
Reid Kleckner75b17832013-07-19 18:05:13 +000068TEST(Option, OptionParsing) {
Michael J. Spencer96a564f2012-12-05 00:29:32 +000069 TestOptTable T;
70 unsigned MAI, MAC;
David Blaikie0c17f952015-06-22 22:06:37 +000071 InputArgList AL = T.ParseArgs(Args, MAI, MAC);
NAKAMURA Takumi3fe36d02013-01-23 08:30:15 +000072
Michael J. Spencer96a564f2012-12-05 00:29:32 +000073 // Check they all exist.
David Blaikie0c17f952015-06-22 22:06:37 +000074 EXPECT_TRUE(AL.hasArg(OPT_A));
75 EXPECT_TRUE(AL.hasArg(OPT_B));
76 EXPECT_TRUE(AL.hasArg(OPT_C));
77 EXPECT_TRUE(AL.hasArg(OPT_D));
78 EXPECT_TRUE(AL.hasArg(OPT_E));
79 EXPECT_TRUE(AL.hasArg(OPT_F));
80 EXPECT_TRUE(AL.hasArg(OPT_G));
Michael J. Spencer96a564f2012-12-05 00:29:32 +000081
82 // Check the values.
Hans Wennborg486e8bb2016-04-15 00:23:15 +000083 EXPECT_EQ("hi", AL.getLastArgValue(OPT_B));
84 EXPECT_EQ("bye", AL.getLastArgValue(OPT_C));
85 EXPECT_EQ("adena", AL.getLastArgValue(OPT_D));
David Blaikie0c17f952015-06-22 22:06:37 +000086 std::vector<std::string> Es = AL.getAllArgValues(OPT_E);
Hans Wennborg486e8bb2016-04-15 00:23:15 +000087 EXPECT_EQ("apple", Es[0]);
88 EXPECT_EQ("bloom", Es[1]);
89 EXPECT_EQ("42", AL.getLastArgValue(OPT_F));
David Blaikie0c17f952015-06-22 22:06:37 +000090 std::vector<std::string> Gs = AL.getAllArgValues(OPT_G);
Hans Wennborg486e8bb2016-04-15 00:23:15 +000091 EXPECT_EQ("chuu", Gs[0]);
92 EXPECT_EQ("2", Gs[1]);
Michael J. Spencer96a564f2012-12-05 00:29:32 +000093
94 // Check the help text.
95 std::string Help;
96 raw_string_ostream RSO(Help);
97 T.PrintHelp(RSO, "test", "title!");
Hans Wennborg486e8bb2016-04-15 00:23:15 +000098 EXPECT_NE(std::string::npos, Help.find("-A"));
Michael J. Spencer96a564f2012-12-05 00:29:32 +000099
Fangrui Song42f63b62018-10-10 00:15:31 +0000100 // Check usage line.
101 T.PrintHelp(RSO, "name [options] file...", "title!");
102 EXPECT_NE(std::string::npos, Help.find("USAGE: name [options] file...\n"));
103
Michael J. Spencer96a564f2012-12-05 00:29:32 +0000104 // Test aliases.
Richard Smithe22326d2017-04-12 23:43:58 +0000105 auto Cs = AL.filtered(OPT_C);
106 ASSERT_NE(Cs.begin(), Cs.end());
107 EXPECT_EQ("desu", StringRef((*Cs.begin())->getValue()));
Michael J. Spencer96a564f2012-12-05 00:29:32 +0000108 ArgStringList ASL;
Richard Smithe22326d2017-04-12 23:43:58 +0000109 (*Cs.begin())->render(AL, ASL);
Hans Wennborg486e8bb2016-04-15 00:23:15 +0000110 ASSERT_EQ(2u, ASL.size());
111 EXPECT_EQ("-C", StringRef(ASL[0]));
112 EXPECT_EQ("desu", StringRef(ASL[1]));
Michael J. Spencer96a564f2012-12-05 00:29:32 +0000113}
Reid Kleckner75b17832013-07-19 18:05:13 +0000114
115TEST(Option, ParseWithFlagExclusions) {
116 TestOptTable T;
117 unsigned MAI, MAC;
Reid Kleckner75b17832013-07-19 18:05:13 +0000118
119 // Exclude flag3 to avoid parsing as OPT_SLASH_C.
David Blaikie0c17f952015-06-22 22:06:37 +0000120 InputArgList AL = T.ParseArgs(Args, MAI, MAC,
121 /*FlagsToInclude=*/0,
122 /*FlagsToExclude=*/OptFlag3);
123 EXPECT_TRUE(AL.hasArg(OPT_A));
124 EXPECT_TRUE(AL.hasArg(OPT_C));
125 EXPECT_FALSE(AL.hasArg(OPT_SLASH_C));
Reid Kleckner75b17832013-07-19 18:05:13 +0000126
127 // Exclude flag1 to avoid parsing as OPT_C.
David Blaikie0c17f952015-06-22 22:06:37 +0000128 AL = T.ParseArgs(Args, MAI, MAC,
129 /*FlagsToInclude=*/0,
130 /*FlagsToExclude=*/OptFlag1);
131 EXPECT_TRUE(AL.hasArg(OPT_B));
132 EXPECT_FALSE(AL.hasArg(OPT_C));
133 EXPECT_TRUE(AL.hasArg(OPT_SLASH_C));
Reid Kleckner75b17832013-07-19 18:05:13 +0000134
135 const char *NewArgs[] = { "/C", "foo", "--C=bar" };
David Blaikie0c17f952015-06-22 22:06:37 +0000136 AL = T.ParseArgs(NewArgs, MAI, MAC);
137 EXPECT_TRUE(AL.hasArg(OPT_SLASH_C));
138 EXPECT_TRUE(AL.hasArg(OPT_C));
Hans Wennborg486e8bb2016-04-15 00:23:15 +0000139 EXPECT_EQ("foo", AL.getLastArgValue(OPT_SLASH_C));
140 EXPECT_EQ("bar", AL.getLastArgValue(OPT_C));
Reid Kleckner75b17832013-07-19 18:05:13 +0000141}
Hans Wennborg6c7e7872013-07-22 16:18:13 +0000142
143TEST(Option, ParseAliasInGroup) {
144 TestOptTable T;
145 unsigned MAI, MAC;
146
147 const char *MyArgs[] = { "-I" };
David Blaikie0c17f952015-06-22 22:06:37 +0000148 InputArgList AL = T.ParseArgs(MyArgs, MAI, MAC);
149 EXPECT_TRUE(AL.hasArg(OPT_H));
Hans Wennborg6c7e7872013-07-22 16:18:13 +0000150}
Hans Wennborg9dd8c0c2013-07-31 22:44:41 +0000151
152TEST(Option, AliasArgs) {
153 TestOptTable T;
154 unsigned MAI, MAC;
155
156 const char *MyArgs[] = { "-J", "-Joo" };
David Blaikie0c17f952015-06-22 22:06:37 +0000157 InputArgList AL = T.ParseArgs(MyArgs, MAI, MAC);
158 EXPECT_TRUE(AL.hasArg(OPT_B));
Hans Wennborg486e8bb2016-04-15 00:23:15 +0000159 EXPECT_EQ("foo", AL.getAllArgValues(OPT_B)[0]);
160 EXPECT_EQ("bar", AL.getAllArgValues(OPT_B)[1]);
Hans Wennborg9dd8c0c2013-07-31 22:44:41 +0000161}
Hans Wennborg6bf104b2013-08-02 21:20:27 +0000162
Rui Ueyama29572732013-08-28 20:04:31 +0000163TEST(Option, IgnoreCase) {
164 TestOptTable T(true);
165 unsigned MAI, MAC;
166
167 const char *MyArgs[] = { "-a", "-joo" };
David Blaikie0c17f952015-06-22 22:06:37 +0000168 InputArgList AL = T.ParseArgs(MyArgs, MAI, MAC);
169 EXPECT_TRUE(AL.hasArg(OPT_A));
170 EXPECT_TRUE(AL.hasArg(OPT_B));
Rui Ueyama29572732013-08-28 20:04:31 +0000171}
172
173TEST(Option, DoNotIgnoreCase) {
174 TestOptTable T;
175 unsigned MAI, MAC;
176
177 const char *MyArgs[] = { "-a", "-joo" };
David Blaikie0c17f952015-06-22 22:06:37 +0000178 InputArgList AL = T.ParseArgs(MyArgs, MAI, MAC);
179 EXPECT_FALSE(AL.hasArg(OPT_A));
180 EXPECT_FALSE(AL.hasArg(OPT_B));
Rui Ueyama29572732013-08-28 20:04:31 +0000181}
182
Hans Wennborgaf9e3552013-08-13 21:09:50 +0000183TEST(Option, SlurpEmpty) {
184 TestOptTable T;
185 unsigned MAI, MAC;
186
187 const char *MyArgs[] = { "-A", "-slurp" };
David Blaikie0c17f952015-06-22 22:06:37 +0000188 InputArgList AL = T.ParseArgs(MyArgs, MAI, MAC);
189 EXPECT_TRUE(AL.hasArg(OPT_A));
190 EXPECT_TRUE(AL.hasArg(OPT_Slurp));
Hans Wennborg486e8bb2016-04-15 00:23:15 +0000191 EXPECT_EQ(0U, AL.getAllArgValues(OPT_Slurp).size());
Hans Wennborgaf9e3552013-08-13 21:09:50 +0000192}
193
194TEST(Option, Slurp) {
195 TestOptTable T;
196 unsigned MAI, MAC;
197
198 const char *MyArgs[] = { "-A", "-slurp", "-B", "--", "foo" };
David Blaikie0c17f952015-06-22 22:06:37 +0000199 InputArgList AL = T.ParseArgs(MyArgs, MAI, MAC);
200 EXPECT_EQ(AL.size(), 2U);
201 EXPECT_TRUE(AL.hasArg(OPT_A));
202 EXPECT_FALSE(AL.hasArg(OPT_B));
203 EXPECT_TRUE(AL.hasArg(OPT_Slurp));
Hans Wennborg486e8bb2016-04-15 00:23:15 +0000204 EXPECT_EQ(3U, AL.getAllArgValues(OPT_Slurp).size());
205 EXPECT_EQ("-B", AL.getAllArgValues(OPT_Slurp)[0]);
206 EXPECT_EQ("--", AL.getAllArgValues(OPT_Slurp)[1]);
207 EXPECT_EQ("foo", AL.getAllArgValues(OPT_Slurp)[2]);
Hans Wennborgaf9e3552013-08-13 21:09:50 +0000208}
Hans Wennborg375079a2015-05-04 18:00:13 +0000209
Hans Wennborg9f34fd52016-04-15 00:23:30 +0000210TEST(Option, SlurpJoinedEmpty) {
211 TestOptTable T;
212 unsigned MAI, MAC;
213
214 const char *MyArgs[] = { "-A", "-slurpjoined" };
215 InputArgList AL = T.ParseArgs(MyArgs, MAI, MAC);
216 EXPECT_TRUE(AL.hasArg(OPT_A));
217 EXPECT_TRUE(AL.hasArg(OPT_SlurpJoined));
218 EXPECT_EQ(AL.getAllArgValues(OPT_SlurpJoined).size(), 0U);
219}
220
221TEST(Option, SlurpJoinedOneJoined) {
222 TestOptTable T;
223 unsigned MAI, MAC;
224
225 const char *MyArgs[] = { "-A", "-slurpjoinedfoo" };
226 InputArgList AL = T.ParseArgs(MyArgs, MAI, MAC);
227 EXPECT_TRUE(AL.hasArg(OPT_A));
228 EXPECT_TRUE(AL.hasArg(OPT_SlurpJoined));
229 EXPECT_EQ(AL.getAllArgValues(OPT_SlurpJoined).size(), 1U);
230 EXPECT_EQ(AL.getAllArgValues(OPT_SlurpJoined)[0], "foo");
231}
232
233TEST(Option, SlurpJoinedAndSeparate) {
234 TestOptTable T;
235 unsigned MAI, MAC;
236
237 const char *MyArgs[] = { "-A", "-slurpjoinedfoo", "bar", "baz" };
238 InputArgList AL = T.ParseArgs(MyArgs, MAI, MAC);
239 EXPECT_TRUE(AL.hasArg(OPT_A));
240 EXPECT_TRUE(AL.hasArg(OPT_SlurpJoined));
241 EXPECT_EQ(3U, AL.getAllArgValues(OPT_SlurpJoined).size());
242 EXPECT_EQ("foo", AL.getAllArgValues(OPT_SlurpJoined)[0]);
243 EXPECT_EQ("bar", AL.getAllArgValues(OPT_SlurpJoined)[1]);
244 EXPECT_EQ("baz", AL.getAllArgValues(OPT_SlurpJoined)[2]);
245}
246
247TEST(Option, SlurpJoinedButSeparate) {
248 TestOptTable T;
249 unsigned MAI, MAC;
250
251 const char *MyArgs[] = { "-A", "-slurpjoined", "foo", "bar", "baz" };
252 InputArgList AL = T.ParseArgs(MyArgs, MAI, MAC);
253 EXPECT_TRUE(AL.hasArg(OPT_A));
254 EXPECT_TRUE(AL.hasArg(OPT_SlurpJoined));
255 EXPECT_EQ(3U, AL.getAllArgValues(OPT_SlurpJoined).size());
256 EXPECT_EQ("foo", AL.getAllArgValues(OPT_SlurpJoined)[0]);
257 EXPECT_EQ("bar", AL.getAllArgValues(OPT_SlurpJoined)[1]);
258 EXPECT_EQ("baz", AL.getAllArgValues(OPT_SlurpJoined)[2]);
259}
260
Hans Wennborg375079a2015-05-04 18:00:13 +0000261TEST(Option, FlagAliasToJoined) {
262 TestOptTable T;
263 unsigned MAI, MAC;
264
265 // Check that a flag alias provides an empty argument to a joined option.
266 const char *MyArgs[] = { "-K" };
David Blaikie0c17f952015-06-22 22:06:37 +0000267 InputArgList AL = T.ParseArgs(MyArgs, MAI, MAC);
268 EXPECT_EQ(AL.size(), 1U);
269 EXPECT_TRUE(AL.hasArg(OPT_B));
Hans Wennborg486e8bb2016-04-15 00:23:15 +0000270 EXPECT_EQ(1U, AL.getAllArgValues(OPT_B).size());
271 EXPECT_EQ("", AL.getAllArgValues(OPT_B)[0]);
Hans Wennborg375079a2015-05-04 18:00:13 +0000272}
Brian Gesiak1fed6232018-01-05 17:10:39 +0000273
274TEST(Option, FindNearest) {
275 TestOptTable T;
276 std::string Nearest;
277
278 // Options that are too short should not be considered
279 // "near" other short options.
280 EXPECT_GT(T.findNearest("-A", Nearest), 4U);
281 EXPECT_GT(T.findNearest("/C", Nearest), 4U);
282 EXPECT_GT(T.findNearest("--C=foo", Nearest), 4U);
283
284 // The nearest candidate should mirror the amount of prefix
285 // characters used in the original string.
286 EXPECT_EQ(1U, T.findNearest("-blorb", Nearest));
287 EXPECT_EQ(Nearest, "-blorp");
288 EXPECT_EQ(1U, T.findNearest("--blorm", Nearest));
289 EXPECT_EQ(Nearest, "--blorp");
Brian Gesiak2fd0a702018-01-09 19:38:04 +0000290 EXPECT_EQ(1U, T.findNearest("-fjormp", Nearest));
291 EXPECT_EQ(Nearest, "--fjormp");
Brian Gesiak1fed6232018-01-05 17:10:39 +0000292
293 // The nearest candidate respects the prefix and value delimiter
294 // of the original string.
295 EXPECT_EQ(1U, T.findNearest("/framb:foo", Nearest));
296 EXPECT_EQ(Nearest, "/cramb:foo");
297
298 // Flags should be included and excluded as specified.
299 EXPECT_EQ(1U, T.findNearest("-doopf", Nearest, /*FlagsToInclude=*/OptFlag2));
300 EXPECT_EQ(Nearest, "-doopf2");
301 EXPECT_EQ(1U, T.findNearest("-doopf", Nearest,
302 /*FlagsToInclude=*/0,
303 /*FlagsToExclude=*/OptFlag2));
304 EXPECT_EQ(Nearest, "-doopf1");
305}
306
307TEST(DISABLED_Option, FindNearestFIXME) {
308 TestOptTable T;
309 std::string Nearest;
310
311 // FIXME: Options with joined values should not have those values considered
312 // when calculating distance. The test below would fail if run, but it should
313 // succeed.
314 EXPECT_EQ(1U, T.findNearest("--erbghFoo", Nearest));
315 EXPECT_EQ(Nearest, "--ermghFoo");
316
317}