brintos

brintos / llvm-project-archived public Read only

0
0
Text · 10.2 KiB · d4744c9 Raw
266 lines · cpp
1//===- unittest/Support/OptionParsingTest.cpp - OptTable tests ------------===//2//3// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.4// See https://llvm.org/LICENSE.txt for license information.5// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception6//7//===----------------------------------------------------------------------===//8 9#include "llvm/ADT/STLExtras.h"10#include "llvm/Option/Arg.h"11#include "llvm/Option/ArgList.h"12#include "llvm/Option/OptTable.h"13#include "llvm/Option/Option.h"14#include "llvm/Support/raw_ostream.h"15#include "gtest/gtest.h"16 17using namespace llvm;18using namespace llvm::opt;19 20#if defined(__clang__)21#pragma clang diagnostic ignored "-Wdeprecated-declarations"22#endif23 24namespace {25enum ID {26  OPT_INVALID = 0,27#define OPTION(PREFIXES, NAME, ID, KIND, GROUP, ALIAS, ALIASARGS, FLAGS,       \28               VISIBILITY, PARAM, HELPTEXT, HELPTEXTSFORVARIANTS, METAVAR,     \29               VALUES, SUBCOMMANDIDS_OFFSET)                                   \30  OPT_##ID,31#include "SubCommandOpts.inc"32#undef OPTION33};34#define OPTTABLE_STR_TABLE_CODE35#include "SubCommandOpts.inc"36#undef OPTTABLE_STR_TABLE_CODE37 38#define OPTTABLE_PREFIXES_TABLE_CODE39#include "SubCommandOpts.inc"40#undef OPTTABLE_PREFIXES_TABLE_CODE41 42#define OPTTABLE_SUBCOMMAND_IDS_TABLE_CODE43#include "SubCommandOpts.inc"44#undef OPTTABLE_SUBCOMMAND_IDS_TABLE_CODE45 46#define OPTTABLE_SUBCOMMANDS_CODE47#include "SubCommandOpts.inc"48#undef OPTTABLE_SUBCOMMANDS_CODE49 50static constexpr OptTable::Info InfoTable[] = {51#define OPTION(...) LLVM_CONSTRUCT_OPT_INFO(__VA_ARGS__),52#include "SubCommandOpts.inc"53#undef OPTION54};55 56class TestOptSubCommandTable : public GenericOptTable {57public:58  TestOptSubCommandTable(bool IgnoreCase = false)59      : GenericOptTable(OptionStrTable, OptionPrefixesTable, InfoTable,60                        /*IgnoreCase=*/false, OptionSubCommands,61                        OptionSubCommandIDsTable) {}62};63 64// Test fixture65template <typename T> class OptSubCommandTableTest : public ::testing::Test {};66 67// Test both precomputed and computed OptTables with the same suite of tests.68using OptSubCommandTableTestTypes = ::testing::Types<TestOptSubCommandTable>;69 70TYPED_TEST_SUITE(OptSubCommandTableTest, OptSubCommandTableTestTypes, );71 72TYPED_TEST(OptSubCommandTableTest, SubCommandParsing) {73  TypeParam T;74  unsigned MAI, MAC;75 76  std::string ErrMsg;77  raw_string_ostream RSO1(ErrMsg);78 79  auto HandleMultipleSubcommands = [&](ArrayRef<StringRef> SubCommands) {80    ErrMsg.clear();81    RSO1 << "Multiple subcommands passed\n";82    for (auto SC : SubCommands)83      RSO1 << "\n" << SC;84  };85 86  auto HandleOtherPositionals = [&](ArrayRef<StringRef> Positionals) {87    ErrMsg.clear();88    RSO1 << "Unregistered positionals passed\n";89    for (auto SC : Positionals)90      RSO1 << "\n" << SC;91  };92 93  {94    // Test case 1: Toplevel option, no subcommand95    const char *Args[] = {"-version"};96    InputArgList AL = T.ParseArgs(Args, MAI, MAC);97    EXPECT_TRUE(AL.hasArg(OPT_version));98    StringRef SC = AL.getSubCommand(99        T.getSubCommands(), HandleMultipleSubcommands, HandleOtherPositionals);100    EXPECT_TRUE(SC.empty());101    EXPECT_FALSE(AL.hasArg(OPT_uppercase));102    EXPECT_FALSE(AL.hasArg(OPT_lowercase));103  }104 105  {106    // Test case 2: Subcommand 'foo' with its valid options107    const char *Args[] = {"foo", "-uppercase"};108    InputArgList AL = T.ParseArgs(Args, MAI, MAC);109    StringRef SC = AL.getSubCommand(110        T.getSubCommands(), HandleMultipleSubcommands, HandleOtherPositionals);111    EXPECT_EQ(SC, "foo");112    EXPECT_TRUE(AL.hasArg(OPT_uppercase));113    EXPECT_FALSE(AL.hasArg(OPT_lowercase));114    EXPECT_FALSE(AL.hasArg(OPT_version));115    EXPECT_EQ(std::string::npos, ErrMsg.find("Multiple subcommands passed"))116        << "Did not expect error message as this is a valid use case.";117    EXPECT_EQ(std::string::npos, ErrMsg.find("Unregistered positionals passed"))118        << "Did not expect error message as this is a valid use case.";119  }120 121  {122    // Test case 3: Check valid use of subcommand which follows a valid123    // subcommand option.124    const char *Args[] = {"-uppercase", "foo"};125    InputArgList AL = T.ParseArgs(Args, MAI, MAC);126    StringRef SC = AL.getSubCommand(127        T.getSubCommands(), HandleMultipleSubcommands, HandleOtherPositionals);128    EXPECT_EQ(SC, "foo");129    EXPECT_TRUE(AL.hasArg(OPT_uppercase));130    EXPECT_FALSE(AL.hasArg(OPT_lowercase));131    EXPECT_FALSE(AL.hasArg(OPT_version));132    EXPECT_EQ(std::string::npos, ErrMsg.find("Multiple subcommands passed"))133        << "Did not expect error message as this is a valid use case.";134    EXPECT_EQ(std::string::npos, ErrMsg.find("Unregistered positionals passed"))135        << "Did not expect error message as this is a valid use case.";136  }137 138  {139    // Test case 4: Check invalid use of passing multiple subcommands.140    const char *Args[] = {"-uppercase", "foo", "bar"};141    InputArgList AL = T.ParseArgs(Args, MAI, MAC);142    StringRef SC = AL.getSubCommand(143        T.getSubCommands(), HandleMultipleSubcommands, HandleOtherPositionals);144    // No valid subcommand should be returned as this is an invalid invocation.145    EXPECT_TRUE(SC.empty());146    // Expect the multiple subcommands error message.147    EXPECT_NE(std::string::npos, ErrMsg.find("Multiple subcommands passed"));148    EXPECT_NE(std::string::npos, ErrMsg.find("foo"));149    EXPECT_NE(std::string::npos, ErrMsg.find("bar"));150    EXPECT_EQ(std::string::npos, ErrMsg.find("Unregistered positionals passed"))151        << "Did not expect error message as this is a valid use case.";152  }153 154  {155    // Test case 5: Check invalid use of passing unregistered subcommands.156    const char *Args[] = {"foobar"};157    InputArgList AL = T.ParseArgs(Args, MAI, MAC);158    StringRef SC = AL.getSubCommand(159        T.getSubCommands(), HandleMultipleSubcommands, HandleOtherPositionals);160    // No valid subcommand should be returned as this is an invalid invocation.161    EXPECT_TRUE(SC.empty());162    // Expect the unregistered subcommands error message.163    EXPECT_NE(std::string::npos,164              ErrMsg.find("Unregistered positionals passed"));165    EXPECT_NE(std::string::npos, ErrMsg.find("foobar"));166  }167 168  {169    // Test case 6: Check invalid use of a valid subcommand which follows a170    // valid subcommand option but the option is not registered with the given171    // subcommand.172    const char *Args[] = {"-lowercase", "bar"};173    InputArgList AL = T.ParseArgs(Args, MAI, MAC);174    StringRef SC = AL.getSubCommand(175        T.getSubCommands(), HandleMultipleSubcommands, HandleOtherPositionals);176    auto HandleSubCommandArg = [&](ID OptionType) {177      if (!AL.hasArg(OptionType))178        return false;179      auto O = T.getOption(OptionType);180      if (!O.isRegisteredSC(SC)) {181        ErrMsg.clear();182        RSO1 << "Option [" << O.getName() << "] is not valid for SubCommand ["183             << SC << "]\n";184        return false;185      }186      return true;187    };188    EXPECT_EQ(SC, "bar");                  // valid subcommand189    EXPECT_TRUE(AL.hasArg(OPT_lowercase)); // valid option190    EXPECT_FALSE(HandleSubCommandArg(OPT_lowercase));191    EXPECT_NE(192        std::string::npos,193        ErrMsg.find("Option [lowercase] is not valid for SubCommand [bar]"));194  }195 196  {197    // Test case 7: Check valid use of a valid subcommand following more198    // positional arguments.199    const char *Args[] = {"bar", "input"};200    InputArgList AL = T.ParseArgs(Args, MAI, MAC);201    StringRef SC = AL.getSubCommand(202        T.getSubCommands(), HandleMultipleSubcommands, HandleOtherPositionals);203    EXPECT_EQ(SC, "bar"); // valid subcommand204    EXPECT_NE(std::string::npos,205              ErrMsg.find("Unregistered positionals passed"));206    EXPECT_NE(std::string::npos, ErrMsg.find("input"));207  }208}209 210TYPED_TEST(OptSubCommandTableTest, SubCommandHelp) {211  TypeParam T;212  std::string Help;213  raw_string_ostream RSO(Help);214 215  // Toplevel help216  T.printHelp(RSO, "Test Usage String", "OverviewString");217  EXPECT_NE(std::string::npos, Help.find("OVERVIEW:"));218  EXPECT_NE(std::string::npos, Help.find("OverviewString"));219  EXPECT_NE(std::string::npos, Help.find("USAGE:"));220  EXPECT_NE(std::string::npos, Help.find("Test Usage String"));221  EXPECT_NE(std::string::npos, Help.find("SUBCOMMANDS:"));222  EXPECT_NE(std::string::npos, Help.find("foo"));223  EXPECT_NE(std::string::npos, Help.find("bar"));224  EXPECT_NE(std::string::npos, Help.find("HelpText for SubCommand foo."));225  EXPECT_NE(std::string::npos, Help.find("HelpText for SubCommand bar."));226  EXPECT_NE(std::string::npos, Help.find("OPTIONS:"));227  EXPECT_NE(std::string::npos, Help.find("--help"));228  EXPECT_NE(std::string::npos, Help.find("-version"));229  // uppercase is not a global option and should not be shown.230  EXPECT_EQ(std::string::npos, Help.find("-uppercase"));231 232  // Help for subcommand foo233  Help.clear();234  StringRef SC1 = "foo";235  T.printHelp(RSO, "Test Usage String", "OverviewString", false, false,236              Visibility(), SC1);237  EXPECT_NE(std::string::npos, Help.find("OVERVIEW:"));238  EXPECT_NE(std::string::npos, Help.find("OverviewString"));239  // SubCommand "foo" definition for tablegen has NO dedicated usage string so240  // not expected to see USAGE.241  EXPECT_EQ(std::string::npos, Help.find("USAGE:"));242  EXPECT_NE(std::string::npos, Help.find("HelpText for SubCommand foo."));243  EXPECT_NE(std::string::npos, Help.find("-uppercase"));244  EXPECT_NE(std::string::npos, Help.find("-lowercase"));245  EXPECT_EQ(std::string::npos, Help.find("-version"));246  EXPECT_EQ(std::string::npos, Help.find("SUBCOMMANDS:"));247 248  // Help for subcommand bar249  Help.clear();250  StringRef SC2 = "bar";251  T.printHelp(RSO, "Test Usage String", "OverviewString", false, false,252              Visibility(), SC2);253  EXPECT_NE(std::string::npos, Help.find("OVERVIEW:"));254  EXPECT_NE(std::string::npos, Help.find("OverviewString"));255  // SubCommand "bar" definition for tablegen has a dedicated usage string.256  EXPECT_NE(std::string::npos, Help.find("USAGE:"));257  EXPECT_NE(std::string::npos, Help.find("Subcommand bar <options>"));258  EXPECT_NE(std::string::npos, Help.find("HelpText for SubCommand bar."));259  EXPECT_NE(std::string::npos, Help.find("-uppercase"));260  // lowercase is not an option for bar and should not be shown.261  EXPECT_EQ(std::string::npos, Help.find("-lowercase"));262  // version is a global option and should not be shown.263  EXPECT_EQ(std::string::npos, Help.find("-version"));264}265} // end anonymous namespace266