Home | History | Annotate | Download | only in Support
      1 //===- llvm/unittest/Support/CommandLineTest.cpp - CommandLine 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/Support/CommandLine.h"
     11 #include "llvm/ADT/STLExtras.h"
     12 #include "llvm/ADT/SmallString.h"
     13 #include "llvm/ADT/Triple.h"
     14 #include "llvm/Config/config.h"
     15 #include "llvm/Support/FileSystem.h"
     16 #include "llvm/Support/InitLLVM.h"
     17 #include "llvm/Support/Path.h"
     18 #include "llvm/Support/Program.h"
     19 #include "llvm/Support/StringSaver.h"
     20 #include "gtest/gtest.h"
     21 #include <fstream>
     22 #include <stdlib.h>
     23 #include <string>
     24 
     25 using namespace llvm;
     26 
     27 namespace {
     28 
     29 class TempEnvVar {
     30  public:
     31   TempEnvVar(const char *name, const char *value)
     32       : name(name) {
     33     const char *old_value = getenv(name);
     34     EXPECT_EQ(nullptr, old_value) << old_value;
     35 #if HAVE_SETENV
     36     setenv(name, value, true);
     37 #else
     38 #   define SKIP_ENVIRONMENT_TESTS
     39 #endif
     40   }
     41 
     42   ~TempEnvVar() {
     43 #if HAVE_SETENV
     44     // Assume setenv and unsetenv come together.
     45     unsetenv(name);
     46 #else
     47     (void)name; // Suppress -Wunused-private-field.
     48 #endif
     49   }
     50 
     51  private:
     52   const char *const name;
     53 };
     54 
     55 template <typename T, typename Base = cl::opt<T>>
     56 class StackOption : public Base {
     57 public:
     58   template <class... Ts>
     59   explicit StackOption(Ts &&... Ms) : Base(std::forward<Ts>(Ms)...) {}
     60 
     61   ~StackOption() override { this->removeArgument(); }
     62 
     63   template <class DT> StackOption<T> &operator=(const DT &V) {
     64     this->setValue(V);
     65     return *this;
     66   }
     67 };
     68 
     69 class StackSubCommand : public cl::SubCommand {
     70 public:
     71   StackSubCommand(StringRef Name,
     72                   StringRef Description = StringRef())
     73       : SubCommand(Name, Description) {}
     74 
     75   StackSubCommand() : SubCommand() {}
     76 
     77   ~StackSubCommand() { unregisterSubCommand(); }
     78 };
     79 
     80 
     81 cl::OptionCategory TestCategory("Test Options", "Description");
     82 TEST(CommandLineTest, ModifyExisitingOption) {
     83   StackOption<int> TestOption("test-option", cl::desc("old description"));
     84 
     85   static const char Description[] = "New description";
     86   static const char ArgString[] = "new-test-option";
     87   static const char ValueString[] = "Integer";
     88 
     89   StringMap<cl::Option *> &Map =
     90       cl::getRegisteredOptions(*cl::TopLevelSubCommand);
     91 
     92   ASSERT_TRUE(Map.count("test-option") == 1) <<
     93     "Could not find option in map.";
     94 
     95   cl::Option *Retrieved = Map["test-option"];
     96   ASSERT_EQ(&TestOption, Retrieved) << "Retrieved wrong option.";
     97 
     98   ASSERT_EQ(&cl::GeneralCategory,Retrieved->Category) <<
     99     "Incorrect default option category.";
    100 
    101   Retrieved->setCategory(TestCategory);
    102   ASSERT_EQ(&TestCategory,Retrieved->Category) <<
    103     "Failed to modify option's option category.";
    104 
    105   Retrieved->setDescription(Description);
    106   ASSERT_STREQ(Retrieved->HelpStr.data(), Description)
    107       << "Changing option description failed.";
    108 
    109   Retrieved->setArgStr(ArgString);
    110   ASSERT_STREQ(ArgString, Retrieved->ArgStr.data())
    111       << "Failed to modify option's Argument string.";
    112 
    113   Retrieved->setValueStr(ValueString);
    114   ASSERT_STREQ(Retrieved->ValueStr.data(), ValueString)
    115       << "Failed to modify option's Value string.";
    116 
    117   Retrieved->setHiddenFlag(cl::Hidden);
    118   ASSERT_EQ(cl::Hidden, TestOption.getOptionHiddenFlag()) <<
    119     "Failed to modify option's hidden flag.";
    120 }
    121 #ifndef SKIP_ENVIRONMENT_TESTS
    122 
    123 const char test_env_var[] = "LLVM_TEST_COMMAND_LINE_FLAGS";
    124 
    125 cl::opt<std::string> EnvironmentTestOption("env-test-opt");
    126 TEST(CommandLineTest, ParseEnvironment) {
    127   TempEnvVar TEV(test_env_var, "-env-test-opt=hello");
    128   EXPECT_EQ("", EnvironmentTestOption);
    129   cl::ParseEnvironmentOptions("CommandLineTest", test_env_var);
    130   EXPECT_EQ("hello", EnvironmentTestOption);
    131 }
    132 
    133 // This test used to make valgrind complain
    134 // ("Conditional jump or move depends on uninitialised value(s)")
    135 //
    136 // Warning: Do not run any tests after this one that try to gain access to
    137 // registered command line options because this will likely result in a
    138 // SEGFAULT. This can occur because the cl::opt in the test below is declared
    139 // on the stack which will be destroyed after the test completes but the
    140 // command line system will still hold a pointer to a deallocated cl::Option.
    141 TEST(CommandLineTest, ParseEnvironmentToLocalVar) {
    142   // Put cl::opt on stack to check for proper initialization of fields.
    143   StackOption<std::string> EnvironmentTestOptionLocal("env-test-opt-local");
    144   TempEnvVar TEV(test_env_var, "-env-test-opt-local=hello-local");
    145   EXPECT_EQ("", EnvironmentTestOptionLocal);
    146   cl::ParseEnvironmentOptions("CommandLineTest", test_env_var);
    147   EXPECT_EQ("hello-local", EnvironmentTestOptionLocal);
    148 }
    149 
    150 #endif  // SKIP_ENVIRONMENT_TESTS
    151 
    152 TEST(CommandLineTest, UseOptionCategory) {
    153   StackOption<int> TestOption2("test-option", cl::cat(TestCategory));
    154 
    155   ASSERT_EQ(&TestCategory,TestOption2.Category) << "Failed to assign Option "
    156                                                   "Category.";
    157 }
    158 
    159 typedef void ParserFunction(StringRef Source, StringSaver &Saver,
    160                             SmallVectorImpl<const char *> &NewArgv,
    161                             bool MarkEOLs);
    162 
    163 void testCommandLineTokenizer(ParserFunction *parse, StringRef Input,
    164                               const char *const Output[], size_t OutputSize) {
    165   SmallVector<const char *, 0> Actual;
    166   BumpPtrAllocator A;
    167   StringSaver Saver(A);
    168   parse(Input, Saver, Actual, /*MarkEOLs=*/false);
    169   EXPECT_EQ(OutputSize, Actual.size());
    170   for (unsigned I = 0, E = Actual.size(); I != E; ++I) {
    171     if (I < OutputSize) {
    172       EXPECT_STREQ(Output[I], Actual[I]);
    173     }
    174   }
    175 }
    176 
    177 TEST(CommandLineTest, TokenizeGNUCommandLine) {
    178   const char Input[] =
    179       "foo\\ bar \"foo bar\" \'foo bar\' 'foo\\\\bar' -DFOO=bar\\(\\) "
    180       "foo\"bar\"baz C:\\\\src\\\\foo.cpp \"C:\\src\\foo.cpp\"";
    181   const char *const Output[] = {
    182       "foo bar",     "foo bar",   "foo bar",          "foo\\bar",
    183       "-DFOO=bar()", "foobarbaz", "C:\\src\\foo.cpp", "C:srcfoo.cpp"};
    184   testCommandLineTokenizer(cl::TokenizeGNUCommandLine, Input, Output,
    185                            array_lengthof(Output));
    186 }
    187 
    188 TEST(CommandLineTest, TokenizeWindowsCommandLine) {
    189   const char Input[] = "a\\b c\\\\d e\\\\\"f g\" h\\\"i j\\\\\\\"k \"lmn\" o pqr "
    190                       "\"st \\\"u\" \\v";
    191   const char *const Output[] = { "a\\b", "c\\\\d", "e\\f g", "h\"i", "j\\\"k",
    192                                  "lmn", "o", "pqr", "st \"u", "\\v" };
    193   testCommandLineTokenizer(cl::TokenizeWindowsCommandLine, Input, Output,
    194                            array_lengthof(Output));
    195 }
    196 
    197 TEST(CommandLineTest, TokenizeConfigFile1) {
    198   const char *Input = "\\";
    199   const char *const Output[] = { "\\" };
    200   testCommandLineTokenizer(cl::tokenizeConfigFile, Input, Output,
    201                            array_lengthof(Output));
    202 }
    203 
    204 TEST(CommandLineTest, TokenizeConfigFile2) {
    205   const char *Input = "\\abc";
    206   const char *const Output[] = { "abc" };
    207   testCommandLineTokenizer(cl::tokenizeConfigFile, Input, Output,
    208                            array_lengthof(Output));
    209 }
    210 
    211 TEST(CommandLineTest, TokenizeConfigFile3) {
    212   const char *Input = "abc\\";
    213   const char *const Output[] = { "abc\\" };
    214   testCommandLineTokenizer(cl::tokenizeConfigFile, Input, Output,
    215                            array_lengthof(Output));
    216 }
    217 
    218 TEST(CommandLineTest, TokenizeConfigFile4) {
    219   const char *Input = "abc\\\n123";
    220   const char *const Output[] = { "abc123" };
    221   testCommandLineTokenizer(cl::tokenizeConfigFile, Input, Output,
    222                            array_lengthof(Output));
    223 }
    224 
    225 TEST(CommandLineTest, TokenizeConfigFile5) {
    226   const char *Input = "abc\\\r\n123";
    227   const char *const Output[] = { "abc123" };
    228   testCommandLineTokenizer(cl::tokenizeConfigFile, Input, Output,
    229                            array_lengthof(Output));
    230 }
    231 
    232 TEST(CommandLineTest, TokenizeConfigFile6) {
    233   const char *Input = "abc\\\n";
    234   const char *const Output[] = { "abc" };
    235   testCommandLineTokenizer(cl::tokenizeConfigFile, Input, Output,
    236                            array_lengthof(Output));
    237 }
    238 
    239 TEST(CommandLineTest, TokenizeConfigFile7) {
    240   const char *Input = "abc\\\r\n";
    241   const char *const Output[] = { "abc" };
    242   testCommandLineTokenizer(cl::tokenizeConfigFile, Input, Output,
    243                            array_lengthof(Output));
    244 }
    245 
    246 TEST(CommandLineTest, TokenizeConfigFile8) {
    247   SmallVector<const char *, 0> Actual;
    248   BumpPtrAllocator A;
    249   StringSaver Saver(A);
    250   cl::tokenizeConfigFile("\\\n", Saver, Actual, /*MarkEOLs=*/false);
    251   EXPECT_TRUE(Actual.empty());
    252 }
    253 
    254 TEST(CommandLineTest, TokenizeConfigFile9) {
    255   SmallVector<const char *, 0> Actual;
    256   BumpPtrAllocator A;
    257   StringSaver Saver(A);
    258   cl::tokenizeConfigFile("\\\r\n", Saver, Actual, /*MarkEOLs=*/false);
    259   EXPECT_TRUE(Actual.empty());
    260 }
    261 
    262 TEST(CommandLineTest, TokenizeConfigFile10) {
    263   const char *Input = "\\\nabc";
    264   const char *const Output[] = { "abc" };
    265   testCommandLineTokenizer(cl::tokenizeConfigFile, Input, Output,
    266                            array_lengthof(Output));
    267 }
    268 
    269 TEST(CommandLineTest, TokenizeConfigFile11) {
    270   const char *Input = "\\\r\nabc";
    271   const char *const Output[] = { "abc" };
    272   testCommandLineTokenizer(cl::tokenizeConfigFile, Input, Output,
    273                            array_lengthof(Output));
    274 }
    275 
    276 TEST(CommandLineTest, AliasesWithArguments) {
    277   static const size_t ARGC = 3;
    278   const char *const Inputs[][ARGC] = {
    279     { "-tool", "-actual=x", "-extra" },
    280     { "-tool", "-actual", "x" },
    281     { "-tool", "-alias=x", "-extra" },
    282     { "-tool", "-alias", "x" }
    283   };
    284 
    285   for (size_t i = 0, e = array_lengthof(Inputs); i < e; ++i) {
    286     StackOption<std::string> Actual("actual");
    287     StackOption<bool> Extra("extra");
    288     StackOption<std::string> Input(cl::Positional);
    289 
    290     cl::alias Alias("alias", llvm::cl::aliasopt(Actual));
    291 
    292     cl::ParseCommandLineOptions(ARGC, Inputs[i]);
    293     EXPECT_EQ("x", Actual);
    294     EXPECT_EQ(0, Input.getNumOccurrences());
    295 
    296     Alias.removeArgument();
    297   }
    298 }
    299 
    300 void testAliasRequired(int argc, const char *const *argv) {
    301   StackOption<std::string> Option("option", cl::Required);
    302   cl::alias Alias("o", llvm::cl::aliasopt(Option));
    303 
    304   cl::ParseCommandLineOptions(argc, argv);
    305   EXPECT_EQ("x", Option);
    306   EXPECT_EQ(1, Option.getNumOccurrences());
    307 
    308   Alias.removeArgument();
    309 }
    310 
    311 TEST(CommandLineTest, AliasRequired) {
    312   const char *opts1[] = { "-tool", "-option=x" };
    313   const char *opts2[] = { "-tool", "-o", "x" };
    314   testAliasRequired(array_lengthof(opts1), opts1);
    315   testAliasRequired(array_lengthof(opts2), opts2);
    316 }
    317 
    318 TEST(CommandLineTest, HideUnrelatedOptions) {
    319   StackOption<int> TestOption1("hide-option-1");
    320   StackOption<int> TestOption2("hide-option-2", cl::cat(TestCategory));
    321 
    322   cl::HideUnrelatedOptions(TestCategory);
    323 
    324   ASSERT_EQ(cl::ReallyHidden, TestOption1.getOptionHiddenFlag())
    325       << "Failed to hide extra option.";
    326   ASSERT_EQ(cl::NotHidden, TestOption2.getOptionHiddenFlag())
    327       << "Hid extra option that should be visable.";
    328 
    329   StringMap<cl::Option *> &Map =
    330       cl::getRegisteredOptions(*cl::TopLevelSubCommand);
    331   ASSERT_EQ(cl::NotHidden, Map["help"]->getOptionHiddenFlag())
    332       << "Hid default option that should be visable.";
    333 }
    334 
    335 cl::OptionCategory TestCategory2("Test Options set 2", "Description");
    336 
    337 TEST(CommandLineTest, HideUnrelatedOptionsMulti) {
    338   StackOption<int> TestOption1("multi-hide-option-1");
    339   StackOption<int> TestOption2("multi-hide-option-2", cl::cat(TestCategory));
    340   StackOption<int> TestOption3("multi-hide-option-3", cl::cat(TestCategory2));
    341 
    342   const cl::OptionCategory *VisibleCategories[] = {&TestCategory,
    343                                                    &TestCategory2};
    344 
    345   cl::HideUnrelatedOptions(makeArrayRef(VisibleCategories));
    346 
    347   ASSERT_EQ(cl::ReallyHidden, TestOption1.getOptionHiddenFlag())
    348       << "Failed to hide extra option.";
    349   ASSERT_EQ(cl::NotHidden, TestOption2.getOptionHiddenFlag())
    350       << "Hid extra option that should be visable.";
    351   ASSERT_EQ(cl::NotHidden, TestOption3.getOptionHiddenFlag())
    352       << "Hid extra option that should be visable.";
    353 
    354   StringMap<cl::Option *> &Map =
    355       cl::getRegisteredOptions(*cl::TopLevelSubCommand);
    356   ASSERT_EQ(cl::NotHidden, Map["help"]->getOptionHiddenFlag())
    357       << "Hid default option that should be visable.";
    358 }
    359 
    360 TEST(CommandLineTest, SetValueInSubcategories) {
    361   cl::ResetCommandLineParser();
    362 
    363   StackSubCommand SC1("sc1", "First subcommand");
    364   StackSubCommand SC2("sc2", "Second subcommand");
    365 
    366   StackOption<bool> TopLevelOpt("top-level", cl::init(false));
    367   StackOption<bool> SC1Opt("sc1", cl::sub(SC1), cl::init(false));
    368   StackOption<bool> SC2Opt("sc2", cl::sub(SC2), cl::init(false));
    369 
    370   EXPECT_FALSE(TopLevelOpt);
    371   EXPECT_FALSE(SC1Opt);
    372   EXPECT_FALSE(SC2Opt);
    373   const char *args[] = {"prog", "-top-level"};
    374   EXPECT_TRUE(
    375       cl::ParseCommandLineOptions(2, args, StringRef(), &llvm::nulls()));
    376   EXPECT_TRUE(TopLevelOpt);
    377   EXPECT_FALSE(SC1Opt);
    378   EXPECT_FALSE(SC2Opt);
    379 
    380   TopLevelOpt = false;
    381 
    382   cl::ResetAllOptionOccurrences();
    383   EXPECT_FALSE(TopLevelOpt);
    384   EXPECT_FALSE(SC1Opt);
    385   EXPECT_FALSE(SC2Opt);
    386   const char *args2[] = {"prog", "sc1", "-sc1"};
    387   EXPECT_TRUE(
    388       cl::ParseCommandLineOptions(3, args2, StringRef(), &llvm::nulls()));
    389   EXPECT_FALSE(TopLevelOpt);
    390   EXPECT_TRUE(SC1Opt);
    391   EXPECT_FALSE(SC2Opt);
    392 
    393   SC1Opt = false;
    394 
    395   cl::ResetAllOptionOccurrences();
    396   EXPECT_FALSE(TopLevelOpt);
    397   EXPECT_FALSE(SC1Opt);
    398   EXPECT_FALSE(SC2Opt);
    399   const char *args3[] = {"prog", "sc2", "-sc2"};
    400   EXPECT_TRUE(
    401       cl::ParseCommandLineOptions(3, args3, StringRef(), &llvm::nulls()));
    402   EXPECT_FALSE(TopLevelOpt);
    403   EXPECT_FALSE(SC1Opt);
    404   EXPECT_TRUE(SC2Opt);
    405 }
    406 
    407 TEST(CommandLineTest, LookupFailsInWrongSubCommand) {
    408   cl::ResetCommandLineParser();
    409 
    410   StackSubCommand SC1("sc1", "First subcommand");
    411   StackSubCommand SC2("sc2", "Second subcommand");
    412 
    413   StackOption<bool> SC1Opt("sc1", cl::sub(SC1), cl::init(false));
    414   StackOption<bool> SC2Opt("sc2", cl::sub(SC2), cl::init(false));
    415 
    416   std::string Errs;
    417   raw_string_ostream OS(Errs);
    418 
    419   const char *args[] = {"prog", "sc1", "-sc2"};
    420   EXPECT_FALSE(cl::ParseCommandLineOptions(3, args, StringRef(), &OS));
    421   OS.flush();
    422   EXPECT_FALSE(Errs.empty());
    423 }
    424 
    425 TEST(CommandLineTest, AddToAllSubCommands) {
    426   cl::ResetCommandLineParser();
    427 
    428   StackSubCommand SC1("sc1", "First subcommand");
    429   StackOption<bool> AllOpt("everywhere", cl::sub(*cl::AllSubCommands),
    430                            cl::init(false));
    431   StackSubCommand SC2("sc2", "Second subcommand");
    432 
    433   const char *args[] = {"prog", "-everywhere"};
    434   const char *args2[] = {"prog", "sc1", "-everywhere"};
    435   const char *args3[] = {"prog", "sc2", "-everywhere"};
    436 
    437   std::string Errs;
    438   raw_string_ostream OS(Errs);
    439 
    440   EXPECT_FALSE(AllOpt);
    441   EXPECT_TRUE(cl::ParseCommandLineOptions(2, args, StringRef(), &OS));
    442   EXPECT_TRUE(AllOpt);
    443 
    444   AllOpt = false;
    445 
    446   cl::ResetAllOptionOccurrences();
    447   EXPECT_FALSE(AllOpt);
    448   EXPECT_TRUE(cl::ParseCommandLineOptions(3, args2, StringRef(), &OS));
    449   EXPECT_TRUE(AllOpt);
    450 
    451   AllOpt = false;
    452 
    453   cl::ResetAllOptionOccurrences();
    454   EXPECT_FALSE(AllOpt);
    455   EXPECT_TRUE(cl::ParseCommandLineOptions(3, args3, StringRef(), &OS));
    456   EXPECT_TRUE(AllOpt);
    457 
    458   // Since all parsing succeeded, the error message should be empty.
    459   OS.flush();
    460   EXPECT_TRUE(Errs.empty());
    461 }
    462 
    463 TEST(CommandLineTest, ReparseCommandLineOptions) {
    464   cl::ResetCommandLineParser();
    465 
    466   StackOption<bool> TopLevelOpt("top-level", cl::sub(*cl::TopLevelSubCommand),
    467                                 cl::init(false));
    468 
    469   const char *args[] = {"prog", "-top-level"};
    470 
    471   EXPECT_FALSE(TopLevelOpt);
    472   EXPECT_TRUE(
    473       cl::ParseCommandLineOptions(2, args, StringRef(), &llvm::nulls()));
    474   EXPECT_TRUE(TopLevelOpt);
    475 
    476   TopLevelOpt = false;
    477 
    478   cl::ResetAllOptionOccurrences();
    479   EXPECT_FALSE(TopLevelOpt);
    480   EXPECT_TRUE(
    481       cl::ParseCommandLineOptions(2, args, StringRef(), &llvm::nulls()));
    482   EXPECT_TRUE(TopLevelOpt);
    483 }
    484 
    485 TEST(CommandLineTest, RemoveFromRegularSubCommand) {
    486   cl::ResetCommandLineParser();
    487 
    488   StackSubCommand SC("sc", "Subcommand");
    489   StackOption<bool> RemoveOption("remove-option", cl::sub(SC), cl::init(false));
    490   StackOption<bool> KeepOption("keep-option", cl::sub(SC), cl::init(false));
    491 
    492   const char *args[] = {"prog", "sc", "-remove-option"};
    493 
    494   std::string Errs;
    495   raw_string_ostream OS(Errs);
    496 
    497   EXPECT_FALSE(RemoveOption);
    498   EXPECT_TRUE(cl::ParseCommandLineOptions(3, args, StringRef(), &OS));
    499   EXPECT_TRUE(RemoveOption);
    500   OS.flush();
    501   EXPECT_TRUE(Errs.empty());
    502 
    503   RemoveOption.removeArgument();
    504 
    505   cl::ResetAllOptionOccurrences();
    506   EXPECT_FALSE(cl::ParseCommandLineOptions(3, args, StringRef(), &OS));
    507   OS.flush();
    508   EXPECT_FALSE(Errs.empty());
    509 }
    510 
    511 TEST(CommandLineTest, RemoveFromTopLevelSubCommand) {
    512   cl::ResetCommandLineParser();
    513 
    514   StackOption<bool> TopLevelRemove(
    515       "top-level-remove", cl::sub(*cl::TopLevelSubCommand), cl::init(false));
    516   StackOption<bool> TopLevelKeep(
    517       "top-level-keep", cl::sub(*cl::TopLevelSubCommand), cl::init(false));
    518 
    519   const char *args[] = {"prog", "-top-level-remove"};
    520 
    521   EXPECT_FALSE(TopLevelRemove);
    522   EXPECT_TRUE(
    523       cl::ParseCommandLineOptions(2, args, StringRef(), &llvm::nulls()));
    524   EXPECT_TRUE(TopLevelRemove);
    525 
    526   TopLevelRemove.removeArgument();
    527 
    528   cl::ResetAllOptionOccurrences();
    529   EXPECT_FALSE(
    530       cl::ParseCommandLineOptions(2, args, StringRef(), &llvm::nulls()));
    531 }
    532 
    533 TEST(CommandLineTest, RemoveFromAllSubCommands) {
    534   cl::ResetCommandLineParser();
    535 
    536   StackSubCommand SC1("sc1", "First Subcommand");
    537   StackSubCommand SC2("sc2", "Second Subcommand");
    538   StackOption<bool> RemoveOption("remove-option", cl::sub(*cl::AllSubCommands),
    539                                  cl::init(false));
    540   StackOption<bool> KeepOption("keep-option", cl::sub(*cl::AllSubCommands),
    541                                cl::init(false));
    542 
    543   const char *args0[] = {"prog", "-remove-option"};
    544   const char *args1[] = {"prog", "sc1", "-remove-option"};
    545   const char *args2[] = {"prog", "sc2", "-remove-option"};
    546 
    547   // It should work for all subcommands including the top-level.
    548   EXPECT_FALSE(RemoveOption);
    549   EXPECT_TRUE(
    550       cl::ParseCommandLineOptions(2, args0, StringRef(), &llvm::nulls()));
    551   EXPECT_TRUE(RemoveOption);
    552 
    553   RemoveOption = false;
    554 
    555   cl::ResetAllOptionOccurrences();
    556   EXPECT_FALSE(RemoveOption);
    557   EXPECT_TRUE(
    558       cl::ParseCommandLineOptions(3, args1, StringRef(), &llvm::nulls()));
    559   EXPECT_TRUE(RemoveOption);
    560 
    561   RemoveOption = false;
    562 
    563   cl::ResetAllOptionOccurrences();
    564   EXPECT_FALSE(RemoveOption);
    565   EXPECT_TRUE(
    566       cl::ParseCommandLineOptions(3, args2, StringRef(), &llvm::nulls()));
    567   EXPECT_TRUE(RemoveOption);
    568 
    569   RemoveOption.removeArgument();
    570 
    571   // It should not work for any subcommands including the top-level.
    572   cl::ResetAllOptionOccurrences();
    573   EXPECT_FALSE(
    574       cl::ParseCommandLineOptions(2, args0, StringRef(), &llvm::nulls()));
    575   cl::ResetAllOptionOccurrences();
    576   EXPECT_FALSE(
    577       cl::ParseCommandLineOptions(3, args1, StringRef(), &llvm::nulls()));
    578   cl::ResetAllOptionOccurrences();
    579   EXPECT_FALSE(
    580       cl::ParseCommandLineOptions(3, args2, StringRef(), &llvm::nulls()));
    581 }
    582 
    583 TEST(CommandLineTest, GetRegisteredSubcommands) {
    584   cl::ResetCommandLineParser();
    585 
    586   StackSubCommand SC1("sc1", "First Subcommand");
    587   StackOption<bool> Opt1("opt1", cl::sub(SC1), cl::init(false));
    588   StackSubCommand SC2("sc2", "Second subcommand");
    589   StackOption<bool> Opt2("opt2", cl::sub(SC2), cl::init(false));
    590 
    591   const char *args0[] = {"prog", "sc1"};
    592   const char *args1[] = {"prog", "sc2"};
    593 
    594   EXPECT_TRUE(
    595       cl::ParseCommandLineOptions(2, args0, StringRef(), &llvm::nulls()));
    596   EXPECT_FALSE(Opt1);
    597   EXPECT_FALSE(Opt2);
    598   for (auto *S : cl::getRegisteredSubcommands()) {
    599     if (*S) {
    600       EXPECT_EQ("sc1", S->getName());
    601     }
    602   }
    603 
    604   cl::ResetAllOptionOccurrences();
    605   EXPECT_TRUE(
    606       cl::ParseCommandLineOptions(2, args1, StringRef(), &llvm::nulls()));
    607   EXPECT_FALSE(Opt1);
    608   EXPECT_FALSE(Opt2);
    609   for (auto *S : cl::getRegisteredSubcommands()) {
    610     if (*S) {
    611       EXPECT_EQ("sc2", S->getName());
    612     }
    613   }
    614 }
    615 
    616 TEST(CommandLineTest, ArgumentLimit) {
    617   std::string args(32 * 4096, 'a');
    618   EXPECT_FALSE(llvm::sys::commandLineFitsWithinSystemLimits("cl", args.data()));
    619 }
    620 
    621 TEST(CommandLineTest, ResponseFileWindows) {
    622   if (!Triple(sys::getProcessTriple()).isOSWindows())
    623     return;
    624 
    625   StackOption<std::string, cl::list<std::string>> InputFilenames(
    626       cl::Positional, cl::desc("<input files>"), cl::ZeroOrMore);
    627   StackOption<bool> TopLevelOpt("top-level", cl::init(false));
    628 
    629   // Create response file.
    630   int FileDescriptor;
    631   SmallString<64> TempPath;
    632   std::error_code EC =
    633       llvm::sys::fs::createTemporaryFile("resp-", ".txt", FileDescriptor, TempPath);
    634   EXPECT_TRUE(!EC);
    635 
    636   std::ofstream RspFile(TempPath.c_str());
    637   EXPECT_TRUE(RspFile.is_open());
    638   RspFile << "-top-level\npath\\dir\\file1\npath/dir/file2";
    639   RspFile.close();
    640 
    641   llvm::SmallString<128> RspOpt;
    642   RspOpt.append(1, '@');
    643   RspOpt.append(TempPath.c_str());
    644   const char *args[] = {"prog", RspOpt.c_str()};
    645   EXPECT_FALSE(TopLevelOpt);
    646   EXPECT_TRUE(
    647       cl::ParseCommandLineOptions(2, args, StringRef(), &llvm::nulls()));
    648   EXPECT_TRUE(TopLevelOpt);
    649   EXPECT_TRUE(InputFilenames[0] == "path\\dir\\file1");
    650   EXPECT_TRUE(InputFilenames[1] == "path/dir/file2");
    651 
    652   llvm::sys::fs::remove(TempPath.c_str());
    653 }
    654 
    655 TEST(CommandLineTest, ResponseFiles) {
    656   llvm::SmallString<128> TestDir;
    657   std::error_code EC =
    658     llvm::sys::fs::createUniqueDirectory("unittest", TestDir);
    659   EXPECT_TRUE(!EC);
    660 
    661   // Create included response file of first level.
    662   llvm::SmallString<128> IncludedFileName;
    663   llvm::sys::path::append(IncludedFileName, TestDir, "resp1");
    664   std::ofstream IncludedFile(IncludedFileName.c_str());
    665   EXPECT_TRUE(IncludedFile.is_open());
    666   IncludedFile << "-option_1 -option_2\n"
    667                   "@incdir/resp2\n"
    668                   "-option_3=abcd\n";
    669   IncludedFile.close();
    670 
    671   // Directory for included file.
    672   llvm::SmallString<128> IncDir;
    673   llvm::sys::path::append(IncDir, TestDir, "incdir");
    674   EC = llvm::sys::fs::create_directory(IncDir);
    675   EXPECT_TRUE(!EC);
    676 
    677   // Create included response file of second level.
    678   llvm::SmallString<128> IncludedFileName2;
    679   llvm::sys::path::append(IncludedFileName2, IncDir, "resp2");
    680   std::ofstream IncludedFile2(IncludedFileName2.c_str());
    681   EXPECT_TRUE(IncludedFile2.is_open());
    682   IncludedFile2 << "-option_21 -option_22\n";
    683   IncludedFile2 << "-option_23=abcd\n";
    684   IncludedFile2.close();
    685 
    686   // Prepare 'file' with reference to response file.
    687   SmallString<128> IncRef;
    688   IncRef.append(1, '@');
    689   IncRef.append(IncludedFileName.c_str());
    690   llvm::SmallVector<const char *, 4> Argv =
    691                           { "test/test", "-flag_1", IncRef.c_str(), "-flag_2" };
    692 
    693   // Expand response files.
    694   llvm::BumpPtrAllocator A;
    695   llvm::StringSaver Saver(A);
    696   bool Res = llvm::cl::ExpandResponseFiles(
    697                     Saver, llvm::cl::TokenizeGNUCommandLine, Argv, false, true);
    698   EXPECT_TRUE(Res);
    699   EXPECT_EQ(Argv.size(), 9U);
    700   EXPECT_STREQ(Argv[0], "test/test");
    701   EXPECT_STREQ(Argv[1], "-flag_1");
    702   EXPECT_STREQ(Argv[2], "-option_1");
    703   EXPECT_STREQ(Argv[3], "-option_2");
    704   EXPECT_STREQ(Argv[4], "-option_21");
    705   EXPECT_STREQ(Argv[5], "-option_22");
    706   EXPECT_STREQ(Argv[6], "-option_23=abcd");
    707   EXPECT_STREQ(Argv[7], "-option_3=abcd");
    708   EXPECT_STREQ(Argv[8], "-flag_2");
    709 
    710   llvm::sys::fs::remove(IncludedFileName2);
    711   llvm::sys::fs::remove(IncDir);
    712   llvm::sys::fs::remove(IncludedFileName);
    713   llvm::sys::fs::remove(TestDir);
    714 }
    715 
    716 TEST(CommandLineTest, SetDefautValue) {
    717   cl::ResetCommandLineParser();
    718 
    719   StackOption<std::string> Opt1("opt1", cl::init("true"));
    720   StackOption<bool> Opt2("opt2", cl::init(true));
    721   cl::alias Alias("alias", llvm::cl::aliasopt(Opt2));
    722   StackOption<int> Opt3("opt3", cl::init(3));
    723 
    724   const char *args[] = {"prog", "-opt1=false", "-opt2", "-opt3"};
    725 
    726   EXPECT_TRUE(
    727     cl::ParseCommandLineOptions(2, args, StringRef(), &llvm::nulls()));
    728 
    729   EXPECT_TRUE(Opt1 == "false");
    730   EXPECT_TRUE(Opt2);
    731   EXPECT_TRUE(Opt3 == 3);
    732 
    733   Opt2 = false;
    734   Opt3 = 1;
    735 
    736   cl::ResetAllOptionOccurrences();
    737 
    738   for (auto &OM : cl::getRegisteredOptions(*cl::TopLevelSubCommand)) {
    739     cl::Option *O = OM.second;
    740     if (O->ArgStr == "opt2") {
    741       continue;
    742     }
    743     O->setDefault();
    744   }
    745 
    746   EXPECT_TRUE(Opt1 == "true");
    747   EXPECT_TRUE(Opt2);
    748   EXPECT_TRUE(Opt3 == 3);
    749   Alias.removeArgument();
    750 }
    751 
    752 TEST(CommandLineTest, ReadConfigFile) {
    753   llvm::SmallVector<const char *, 1> Argv;
    754 
    755   llvm::SmallString<128> TestDir;
    756   std::error_code EC =
    757       llvm::sys::fs::createUniqueDirectory("unittest", TestDir);
    758   EXPECT_TRUE(!EC);
    759 
    760   llvm::SmallString<128> TestCfg;
    761   llvm::sys::path::append(TestCfg, TestDir, "foo");
    762   std::ofstream ConfigFile(TestCfg.c_str());
    763   EXPECT_TRUE(ConfigFile.is_open());
    764   ConfigFile << "# Comment\n"
    765                 "-option_1\n"
    766                 "@subconfig\n"
    767                 "-option_3=abcd\n"
    768                 "-option_4=\\\n"
    769                 "cdef\n";
    770   ConfigFile.close();
    771 
    772   llvm::SmallString<128> TestCfg2;
    773   llvm::sys::path::append(TestCfg2, TestDir, "subconfig");
    774   std::ofstream ConfigFile2(TestCfg2.c_str());
    775   EXPECT_TRUE(ConfigFile2.is_open());
    776   ConfigFile2 << "-option_2\n"
    777                  "\n"
    778                  "   # comment\n";
    779   ConfigFile2.close();
    780 
    781   // Make sure the current directory is not the directory where config files
    782   // resides. In this case the code that expands response files will not find
    783   // 'subconfig' unless it resolves nested inclusions relative to the including
    784   // file.
    785   llvm::SmallString<128> CurrDir;
    786   EC = llvm::sys::fs::current_path(CurrDir);
    787   EXPECT_TRUE(!EC);
    788   EXPECT_TRUE(StringRef(CurrDir) != StringRef(TestDir));
    789 
    790   llvm::BumpPtrAllocator A;
    791   llvm::StringSaver Saver(A);
    792   bool Result = llvm::cl::readConfigFile(TestCfg, Saver, Argv);
    793 
    794   EXPECT_TRUE(Result);
    795   EXPECT_EQ(Argv.size(), 4U);
    796   EXPECT_STREQ(Argv[0], "-option_1");
    797   EXPECT_STREQ(Argv[1], "-option_2");
    798   EXPECT_STREQ(Argv[2], "-option_3=abcd");
    799   EXPECT_STREQ(Argv[3], "-option_4=cdef");
    800 
    801   llvm::sys::fs::remove(TestCfg2);
    802   llvm::sys::fs::remove(TestCfg);
    803   llvm::sys::fs::remove(TestDir);
    804 }
    805 
    806 TEST(CommandLineTest, PositionalEatArgsError) {
    807   StackOption<std::string, cl::list<std::string>> PosEatArgs(
    808       "positional-eat-args", cl::Positional, cl::desc("<arguments>..."),
    809       cl::ZeroOrMore, cl::PositionalEatsArgs);
    810 
    811   const char *args[] = {"prog", "-positional-eat-args=XXXX"};
    812   const char *args2[] = {"prog", "-positional-eat-args=XXXX", "-foo"};
    813   const char *args3[] = {"prog", "-positional-eat-args", "-foo"};
    814 
    815   std::string Errs;
    816   raw_string_ostream OS(Errs);
    817   EXPECT_FALSE(cl::ParseCommandLineOptions(2, args, StringRef(), &OS)); OS.flush();
    818   EXPECT_FALSE(Errs.empty()); Errs.clear();
    819   EXPECT_FALSE(cl::ParseCommandLineOptions(3, args2, StringRef(), &OS)); OS.flush();
    820   EXPECT_FALSE(Errs.empty()); Errs.clear();
    821   EXPECT_TRUE(cl::ParseCommandLineOptions(3, args3, StringRef(), &OS)); OS.flush();
    822   EXPECT_TRUE(Errs.empty());
    823 }
    824 
    825 #ifdef _WIN32
    826 TEST(CommandLineTest, GetCommandLineArguments) {
    827   int argc = __argc;
    828   char **argv = __argv;
    829 
    830   // GetCommandLineArguments is called in InitLLVM.
    831   llvm::InitLLVM X(argc, argv);
    832 
    833   EXPECT_EQ(llvm::sys::path::is_absolute(argv[0]),
    834             llvm::sys::path::is_absolute(__argv[0]));
    835 
    836   EXPECT_TRUE(llvm::sys::path::filename(argv[0])
    837               .equals_lower("supporttests.exe"))
    838       << "Filename of test executable is "
    839       << llvm::sys::path::filename(argv[0]);
    840 }
    841 #endif
    842 
    843 }  // anonymous namespace
    844