Home | History | Annotate | Download | only in Option
      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 
    270 TEST(Option, FindNearest) {
    271   TestOptTable T;
    272   std::string Nearest;
    273 
    274   // Options that are too short should not be considered
    275   // "near" other short options.
    276   EXPECT_GT(T.findNearest("-A", Nearest), 4U);
    277   EXPECT_GT(T.findNearest("/C", Nearest), 4U);
    278   EXPECT_GT(T.findNearest("--C=foo", Nearest), 4U);
    279 
    280   // The nearest candidate should mirror the amount of prefix
    281   // characters used in the original string.
    282   EXPECT_EQ(1U, T.findNearest("-blorb", Nearest));
    283   EXPECT_EQ(Nearest, "-blorp");
    284   EXPECT_EQ(1U, T.findNearest("--blorm", Nearest));
    285   EXPECT_EQ(Nearest, "--blorp");
    286   EXPECT_EQ(1U, T.findNearest("-fjormp", Nearest));
    287   EXPECT_EQ(Nearest, "--fjormp");
    288 
    289   // The nearest candidate respects the prefix and value delimiter
    290   // of the original string.
    291   EXPECT_EQ(1U, T.findNearest("/framb:foo", Nearest));
    292   EXPECT_EQ(Nearest, "/cramb:foo");
    293 
    294   // Flags should be included and excluded as specified.
    295   EXPECT_EQ(1U, T.findNearest("-doopf", Nearest, /*FlagsToInclude=*/OptFlag2));
    296   EXPECT_EQ(Nearest, "-doopf2");
    297   EXPECT_EQ(1U, T.findNearest("-doopf", Nearest,
    298                               /*FlagsToInclude=*/0,
    299                               /*FlagsToExclude=*/OptFlag2));
    300   EXPECT_EQ(Nearest, "-doopf1");
    301 }
    302 
    303 TEST(DISABLED_Option, FindNearestFIXME) {
    304   TestOptTable T;
    305   std::string Nearest;
    306 
    307   // FIXME: Options with joined values should not have those values considered
    308   // when calculating distance. The test below would fail if run, but it should
    309   // succeed.
    310   EXPECT_EQ(1U, T.findNearest("--erbghFoo", Nearest));
    311   EXPECT_EQ(Nearest, "--ermghFoo");
    312 
    313 }
    314