| //===- unittest/Support/OptionParsingTest.cpp - OptTable tests ------------===// |
| // |
| // The LLVM Compiler Infrastructure |
| // |
| // This file is distributed under the University of Illinois Open Source |
| // License. See LICENSE.TXT for details. |
| // |
| //===----------------------------------------------------------------------===// |
| |
| #include "llvm/ADT/STLExtras.h" |
| #include "llvm/Option/Arg.h" |
| #include "llvm/Option/ArgList.h" |
| #include "llvm/Option/Option.h" |
| #include "gtest/gtest.h" |
| |
| using namespace llvm; |
| using namespace llvm::opt; |
| |
| enum ID { |
| OPT_INVALID = 0, // This is not an option ID. |
| #define OPTION(PREFIX, NAME, ID, KIND, GROUP, ALIAS, ALIASARGS, FLAGS, PARAM, \ |
| HELPTEXT, METAVAR, VALUES) \ |
| OPT_##ID, |
| #include "Opts.inc" |
| LastOption |
| #undef OPTION |
| }; |
| |
| #define PREFIX(NAME, VALUE) const char *const NAME[] = VALUE; |
| #include "Opts.inc" |
| #undef PREFIX |
| |
| enum OptionFlags { |
| OptFlag1 = (1 << 4), |
| OptFlag2 = (1 << 5), |
| OptFlag3 = (1 << 6) |
| }; |
| |
| static const OptTable::Info InfoTable[] = { |
| #define OPTION(PREFIX, NAME, ID, KIND, GROUP, ALIAS, ALIASARGS, FLAGS, PARAM, \ |
| HELPTEXT, METAVAR, VALUES) \ |
| {PREFIX, NAME, HELPTEXT, METAVAR, OPT_##ID, Option::KIND##Class, \ |
| PARAM, FLAGS, OPT_##GROUP, OPT_##ALIAS, ALIASARGS, VALUES}, |
| #include "Opts.inc" |
| #undef OPTION |
| }; |
| |
| namespace { |
| class TestOptTable : public OptTable { |
| public: |
| TestOptTable(bool IgnoreCase = false) |
| : OptTable(InfoTable, IgnoreCase) {} |
| }; |
| } |
| |
| const char *Args[] = { |
| "-A", |
| "-Bhi", |
| "--C=desu", |
| "-C", "bye", |
| "-D,adena", |
| "-E", "apple", "bloom", |
| "-Fblarg", |
| "-F", "42", |
| "-Gchuu", "2" |
| }; |
| |
| TEST(Option, OptionParsing) { |
| TestOptTable T; |
| unsigned MAI, MAC; |
| InputArgList AL = T.ParseArgs(Args, MAI, MAC); |
| |
| // Check they all exist. |
| EXPECT_TRUE(AL.hasArg(OPT_A)); |
| EXPECT_TRUE(AL.hasArg(OPT_B)); |
| EXPECT_TRUE(AL.hasArg(OPT_C)); |
| EXPECT_TRUE(AL.hasArg(OPT_D)); |
| EXPECT_TRUE(AL.hasArg(OPT_E)); |
| EXPECT_TRUE(AL.hasArg(OPT_F)); |
| EXPECT_TRUE(AL.hasArg(OPT_G)); |
| |
| // Check the values. |
| EXPECT_EQ("hi", AL.getLastArgValue(OPT_B)); |
| EXPECT_EQ("bye", AL.getLastArgValue(OPT_C)); |
| EXPECT_EQ("adena", AL.getLastArgValue(OPT_D)); |
| std::vector<std::string> Es = AL.getAllArgValues(OPT_E); |
| EXPECT_EQ("apple", Es[0]); |
| EXPECT_EQ("bloom", Es[1]); |
| EXPECT_EQ("42", AL.getLastArgValue(OPT_F)); |
| std::vector<std::string> Gs = AL.getAllArgValues(OPT_G); |
| EXPECT_EQ("chuu", Gs[0]); |
| EXPECT_EQ("2", Gs[1]); |
| |
| // Check the help text. |
| std::string Help; |
| raw_string_ostream RSO(Help); |
| T.PrintHelp(RSO, "test", "title!"); |
| EXPECT_NE(std::string::npos, Help.find("-A")); |
| |
| // Test aliases. |
| auto Cs = AL.filtered(OPT_C); |
| ASSERT_NE(Cs.begin(), Cs.end()); |
| EXPECT_EQ("desu", StringRef((*Cs.begin())->getValue())); |
| ArgStringList ASL; |
| (*Cs.begin())->render(AL, ASL); |
| ASSERT_EQ(2u, ASL.size()); |
| EXPECT_EQ("-C", StringRef(ASL[0])); |
| EXPECT_EQ("desu", StringRef(ASL[1])); |
| } |
| |
| TEST(Option, ParseWithFlagExclusions) { |
| TestOptTable T; |
| unsigned MAI, MAC; |
| |
| // Exclude flag3 to avoid parsing as OPT_SLASH_C. |
| InputArgList AL = T.ParseArgs(Args, MAI, MAC, |
| /*FlagsToInclude=*/0, |
| /*FlagsToExclude=*/OptFlag3); |
| EXPECT_TRUE(AL.hasArg(OPT_A)); |
| EXPECT_TRUE(AL.hasArg(OPT_C)); |
| EXPECT_FALSE(AL.hasArg(OPT_SLASH_C)); |
| |
| // Exclude flag1 to avoid parsing as OPT_C. |
| AL = T.ParseArgs(Args, MAI, MAC, |
| /*FlagsToInclude=*/0, |
| /*FlagsToExclude=*/OptFlag1); |
| EXPECT_TRUE(AL.hasArg(OPT_B)); |
| EXPECT_FALSE(AL.hasArg(OPT_C)); |
| EXPECT_TRUE(AL.hasArg(OPT_SLASH_C)); |
| |
| const char *NewArgs[] = { "/C", "foo", "--C=bar" }; |
| AL = T.ParseArgs(NewArgs, MAI, MAC); |
| EXPECT_TRUE(AL.hasArg(OPT_SLASH_C)); |
| EXPECT_TRUE(AL.hasArg(OPT_C)); |
| EXPECT_EQ("foo", AL.getLastArgValue(OPT_SLASH_C)); |
| EXPECT_EQ("bar", AL.getLastArgValue(OPT_C)); |
| } |
| |
| TEST(Option, ParseAliasInGroup) { |
| TestOptTable T; |
| unsigned MAI, MAC; |
| |
| const char *MyArgs[] = { "-I" }; |
| InputArgList AL = T.ParseArgs(MyArgs, MAI, MAC); |
| EXPECT_TRUE(AL.hasArg(OPT_H)); |
| } |
| |
| TEST(Option, AliasArgs) { |
| TestOptTable T; |
| unsigned MAI, MAC; |
| |
| const char *MyArgs[] = { "-J", "-Joo" }; |
| InputArgList AL = T.ParseArgs(MyArgs, MAI, MAC); |
| EXPECT_TRUE(AL.hasArg(OPT_B)); |
| EXPECT_EQ("foo", AL.getAllArgValues(OPT_B)[0]); |
| EXPECT_EQ("bar", AL.getAllArgValues(OPT_B)[1]); |
| } |
| |
| TEST(Option, IgnoreCase) { |
| TestOptTable T(true); |
| unsigned MAI, MAC; |
| |
| const char *MyArgs[] = { "-a", "-joo" }; |
| InputArgList AL = T.ParseArgs(MyArgs, MAI, MAC); |
| EXPECT_TRUE(AL.hasArg(OPT_A)); |
| EXPECT_TRUE(AL.hasArg(OPT_B)); |
| } |
| |
| TEST(Option, DoNotIgnoreCase) { |
| TestOptTable T; |
| unsigned MAI, MAC; |
| |
| const char *MyArgs[] = { "-a", "-joo" }; |
| InputArgList AL = T.ParseArgs(MyArgs, MAI, MAC); |
| EXPECT_FALSE(AL.hasArg(OPT_A)); |
| EXPECT_FALSE(AL.hasArg(OPT_B)); |
| } |
| |
| TEST(Option, SlurpEmpty) { |
| TestOptTable T; |
| unsigned MAI, MAC; |
| |
| const char *MyArgs[] = { "-A", "-slurp" }; |
| InputArgList AL = T.ParseArgs(MyArgs, MAI, MAC); |
| EXPECT_TRUE(AL.hasArg(OPT_A)); |
| EXPECT_TRUE(AL.hasArg(OPT_Slurp)); |
| EXPECT_EQ(0U, AL.getAllArgValues(OPT_Slurp).size()); |
| } |
| |
| TEST(Option, Slurp) { |
| TestOptTable T; |
| unsigned MAI, MAC; |
| |
| const char *MyArgs[] = { "-A", "-slurp", "-B", "--", "foo" }; |
| InputArgList AL = T.ParseArgs(MyArgs, MAI, MAC); |
| EXPECT_EQ(AL.size(), 2U); |
| EXPECT_TRUE(AL.hasArg(OPT_A)); |
| EXPECT_FALSE(AL.hasArg(OPT_B)); |
| EXPECT_TRUE(AL.hasArg(OPT_Slurp)); |
| EXPECT_EQ(3U, AL.getAllArgValues(OPT_Slurp).size()); |
| EXPECT_EQ("-B", AL.getAllArgValues(OPT_Slurp)[0]); |
| EXPECT_EQ("--", AL.getAllArgValues(OPT_Slurp)[1]); |
| EXPECT_EQ("foo", AL.getAllArgValues(OPT_Slurp)[2]); |
| } |
| |
| TEST(Option, SlurpJoinedEmpty) { |
| TestOptTable T; |
| unsigned MAI, MAC; |
| |
| const char *MyArgs[] = { "-A", "-slurpjoined" }; |
| InputArgList AL = T.ParseArgs(MyArgs, MAI, MAC); |
| EXPECT_TRUE(AL.hasArg(OPT_A)); |
| EXPECT_TRUE(AL.hasArg(OPT_SlurpJoined)); |
| EXPECT_EQ(AL.getAllArgValues(OPT_SlurpJoined).size(), 0U); |
| } |
| |
| TEST(Option, SlurpJoinedOneJoined) { |
| TestOptTable T; |
| unsigned MAI, MAC; |
| |
| const char *MyArgs[] = { "-A", "-slurpjoinedfoo" }; |
| InputArgList AL = T.ParseArgs(MyArgs, MAI, MAC); |
| EXPECT_TRUE(AL.hasArg(OPT_A)); |
| EXPECT_TRUE(AL.hasArg(OPT_SlurpJoined)); |
| EXPECT_EQ(AL.getAllArgValues(OPT_SlurpJoined).size(), 1U); |
| EXPECT_EQ(AL.getAllArgValues(OPT_SlurpJoined)[0], "foo"); |
| } |
| |
| TEST(Option, SlurpJoinedAndSeparate) { |
| TestOptTable T; |
| unsigned MAI, MAC; |
| |
| const char *MyArgs[] = { "-A", "-slurpjoinedfoo", "bar", "baz" }; |
| InputArgList AL = T.ParseArgs(MyArgs, MAI, MAC); |
| EXPECT_TRUE(AL.hasArg(OPT_A)); |
| EXPECT_TRUE(AL.hasArg(OPT_SlurpJoined)); |
| EXPECT_EQ(3U, AL.getAllArgValues(OPT_SlurpJoined).size()); |
| EXPECT_EQ("foo", AL.getAllArgValues(OPT_SlurpJoined)[0]); |
| EXPECT_EQ("bar", AL.getAllArgValues(OPT_SlurpJoined)[1]); |
| EXPECT_EQ("baz", AL.getAllArgValues(OPT_SlurpJoined)[2]); |
| } |
| |
| TEST(Option, SlurpJoinedButSeparate) { |
| TestOptTable T; |
| unsigned MAI, MAC; |
| |
| const char *MyArgs[] = { "-A", "-slurpjoined", "foo", "bar", "baz" }; |
| InputArgList AL = T.ParseArgs(MyArgs, MAI, MAC); |
| EXPECT_TRUE(AL.hasArg(OPT_A)); |
| EXPECT_TRUE(AL.hasArg(OPT_SlurpJoined)); |
| EXPECT_EQ(3U, AL.getAllArgValues(OPT_SlurpJoined).size()); |
| EXPECT_EQ("foo", AL.getAllArgValues(OPT_SlurpJoined)[0]); |
| EXPECT_EQ("bar", AL.getAllArgValues(OPT_SlurpJoined)[1]); |
| EXPECT_EQ("baz", AL.getAllArgValues(OPT_SlurpJoined)[2]); |
| } |
| |
| TEST(Option, FlagAliasToJoined) { |
| TestOptTable T; |
| unsigned MAI, MAC; |
| |
| // Check that a flag alias provides an empty argument to a joined option. |
| const char *MyArgs[] = { "-K" }; |
| InputArgList AL = T.ParseArgs(MyArgs, MAI, MAC); |
| EXPECT_EQ(AL.size(), 1U); |
| EXPECT_TRUE(AL.hasArg(OPT_B)); |
| EXPECT_EQ(1U, AL.getAllArgValues(OPT_B).size()); |
| EXPECT_EQ("", AL.getAllArgValues(OPT_B)[0]); |
| } |
| |
| TEST(Option, FindNearest) { |
| TestOptTable T; |
| std::string Nearest; |
| |
| // Options that are too short should not be considered |
| // "near" other short options. |
| EXPECT_GT(T.findNearest("-A", Nearest), 4U); |
| EXPECT_GT(T.findNearest("/C", Nearest), 4U); |
| EXPECT_GT(T.findNearest("--C=foo", Nearest), 4U); |
| |
| // The nearest candidate should mirror the amount of prefix |
| // characters used in the original string. |
| EXPECT_EQ(1U, T.findNearest("-blorb", Nearest)); |
| EXPECT_EQ(Nearest, "-blorp"); |
| EXPECT_EQ(1U, T.findNearest("--blorm", Nearest)); |
| EXPECT_EQ(Nearest, "--blorp"); |
| EXPECT_EQ(1U, T.findNearest("-fjormp", Nearest)); |
| EXPECT_EQ(Nearest, "--fjormp"); |
| |
| // The nearest candidate respects the prefix and value delimiter |
| // of the original string. |
| EXPECT_EQ(1U, T.findNearest("/framb:foo", Nearest)); |
| EXPECT_EQ(Nearest, "/cramb:foo"); |
| |
| // Flags should be included and excluded as specified. |
| EXPECT_EQ(1U, T.findNearest("-doopf", Nearest, /*FlagsToInclude=*/OptFlag2)); |
| EXPECT_EQ(Nearest, "-doopf2"); |
| EXPECT_EQ(1U, T.findNearest("-doopf", Nearest, |
| /*FlagsToInclude=*/0, |
| /*FlagsToExclude=*/OptFlag2)); |
| EXPECT_EQ(Nearest, "-doopf1"); |
| } |
| |
| TEST(DISABLED_Option, FindNearestFIXME) { |
| TestOptTable T; |
| std::string Nearest; |
| |
| // FIXME: Options with joined values should not have those values considered |
| // when calculating distance. The test below would fail if run, but it should |
| // succeed. |
| EXPECT_EQ(1U, T.findNearest("--erbghFoo", Nearest)); |
| EXPECT_EQ(Nearest, "--ermghFoo"); |
| |
| } |