1 //===- 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
10 #include "llvm/ADT/STLExtras.h"
11 #include "llvm/Option/Arg.h"
12 #include "llvm/Option/ArgList.h"
13 #include "llvm/Option/Option.h"
14 #include "gtest/gtest.h"
15
16 using namespace llvm;
17 using namespace llvm::opt;
18
19 enum ID {
20 OPT_INVALID = 0, // This is not an option ID.
21 #define OPTION(PREFIX, NAME, ID, KIND, GROUP, ALIAS, ALIASARGS, FLAGS, PARAM, \
22 HELPTEXT, METAVAR) OPT_##ID,
23 #include "Opts.inc"
24 LastOption
25 #undef OPTION
26 };
27
28 #define PREFIX(NAME, VALUE) const char *const NAME[] = VALUE;
29 #include "Opts.inc"
30 #undef PREFIX
31
32 enum OptionFlags {
33 OptFlag1 = (1 << 4),
34 OptFlag2 = (1 << 5),
35 OptFlag3 = (1 << 6)
36 };
37
38 static const OptTable::Info InfoTable[] = {
39 #define OPTION(PREFIX, NAME, ID, KIND, GROUP, ALIAS, ALIASARGS, FLAGS, PARAM, \
40 HELPTEXT, METAVAR) \
41 { PREFIX, NAME, HELPTEXT, METAVAR, OPT_##ID, Option::KIND##Class, PARAM, \
42 FLAGS, OPT_##GROUP, OPT_##ALIAS, ALIASARGS },
43 #include "Opts.inc"
44 #undef OPTION
45 };
46
47 namespace {
48 class TestOptTable : public OptTable {
49 public:
TestOptTable(bool IgnoreCase=false)50 TestOptTable(bool IgnoreCase = false)
51 : OptTable(InfoTable, IgnoreCase) {}
52 };
53 }
54
55 const char *Args[] = {
56 "-A",
57 "-Bhi",
58 "--C=desu",
59 "-C", "bye",
60 "-D,adena",
61 "-E", "apple", "bloom",
62 "-Fblarg",
63 "-F", "42",
64 "-Gchuu", "2"
65 };
66
TEST(Option,OptionParsing)67 TEST(Option, OptionParsing) {
68 TestOptTable T;
69 unsigned MAI, MAC;
70 InputArgList AL = T.ParseArgs(Args, MAI, MAC);
71
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));
80
81 // Check the values.
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]);
92
93 // Check the help text.
94 std::string Help;
95 raw_string_ostream RSO(Help);
96 T.PrintHelp(RSO, "test", "title!");
97 EXPECT_NE(std::string::npos, Help.find("-A"));
98
99 // Test aliases.
100 arg_iterator Cs = AL.filtered_begin(OPT_C);
101 ASSERT_NE(AL.filtered_end(), Cs);
102 EXPECT_EQ("desu", StringRef((*Cs)->getValue()));
103 ArgStringList ASL;
104 (*Cs)->render(AL, ASL);
105 ASSERT_EQ(2u, ASL.size());
106 EXPECT_EQ("-C", StringRef(ASL[0]));
107 EXPECT_EQ("desu", StringRef(ASL[1]));
108 }
109
TEST(Option,ParseWithFlagExclusions)110 TEST(Option, ParseWithFlagExclusions) {
111 TestOptTable T;
112 unsigned MAI, MAC;
113
114 // Exclude flag3 to avoid parsing as OPT_SLASH_C.
115 InputArgList AL = T.ParseArgs(Args, MAI, MAC,
116 /*FlagsToInclude=*/0,
117 /*FlagsToExclude=*/OptFlag3);
118 EXPECT_TRUE(AL.hasArg(OPT_A));
119 EXPECT_TRUE(AL.hasArg(OPT_C));
120 EXPECT_FALSE(AL.hasArg(OPT_SLASH_C));
121
122 // Exclude flag1 to avoid parsing as OPT_C.
123 AL = T.ParseArgs(Args, MAI, MAC,
124 /*FlagsToInclude=*/0,
125 /*FlagsToExclude=*/OptFlag1);
126 EXPECT_TRUE(AL.hasArg(OPT_B));
127 EXPECT_FALSE(AL.hasArg(OPT_C));
128 EXPECT_TRUE(AL.hasArg(OPT_SLASH_C));
129
130 const char *NewArgs[] = { "/C", "foo", "--C=bar" };
131 AL = T.ParseArgs(NewArgs, MAI, MAC);
132 EXPECT_TRUE(AL.hasArg(OPT_SLASH_C));
133 EXPECT_TRUE(AL.hasArg(OPT_C));
134 EXPECT_EQ("foo", AL.getLastArgValue(OPT_SLASH_C));
135 EXPECT_EQ("bar", AL.getLastArgValue(OPT_C));
136 }
137
TEST(Option,ParseAliasInGroup)138 TEST(Option, ParseAliasInGroup) {
139 TestOptTable T;
140 unsigned MAI, MAC;
141
142 const char *MyArgs[] = { "-I" };
143 InputArgList AL = T.ParseArgs(MyArgs, MAI, MAC);
144 EXPECT_TRUE(AL.hasArg(OPT_H));
145 }
146
TEST(Option,AliasArgs)147 TEST(Option, AliasArgs) {
148 TestOptTable T;
149 unsigned MAI, MAC;
150
151 const char *MyArgs[] = { "-J", "-Joo" };
152 InputArgList AL = T.ParseArgs(MyArgs, MAI, MAC);
153 EXPECT_TRUE(AL.hasArg(OPT_B));
154 EXPECT_EQ("foo", AL.getAllArgValues(OPT_B)[0]);
155 EXPECT_EQ("bar", AL.getAllArgValues(OPT_B)[1]);
156 }
157
TEST(Option,IgnoreCase)158 TEST(Option, IgnoreCase) {
159 TestOptTable T(true);
160 unsigned MAI, MAC;
161
162 const char *MyArgs[] = { "-a", "-joo" };
163 InputArgList AL = T.ParseArgs(MyArgs, MAI, MAC);
164 EXPECT_TRUE(AL.hasArg(OPT_A));
165 EXPECT_TRUE(AL.hasArg(OPT_B));
166 }
167
TEST(Option,DoNotIgnoreCase)168 TEST(Option, DoNotIgnoreCase) {
169 TestOptTable T;
170 unsigned MAI, MAC;
171
172 const char *MyArgs[] = { "-a", "-joo" };
173 InputArgList AL = T.ParseArgs(MyArgs, MAI, MAC);
174 EXPECT_FALSE(AL.hasArg(OPT_A));
175 EXPECT_FALSE(AL.hasArg(OPT_B));
176 }
177
TEST(Option,SlurpEmpty)178 TEST(Option, SlurpEmpty) {
179 TestOptTable T;
180 unsigned MAI, MAC;
181
182 const char *MyArgs[] = { "-A", "-slurp" };
183 InputArgList AL = T.ParseArgs(MyArgs, MAI, MAC);
184 EXPECT_TRUE(AL.hasArg(OPT_A));
185 EXPECT_TRUE(AL.hasArg(OPT_Slurp));
186 EXPECT_EQ(0U, AL.getAllArgValues(OPT_Slurp).size());
187 }
188
TEST(Option,Slurp)189 TEST(Option, Slurp) {
190 TestOptTable T;
191 unsigned MAI, MAC;
192
193 const char *MyArgs[] = { "-A", "-slurp", "-B", "--", "foo" };
194 InputArgList AL = T.ParseArgs(MyArgs, MAI, MAC);
195 EXPECT_EQ(AL.size(), 2U);
196 EXPECT_TRUE(AL.hasArg(OPT_A));
197 EXPECT_FALSE(AL.hasArg(OPT_B));
198 EXPECT_TRUE(AL.hasArg(OPT_Slurp));
199 EXPECT_EQ(3U, AL.getAllArgValues(OPT_Slurp).size());
200 EXPECT_EQ("-B", AL.getAllArgValues(OPT_Slurp)[0]);
201 EXPECT_EQ("--", AL.getAllArgValues(OPT_Slurp)[1]);
202 EXPECT_EQ("foo", AL.getAllArgValues(OPT_Slurp)[2]);
203 }
204
TEST(Option,SlurpJoinedEmpty)205 TEST(Option, SlurpJoinedEmpty) {
206 TestOptTable T;
207 unsigned MAI, MAC;
208
209 const char *MyArgs[] = { "-A", "-slurpjoined" };
210 InputArgList AL = T.ParseArgs(MyArgs, MAI, MAC);
211 EXPECT_TRUE(AL.hasArg(OPT_A));
212 EXPECT_TRUE(AL.hasArg(OPT_SlurpJoined));
213 EXPECT_EQ(AL.getAllArgValues(OPT_SlurpJoined).size(), 0U);
214 }
215
TEST(Option,SlurpJoinedOneJoined)216 TEST(Option, SlurpJoinedOneJoined) {
217 TestOptTable T;
218 unsigned MAI, MAC;
219
220 const char *MyArgs[] = { "-A", "-slurpjoinedfoo" };
221 InputArgList AL = T.ParseArgs(MyArgs, MAI, MAC);
222 EXPECT_TRUE(AL.hasArg(OPT_A));
223 EXPECT_TRUE(AL.hasArg(OPT_SlurpJoined));
224 EXPECT_EQ(AL.getAllArgValues(OPT_SlurpJoined).size(), 1U);
225 EXPECT_EQ(AL.getAllArgValues(OPT_SlurpJoined)[0], "foo");
226 }
227
TEST(Option,SlurpJoinedAndSeparate)228 TEST(Option, SlurpJoinedAndSeparate) {
229 TestOptTable T;
230 unsigned MAI, MAC;
231
232 const char *MyArgs[] = { "-A", "-slurpjoinedfoo", "bar", "baz" };
233 InputArgList AL = T.ParseArgs(MyArgs, MAI, MAC);
234 EXPECT_TRUE(AL.hasArg(OPT_A));
235 EXPECT_TRUE(AL.hasArg(OPT_SlurpJoined));
236 EXPECT_EQ(3U, AL.getAllArgValues(OPT_SlurpJoined).size());
237 EXPECT_EQ("foo", AL.getAllArgValues(OPT_SlurpJoined)[0]);
238 EXPECT_EQ("bar", AL.getAllArgValues(OPT_SlurpJoined)[1]);
239 EXPECT_EQ("baz", AL.getAllArgValues(OPT_SlurpJoined)[2]);
240 }
241
TEST(Option,SlurpJoinedButSeparate)242 TEST(Option, SlurpJoinedButSeparate) {
243 TestOptTable T;
244 unsigned MAI, MAC;
245
246 const char *MyArgs[] = { "-A", "-slurpjoined", "foo", "bar", "baz" };
247 InputArgList AL = T.ParseArgs(MyArgs, MAI, MAC);
248 EXPECT_TRUE(AL.hasArg(OPT_A));
249 EXPECT_TRUE(AL.hasArg(OPT_SlurpJoined));
250 EXPECT_EQ(3U, AL.getAllArgValues(OPT_SlurpJoined).size());
251 EXPECT_EQ("foo", AL.getAllArgValues(OPT_SlurpJoined)[0]);
252 EXPECT_EQ("bar", AL.getAllArgValues(OPT_SlurpJoined)[1]);
253 EXPECT_EQ("baz", AL.getAllArgValues(OPT_SlurpJoined)[2]);
254 }
255
TEST(Option,FlagAliasToJoined)256 TEST(Option, FlagAliasToJoined) {
257 TestOptTable T;
258 unsigned MAI, MAC;
259
260 // Check that a flag alias provides an empty argument to a joined option.
261 const char *MyArgs[] = { "-K" };
262 InputArgList AL = T.ParseArgs(MyArgs, MAI, MAC);
263 EXPECT_EQ(AL.size(), 1U);
264 EXPECT_TRUE(AL.hasArg(OPT_B));
265 EXPECT_EQ(1U, AL.getAllArgValues(OPT_B).size());
266 EXPECT_EQ("", AL.getAllArgValues(OPT_B)[0]);
267 }
268