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 // 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 104 // Test aliases. 105 auto Cs = AL.filtered(OPT_C); 106 ASSERT_NE(Cs.begin(), Cs.end()); 107 EXPECT_EQ("desu", StringRef((*Cs.begin())->getValue())); 108 ArgStringList ASL; 109 (*Cs.begin())->render(AL, ASL); 110 ASSERT_EQ(2u, ASL.size()); 111 EXPECT_EQ("-C", StringRef(ASL[0])); 112 EXPECT_EQ("desu", StringRef(ASL[1])); 113 } 114 115 TEST(Option, ParseWithFlagExclusions) { 116 TestOptTable T; 117 unsigned MAI, MAC; 118 119 // Exclude flag3 to avoid parsing as OPT_SLASH_C. 120 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)); 126 127 // Exclude flag1 to avoid parsing as OPT_C. 128 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)); 134 135 const char *NewArgs[] = { "/C", "foo", "--C=bar" }; 136 AL = T.ParseArgs(NewArgs, MAI, MAC); 137 EXPECT_TRUE(AL.hasArg(OPT_SLASH_C)); 138 EXPECT_TRUE(AL.hasArg(OPT_C)); 139 EXPECT_EQ("foo", AL.getLastArgValue(OPT_SLASH_C)); 140 EXPECT_EQ("bar", AL.getLastArgValue(OPT_C)); 141 } 142 143 TEST(Option, ParseAliasInGroup) { 144 TestOptTable T; 145 unsigned MAI, MAC; 146 147 const char *MyArgs[] = { "-I" }; 148 InputArgList AL = T.ParseArgs(MyArgs, MAI, MAC); 149 EXPECT_TRUE(AL.hasArg(OPT_H)); 150 } 151 152 TEST(Option, AliasArgs) { 153 TestOptTable T; 154 unsigned MAI, MAC; 155 156 const char *MyArgs[] = { "-J", "-Joo" }; 157 InputArgList AL = T.ParseArgs(MyArgs, MAI, MAC); 158 EXPECT_TRUE(AL.hasArg(OPT_B)); 159 EXPECT_EQ("foo", AL.getAllArgValues(OPT_B)[0]); 160 EXPECT_EQ("bar", AL.getAllArgValues(OPT_B)[1]); 161 } 162 163 TEST(Option, IgnoreCase) { 164 TestOptTable T(true); 165 unsigned MAI, MAC; 166 167 const char *MyArgs[] = { "-a", "-joo" }; 168 InputArgList AL = T.ParseArgs(MyArgs, MAI, MAC); 169 EXPECT_TRUE(AL.hasArg(OPT_A)); 170 EXPECT_TRUE(AL.hasArg(OPT_B)); 171 } 172 173 TEST(Option, DoNotIgnoreCase) { 174 TestOptTable T; 175 unsigned MAI, MAC; 176 177 const char *MyArgs[] = { "-a", "-joo" }; 178 InputArgList AL = T.ParseArgs(MyArgs, MAI, MAC); 179 EXPECT_FALSE(AL.hasArg(OPT_A)); 180 EXPECT_FALSE(AL.hasArg(OPT_B)); 181 } 182 183 TEST(Option, SlurpEmpty) { 184 TestOptTable T; 185 unsigned MAI, MAC; 186 187 const char *MyArgs[] = { "-A", "-slurp" }; 188 InputArgList AL = T.ParseArgs(MyArgs, MAI, MAC); 189 EXPECT_TRUE(AL.hasArg(OPT_A)); 190 EXPECT_TRUE(AL.hasArg(OPT_Slurp)); 191 EXPECT_EQ(0U, AL.getAllArgValues(OPT_Slurp).size()); 192 } 193 194 TEST(Option, Slurp) { 195 TestOptTable T; 196 unsigned MAI, MAC; 197 198 const char *MyArgs[] = { "-A", "-slurp", "-B", "--", "foo" }; 199 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)); 204 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]); 208 } 209 210 TEST(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 221 TEST(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 233 TEST(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 247 TEST(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 261 TEST(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" }; 267 InputArgList AL = T.ParseArgs(MyArgs, MAI, MAC); 268 EXPECT_EQ(AL.size(), 1U); 269 EXPECT_TRUE(AL.hasArg(OPT_B)); 270 EXPECT_EQ(1U, AL.getAllArgValues(OPT_B).size()); 271 EXPECT_EQ("", AL.getAllArgValues(OPT_B)[0]); 272 } 273 274 TEST(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"); 290 EXPECT_EQ(1U, T.findNearest("-fjormp", Nearest)); 291 EXPECT_EQ(Nearest, "--fjormp"); 292 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 307 TEST(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 } 318