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