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
16using namespace llvm;
17using namespace llvm::opt;
18
19enum 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
32enum OptionFlags {
33  OptFlag1 = (1 << 4),
34  OptFlag2 = (1 << 5),
35  OptFlag3 = (1 << 6)
36};
37
38static 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
47namespace {
48class TestOptTable : public OptTable {
49public:
50  TestOptTable(bool IgnoreCase = false)
51    : OptTable(InfoTable, IgnoreCase) {}
52};
53}
54
55const 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
67TEST(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
110TEST(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
138TEST(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
147TEST(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
158TEST(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
168TEST(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
178TEST(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
189TEST(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
205TEST(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
216TEST(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
228TEST(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
242TEST(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
256TEST(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