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, VALUES)                                      \
23   OPT_##ID,
24 #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 
33 enum OptionFlags {
34   OptFlag1 = (1 << 4),
35   OptFlag2 = (1 << 5),
36   OptFlag3 = (1 << 6)
37 };
38 
39 static const OptTable::Info InfoTable[] = {
40 #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},
44 #include "Opts.inc"
45 #undef OPTION
46 };
47 
48 namespace {
49 class TestOptTable : public OptTable {
50 public:
51   TestOptTable(bool IgnoreCase = false)
52     : OptTable(InfoTable, IgnoreCase) {}
53 };
54 }
55 
56 const 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 
68 TEST(Option, OptionParsing) {
69   TestOptTable T;
70   unsigned MAI, MAC;
71   InputArgList AL = T.ParseArgs(Args, MAI, MAC);
72 
73   // Check they all exist.
74   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));
81 
82   // Check the values.
83   EXPECT_EQ("hi", AL.getLastArgValue(OPT_B));
84   EXPECT_EQ("bye", AL.getLastArgValue(OPT_C));
85   EXPECT_EQ("adena", AL.getLastArgValue(OPT_D));
86   std::vector<std::string> Es = AL.getAllArgValues(OPT_E);
87   EXPECT_EQ("apple", Es[0]);
88   EXPECT_EQ("bloom", Es[1]);
89   EXPECT_EQ("42", AL.getLastArgValue(OPT_F));
90   std::vector<std::string> Gs = AL.getAllArgValues(OPT_G);
91   EXPECT_EQ("chuu", Gs[0]);
92   EXPECT_EQ("2", Gs[1]);
93 
94   // Check the help text.
95   std::string Help;
96   raw_string_ostream RSO(Help);
97   T.PrintHelp(RSO, "test", "title!");
98   EXPECT_NE(std::string::npos, Help.find("-A"));
99 
100   // Test aliases.
101   auto Cs = AL.filtered(OPT_C);
102   ASSERT_NE(Cs.begin(), Cs.end());
103   EXPECT_EQ("desu", StringRef((*Cs.begin())->getValue()));
104   ArgStringList ASL;
105   (*Cs.begin())->render(AL, ASL);
106   ASSERT_EQ(2u, ASL.size());
107   EXPECT_EQ("-C", StringRef(ASL[0]));
108   EXPECT_EQ("desu", StringRef(ASL[1]));
109 }
110 
111 TEST(Option, ParseWithFlagExclusions) {
112   TestOptTable T;
113   unsigned MAI, MAC;
114 
115   // Exclude flag3 to avoid parsing as OPT_SLASH_C.
116   InputArgList AL = T.ParseArgs(Args, MAI, MAC,
117                                 /*FlagsToInclude=*/0,
118                                 /*FlagsToExclude=*/OptFlag3);
119   EXPECT_TRUE(AL.hasArg(OPT_A));
120   EXPECT_TRUE(AL.hasArg(OPT_C));
121   EXPECT_FALSE(AL.hasArg(OPT_SLASH_C));
122 
123   // Exclude flag1 to avoid parsing as OPT_C.
124   AL = T.ParseArgs(Args, MAI, MAC,
125                    /*FlagsToInclude=*/0,
126                    /*FlagsToExclude=*/OptFlag1);
127   EXPECT_TRUE(AL.hasArg(OPT_B));
128   EXPECT_FALSE(AL.hasArg(OPT_C));
129   EXPECT_TRUE(AL.hasArg(OPT_SLASH_C));
130 
131   const char *NewArgs[] = { "/C", "foo", "--C=bar" };
132   AL = T.ParseArgs(NewArgs, MAI, MAC);
133   EXPECT_TRUE(AL.hasArg(OPT_SLASH_C));
134   EXPECT_TRUE(AL.hasArg(OPT_C));
135   EXPECT_EQ("foo", AL.getLastArgValue(OPT_SLASH_C));
136   EXPECT_EQ("bar", AL.getLastArgValue(OPT_C));
137 }
138 
139 TEST(Option, ParseAliasInGroup) {
140   TestOptTable T;
141   unsigned MAI, MAC;
142 
143   const char *MyArgs[] = { "-I" };
144   InputArgList AL = T.ParseArgs(MyArgs, MAI, MAC);
145   EXPECT_TRUE(AL.hasArg(OPT_H));
146 }
147 
148 TEST(Option, AliasArgs) {
149   TestOptTable T;
150   unsigned MAI, MAC;
151 
152   const char *MyArgs[] = { "-J", "-Joo" };
153   InputArgList AL = T.ParseArgs(MyArgs, MAI, MAC);
154   EXPECT_TRUE(AL.hasArg(OPT_B));
155   EXPECT_EQ("foo", AL.getAllArgValues(OPT_B)[0]);
156   EXPECT_EQ("bar", AL.getAllArgValues(OPT_B)[1]);
157 }
158 
159 TEST(Option, IgnoreCase) {
160   TestOptTable T(true);
161   unsigned MAI, MAC;
162 
163   const char *MyArgs[] = { "-a", "-joo" };
164   InputArgList AL = T.ParseArgs(MyArgs, MAI, MAC);
165   EXPECT_TRUE(AL.hasArg(OPT_A));
166   EXPECT_TRUE(AL.hasArg(OPT_B));
167 }
168 
169 TEST(Option, DoNotIgnoreCase) {
170   TestOptTable T;
171   unsigned MAI, MAC;
172 
173   const char *MyArgs[] = { "-a", "-joo" };
174   InputArgList AL = T.ParseArgs(MyArgs, MAI, MAC);
175   EXPECT_FALSE(AL.hasArg(OPT_A));
176   EXPECT_FALSE(AL.hasArg(OPT_B));
177 }
178 
179 TEST(Option, SlurpEmpty) {
180   TestOptTable T;
181   unsigned MAI, MAC;
182 
183   const char *MyArgs[] = { "-A", "-slurp" };
184   InputArgList AL = T.ParseArgs(MyArgs, MAI, MAC);
185   EXPECT_TRUE(AL.hasArg(OPT_A));
186   EXPECT_TRUE(AL.hasArg(OPT_Slurp));
187   EXPECT_EQ(0U, AL.getAllArgValues(OPT_Slurp).size());
188 }
189 
190 TEST(Option, Slurp) {
191   TestOptTable T;
192   unsigned MAI, MAC;
193 
194   const char *MyArgs[] = { "-A", "-slurp", "-B", "--", "foo" };
195   InputArgList AL = T.ParseArgs(MyArgs, MAI, MAC);
196   EXPECT_EQ(AL.size(), 2U);
197   EXPECT_TRUE(AL.hasArg(OPT_A));
198   EXPECT_FALSE(AL.hasArg(OPT_B));
199   EXPECT_TRUE(AL.hasArg(OPT_Slurp));
200   EXPECT_EQ(3U, AL.getAllArgValues(OPT_Slurp).size());
201   EXPECT_EQ("-B", AL.getAllArgValues(OPT_Slurp)[0]);
202   EXPECT_EQ("--", AL.getAllArgValues(OPT_Slurp)[1]);
203   EXPECT_EQ("foo", AL.getAllArgValues(OPT_Slurp)[2]);
204 }
205 
206 TEST(Option, SlurpJoinedEmpty) {
207   TestOptTable T;
208   unsigned MAI, MAC;
209 
210   const char *MyArgs[] = { "-A", "-slurpjoined" };
211   InputArgList AL = T.ParseArgs(MyArgs, MAI, MAC);
212   EXPECT_TRUE(AL.hasArg(OPT_A));
213   EXPECT_TRUE(AL.hasArg(OPT_SlurpJoined));
214   EXPECT_EQ(AL.getAllArgValues(OPT_SlurpJoined).size(), 0U);
215 }
216 
217 TEST(Option, SlurpJoinedOneJoined) {
218   TestOptTable T;
219   unsigned MAI, MAC;
220 
221   const char *MyArgs[] = { "-A", "-slurpjoinedfoo" };
222   InputArgList AL = T.ParseArgs(MyArgs, MAI, MAC);
223   EXPECT_TRUE(AL.hasArg(OPT_A));
224   EXPECT_TRUE(AL.hasArg(OPT_SlurpJoined));
225   EXPECT_EQ(AL.getAllArgValues(OPT_SlurpJoined).size(), 1U);
226   EXPECT_EQ(AL.getAllArgValues(OPT_SlurpJoined)[0], "foo");
227 }
228 
229 TEST(Option, SlurpJoinedAndSeparate) {
230   TestOptTable T;
231   unsigned MAI, MAC;
232 
233   const char *MyArgs[] = { "-A", "-slurpjoinedfoo", "bar", "baz" };
234   InputArgList AL = T.ParseArgs(MyArgs, MAI, MAC);
235   EXPECT_TRUE(AL.hasArg(OPT_A));
236   EXPECT_TRUE(AL.hasArg(OPT_SlurpJoined));
237   EXPECT_EQ(3U, AL.getAllArgValues(OPT_SlurpJoined).size());
238   EXPECT_EQ("foo", AL.getAllArgValues(OPT_SlurpJoined)[0]);
239   EXPECT_EQ("bar", AL.getAllArgValues(OPT_SlurpJoined)[1]);
240   EXPECT_EQ("baz", AL.getAllArgValues(OPT_SlurpJoined)[2]);
241 }
242 
243 TEST(Option, SlurpJoinedButSeparate) {
244   TestOptTable T;
245   unsigned MAI, MAC;
246 
247   const char *MyArgs[] = { "-A", "-slurpjoined", "foo", "bar", "baz" };
248   InputArgList AL = T.ParseArgs(MyArgs, MAI, MAC);
249   EXPECT_TRUE(AL.hasArg(OPT_A));
250   EXPECT_TRUE(AL.hasArg(OPT_SlurpJoined));
251   EXPECT_EQ(3U, AL.getAllArgValues(OPT_SlurpJoined).size());
252   EXPECT_EQ("foo", AL.getAllArgValues(OPT_SlurpJoined)[0]);
253   EXPECT_EQ("bar", AL.getAllArgValues(OPT_SlurpJoined)[1]);
254   EXPECT_EQ("baz", AL.getAllArgValues(OPT_SlurpJoined)[2]);
255 }
256 
257 TEST(Option, FlagAliasToJoined) {
258   TestOptTable T;
259   unsigned MAI, MAC;
260 
261   // Check that a flag alias provides an empty argument to a joined option.
262   const char *MyArgs[] = { "-K" };
263   InputArgList AL = T.ParseArgs(MyArgs, MAI, MAC);
264   EXPECT_EQ(AL.size(), 1U);
265   EXPECT_TRUE(AL.hasArg(OPT_B));
266   EXPECT_EQ(1U, AL.getAllArgValues(OPT_B).size());
267   EXPECT_EQ("", AL.getAllArgValues(OPT_B)[0]);
268 }
269