1a75d6bf3SJeffrey Yasskin //===- llvm/unittest/Support/CommandLineTest.cpp - CommandLine tests ------===//
2a75d6bf3SJeffrey Yasskin //
32946cd70SChandler Carruth // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
42946cd70SChandler Carruth // See https://llvm.org/LICENSE.txt for license information.
52946cd70SChandler Carruth // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6a75d6bf3SJeffrey Yasskin //
7a75d6bf3SJeffrey Yasskin //===----------------------------------------------------------------------===//
8a75d6bf3SJeffrey Yasskin 
98a8cd2baSChandler Carruth #include "llvm/Support/CommandLine.h"
109a67b073SChandler Carruth #include "llvm/ADT/STLExtras.h"
119a67b073SChandler Carruth #include "llvm/ADT/SmallString.h"
12b3b37783SKadir Cetinkaya #include "llvm/ADT/StringRef.h"
13430c7ff7SDmitry Mikulin #include "llvm/ADT/Triple.h"
149a67b073SChandler Carruth #include "llvm/Config/config.h"
15b3b37783SKadir Cetinkaya #include "llvm/Support/Allocator.h"
166ac8e034SSerge Pavlov #include "llvm/Support/FileSystem.h"
17213aea4cSReid Kleckner #include "llvm/Support/Host.h"
1812ba9ec9SHans Wennborg #include "llvm/Support/InitLLVM.h"
199652652aSJames Henderson #include "llvm/Support/MemoryBuffer.h"
206ac8e034SSerge Pavlov #include "llvm/Support/Path.h"
218199dadaSSaleem Abdulrasool #include "llvm/Support/Program.h"
22454adf64SRafael Espindola #include "llvm/Support/StringSaver.h"
23b3b37783SKadir Cetinkaya #include "llvm/Support/VirtualFileSystem.h"
24b3b37783SKadir Cetinkaya #include "llvm/Support/raw_ostream.h"
25fad75598SSergej Jaskiewicz #include "llvm/Testing/Support/SupportHelpers.h"
26b3b37783SKadir Cetinkaya #include "gmock/gmock.h"
27a75d6bf3SJeffrey Yasskin #include "gtest/gtest.h"
286ac8e034SSerge Pavlov #include <fstream>
2991d3cfedSDuncan P. N. Exon Smith #include <stdlib.h>
30130cec21SChandler Carruth #include <string>
31b3b37783SKadir Cetinkaya #include <tuple>
32a75d6bf3SJeffrey Yasskin 
33a75d6bf3SJeffrey Yasskin using namespace llvm;
34fad75598SSergej Jaskiewicz using llvm::unittest::TempDir;
35fad75598SSergej Jaskiewicz using llvm::unittest::TempFile;
36a75d6bf3SJeffrey Yasskin 
37a75d6bf3SJeffrey Yasskin namespace {
38a75d6bf3SJeffrey Yasskin 
39b3b37783SKadir Cetinkaya MATCHER(StringEquality, "Checks if two char* are equal as strings") {
40b3b37783SKadir Cetinkaya   return std::string(std::get<0>(arg)) == std::string(std::get<1>(arg));
41b3b37783SKadir Cetinkaya }
42b3b37783SKadir Cetinkaya 
43a75d6bf3SJeffrey Yasskin class TempEnvVar {
44a75d6bf3SJeffrey Yasskin  public:
TempEnvVar(const char * name,const char * value)45a75d6bf3SJeffrey Yasskin   TempEnvVar(const char *name, const char *value)
46a75d6bf3SJeffrey Yasskin       : name(name) {
47a75d6bf3SJeffrey Yasskin     const char *old_value = getenv(name);
4866f09ad0SCraig Topper     EXPECT_EQ(nullptr, old_value) << old_value;
4914a5cc54SJeffrey Yasskin #if HAVE_SETENV
50a75d6bf3SJeffrey Yasskin     setenv(name, value, true);
5114a5cc54SJeffrey Yasskin #endif
52a75d6bf3SJeffrey Yasskin   }
53a75d6bf3SJeffrey Yasskin 
~TempEnvVar()54a75d6bf3SJeffrey Yasskin   ~TempEnvVar() {
5514a5cc54SJeffrey Yasskin #if HAVE_SETENV
5614a5cc54SJeffrey Yasskin     // Assume setenv and unsetenv come together.
57a75d6bf3SJeffrey Yasskin     unsetenv(name);
58542a4543SReid Kleckner #else
59542a4543SReid Kleckner     (void)name; // Suppress -Wunused-private-field.
6014a5cc54SJeffrey Yasskin #endif
61a75d6bf3SJeffrey Yasskin   }
62a75d6bf3SJeffrey Yasskin 
63a75d6bf3SJeffrey Yasskin  private:
64a75d6bf3SJeffrey Yasskin   const char *const name;
65a75d6bf3SJeffrey Yasskin };
66a75d6bf3SJeffrey Yasskin 
675390e369SEric Liu template <typename T, typename Base = cl::opt<T>>
685390e369SEric Liu class StackOption : public Base {
69c25b0c7eSJordan Rose public:
70ec8598efSBenjamin Kramer   template <class... Ts>
StackOption(Ts &&...Ms)71ec8598efSBenjamin Kramer   explicit StackOption(Ts &&... Ms) : Base(std::forward<Ts>(Ms)...) {}
725390e369SEric Liu 
~StackOption()73f817c1cbSAlexander Kornienko   ~StackOption() override { this->removeArgument(); }
7407670b3eSZachary Turner 
operator =(const DT & V)7507670b3eSZachary Turner   template <class DT> StackOption<T> &operator=(const DT &V) {
766555995aSDon Hinton     Base::operator=(V);
7707670b3eSZachary Turner     return *this;
7807670b3eSZachary Turner   }
7907670b3eSZachary Turner };
8007670b3eSZachary Turner 
8107670b3eSZachary Turner class StackSubCommand : public cl::SubCommand {
8207670b3eSZachary Turner public:
StackSubCommand(StringRef Name,StringRef Description=StringRef ())83e11b745bSMehdi Amini   StackSubCommand(StringRef Name,
84e11b745bSMehdi Amini                   StringRef Description = StringRef())
8507670b3eSZachary Turner       : SubCommand(Name, Description) {}
8607670b3eSZachary Turner 
StackSubCommand()8707670b3eSZachary Turner   StackSubCommand() : SubCommand() {}
8807670b3eSZachary Turner 
~StackSubCommand()8907670b3eSZachary Turner   ~StackSubCommand() { unregisterSubCommand(); }
90c25b0c7eSJordan Rose };
91c25b0c7eSJordan Rose 
9291d3cfedSDuncan P. N. Exon Smith 
937cb710d5SAndrew Trick cl::OptionCategory TestCategory("Test Options", "Description");
TEST(CommandLineTest,ModifyExisitingOption)947cb710d5SAndrew Trick TEST(CommandLineTest, ModifyExisitingOption) {
95d1d9430aSChris Bieneman   StackOption<int> TestOption("test-option", cl::desc("old description"));
96d1d9430aSChris Bieneman 
97a8b32decSVitaly Buka   static const char Description[] = "New description";
98a8b32decSVitaly Buka   static const char ArgString[] = "new-test-option";
99a8b32decSVitaly Buka   static const char ValueString[] = "Integer";
1007cb710d5SAndrew Trick 
10107670b3eSZachary Turner   StringMap<cl::Option *> &Map =
10207670b3eSZachary Turner       cl::getRegisteredOptions(*cl::TopLevelSubCommand);
1037cb710d5SAndrew Trick 
10438ac4093SArchibald Elliott   ASSERT_EQ(Map.count("test-option"), 1u) << "Could not find option in map.";
1057cb710d5SAndrew Trick 
1067cb710d5SAndrew Trick   cl::Option *Retrieved = Map["test-option"];
1077cb710d5SAndrew Trick   ASSERT_EQ(&TestOption, Retrieved) << "Retrieved wrong option.";
1087cb710d5SAndrew Trick 
109e6695821SHaojian Wu   ASSERT_NE(Retrieved->Categories.end(),
110e6695821SHaojian Wu             find_if(Retrieved->Categories,
111102ec097SDon Hinton                     [&](const llvm::cl::OptionCategory *Cat) {
11276374573SMehdi Amini                       return Cat == &cl::getGeneralCategory();
113102ec097SDon Hinton                     }))
114102ec097SDon Hinton       << "Incorrect default option category.";
1157cb710d5SAndrew Trick 
116102ec097SDon Hinton   Retrieved->addCategory(TestCategory);
117e6695821SHaojian Wu   ASSERT_NE(Retrieved->Categories.end(),
118e6695821SHaojian Wu             find_if(Retrieved->Categories,
119102ec097SDon Hinton                     [&](const llvm::cl::OptionCategory *Cat) {
120102ec097SDon Hinton                       return Cat == &TestCategory;
121102ec097SDon Hinton                     }))
122102ec097SDon Hinton       << "Failed to modify option's option category.";
1237cb710d5SAndrew Trick 
1247cb710d5SAndrew Trick   Retrieved->setDescription(Description);
125ff43d69dSDavid Blaikie   ASSERT_STREQ(Retrieved->HelpStr.data(), Description)
126ff43d69dSDavid Blaikie       << "Changing option description failed.";
1277cb710d5SAndrew Trick 
1287cb710d5SAndrew Trick   Retrieved->setArgStr(ArgString);
129ff43d69dSDavid Blaikie   ASSERT_STREQ(ArgString, Retrieved->ArgStr.data())
130ff43d69dSDavid Blaikie       << "Failed to modify option's Argument string.";
1317cb710d5SAndrew Trick 
1327cb710d5SAndrew Trick   Retrieved->setValueStr(ValueString);
133ff43d69dSDavid Blaikie   ASSERT_STREQ(Retrieved->ValueStr.data(), ValueString)
134ff43d69dSDavid Blaikie       << "Failed to modify option's Value string.";
1357cb710d5SAndrew Trick 
1367cb710d5SAndrew Trick   Retrieved->setHiddenFlag(cl::Hidden);
1377cb710d5SAndrew Trick   ASSERT_EQ(cl::Hidden, TestOption.getOptionHiddenFlag()) <<
1387cb710d5SAndrew Trick     "Failed to modify option's hidden flag.";
1397cb710d5SAndrew Trick }
14014a5cc54SJeffrey Yasskin 
TEST(CommandLineTest,UseOptionCategory)1410537a988SAndrew Trick TEST(CommandLineTest, UseOptionCategory) {
142c25b0c7eSJordan Rose   StackOption<int> TestOption2("test-option", cl::cat(TestCategory));
1430537a988SAndrew Trick 
144e6695821SHaojian Wu   ASSERT_NE(TestOption2.Categories.end(),
145e6695821SHaojian Wu             find_if(TestOption2.Categories,
146102ec097SDon Hinton                          [&](const llvm::cl::OptionCategory *Cat) {
147102ec097SDon Hinton                            return Cat == &TestCategory;
148102ec097SDon Hinton                          }))
149102ec097SDon Hinton       << "Failed to assign Option Category.";
150102ec097SDon Hinton }
151102ec097SDon Hinton 
TEST(CommandLineTest,UseMultipleCategories)152102ec097SDon Hinton TEST(CommandLineTest, UseMultipleCategories) {
153102ec097SDon Hinton   StackOption<int> TestOption2("test-option2", cl::cat(TestCategory),
15476374573SMehdi Amini                                cl::cat(cl::getGeneralCategory()),
15576374573SMehdi Amini                                cl::cat(cl::getGeneralCategory()));
156102ec097SDon Hinton 
15776374573SMehdi Amini   // Make sure cl::getGeneralCategory() wasn't added twice.
158e6695821SHaojian Wu   ASSERT_EQ(TestOption2.Categories.size(), 2U);
1598249a888SDon Hinton 
160e6695821SHaojian Wu   ASSERT_NE(TestOption2.Categories.end(),
161e6695821SHaojian Wu             find_if(TestOption2.Categories,
162102ec097SDon Hinton                          [&](const llvm::cl::OptionCategory *Cat) {
163102ec097SDon Hinton                            return Cat == &TestCategory;
164102ec097SDon Hinton                          }))
165102ec097SDon Hinton       << "Failed to assign Option Category.";
166e6695821SHaojian Wu   ASSERT_NE(TestOption2.Categories.end(),
167e6695821SHaojian Wu             find_if(TestOption2.Categories,
168102ec097SDon Hinton                     [&](const llvm::cl::OptionCategory *Cat) {
16976374573SMehdi Amini                       return Cat == &cl::getGeneralCategory();
170102ec097SDon Hinton                     }))
171102ec097SDon Hinton       << "Failed to assign General Category.";
172102ec097SDon Hinton 
173102ec097SDon Hinton   cl::OptionCategory AnotherCategory("Additional test Options", "Description");
174102ec097SDon Hinton   StackOption<int> TestOption("test-option", cl::cat(TestCategory),
175102ec097SDon Hinton                               cl::cat(AnotherCategory));
176e6695821SHaojian Wu   ASSERT_EQ(TestOption.Categories.end(),
177e6695821SHaojian Wu             find_if(TestOption.Categories,
178102ec097SDon Hinton                     [&](const llvm::cl::OptionCategory *Cat) {
17976374573SMehdi Amini                       return Cat == &cl::getGeneralCategory();
180102ec097SDon Hinton                     }))
181102ec097SDon Hinton       << "Failed to remove General Category.";
182e6695821SHaojian Wu   ASSERT_NE(TestOption.Categories.end(),
183e6695821SHaojian Wu             find_if(TestOption.Categories,
184102ec097SDon Hinton                          [&](const llvm::cl::OptionCategory *Cat) {
185102ec097SDon Hinton                            return Cat == &TestCategory;
186102ec097SDon Hinton                          }))
187102ec097SDon Hinton       << "Failed to assign Option Category.";
188e6695821SHaojian Wu   ASSERT_NE(TestOption.Categories.end(),
189e6695821SHaojian Wu             find_if(TestOption.Categories,
190102ec097SDon Hinton                          [&](const llvm::cl::OptionCategory *Cat) {
191102ec097SDon Hinton                            return Cat == &AnotherCategory;
192102ec097SDon Hinton                          }))
193102ec097SDon Hinton       << "Failed to assign Another Category.";
1940537a988SAndrew Trick }
1950537a988SAndrew Trick 
196454adf64SRafael Espindola typedef void ParserFunction(StringRef Source, StringSaver &Saver,
197e3f146d9SReid Kleckner                             SmallVectorImpl<const char *> &NewArgv,
198e3f146d9SReid Kleckner                             bool MarkEOLs);
199a2222b57SRui Ueyama 
testCommandLineTokenizer(ParserFunction * parse,StringRef Input,ArrayRef<const char * > Output,bool MarkEOLs=false)200e11b745bSMehdi Amini void testCommandLineTokenizer(ParserFunction *parse, StringRef Input,
201f5524745SReid Kleckner                               ArrayRef<const char *> Output,
202f5524745SReid Kleckner                               bool MarkEOLs = false) {
203a2222b57SRui Ueyama   SmallVector<const char *, 0> Actual;
204454adf64SRafael Espindola   BumpPtrAllocator A;
205b82455d2SRafael Espindola   StringSaver Saver(A);
206f5524745SReid Kleckner   parse(Input, Saver, Actual, MarkEOLs);
207f5524745SReid Kleckner   EXPECT_EQ(Output.size(), Actual.size());
208a2222b57SRui Ueyama   for (unsigned I = 0, E = Actual.size(); I != E; ++I) {
209f5524745SReid Kleckner     if (I < Output.size()) {
210a2222b57SRui Ueyama       EXPECT_STREQ(Output[I], Actual[I]);
211a2222b57SRui Ueyama     }
212a2222b57SRui Ueyama   }
213fcae62d6SGalina Kistanova }
214a2222b57SRui Ueyama 
TEST(CommandLineTest,TokenizeGNUCommandLine)215a73c7781SReid Kleckner TEST(CommandLineTest, TokenizeGNUCommandLine) {
216e11b745bSMehdi Amini   const char Input[] =
217fa7f4898SNico Weber       "foo\\ bar \"foo bar\" \'foo bar\' 'foo\\\\bar' -DFOO=bar\\(\\) "
218fa7f4898SNico Weber       "foo\"bar\"baz C:\\\\src\\\\foo.cpp \"C:\\src\\foo.cpp\"";
219fa7f4898SNico Weber   const char *const Output[] = {
220fa7f4898SNico Weber       "foo bar",     "foo bar",   "foo bar",          "foo\\bar",
221fa7f4898SNico Weber       "-DFOO=bar()", "foobarbaz", "C:\\src\\foo.cpp", "C:srcfoo.cpp"};
222f5524745SReid Kleckner   testCommandLineTokenizer(cl::TokenizeGNUCommandLine, Input, Output);
223a73c7781SReid Kleckner }
224a2222b57SRui Ueyama 
TEST(CommandLineTest,TokenizeWindowsCommandLine1)2256823c823SSunil Srivastava TEST(CommandLineTest, TokenizeWindowsCommandLine1) {
2262d068e53SAdrian McCarthy   const char Input[] =
2272d068e53SAdrian McCarthy       R"(a\b c\\d e\\"f g" h\"i j\\\"k "lmn" o pqr "st \"u" \v)";
228a2222b57SRui Ueyama   const char *const Output[] = { "a\\b", "c\\\\d", "e\\f g", "h\"i", "j\\\"k",
229a2222b57SRui Ueyama                                  "lmn", "o", "pqr", "st \"u", "\\v" };
230f5524745SReid Kleckner   testCommandLineTokenizer(cl::TokenizeWindowsCommandLine, Input, Output);
231a73c7781SReid Kleckner }
232a73c7781SReid Kleckner 
TEST(CommandLineTest,TokenizeWindowsCommandLine2)2336823c823SSunil Srivastava TEST(CommandLineTest, TokenizeWindowsCommandLine2) {
2346823c823SSunil Srivastava   const char Input[] = "clang -c -DFOO=\"\"\"ABC\"\"\" x.cpp";
2356823c823SSunil Srivastava   const char *const Output[] = { "clang", "-c", "-DFOO=\"ABC\"", "x.cpp"};
236f5524745SReid Kleckner   testCommandLineTokenizer(cl::TokenizeWindowsCommandLine, Input, Output);
2376823c823SSunil Srivastava }
2386823c823SSunil Srivastava 
TEST(CommandLineTest,TokenizeWindowsCommandLineQuotedLastArgument)2392d068e53SAdrian McCarthy TEST(CommandLineTest, TokenizeWindowsCommandLineQuotedLastArgument) {
2401be024eeSSimon Tatham   // Whitespace at the end of the command line doesn't cause an empty last word
2411be024eeSSimon Tatham   const char Input0[] = R"(a b c d )";
2421be024eeSSimon Tatham   const char *const Output0[] = {"a", "b", "c", "d"};
2431be024eeSSimon Tatham   testCommandLineTokenizer(cl::TokenizeWindowsCommandLine, Input0, Output0);
2441be024eeSSimon Tatham 
2451be024eeSSimon Tatham   // But an explicit "" does
2462d068e53SAdrian McCarthy   const char Input1[] = R"(a b c d "")";
2472d068e53SAdrian McCarthy   const char *const Output1[] = {"a", "b", "c", "d", ""};
248f5524745SReid Kleckner   testCommandLineTokenizer(cl::TokenizeWindowsCommandLine, Input1, Output1);
2491be024eeSSimon Tatham 
2501be024eeSSimon Tatham   // An unterminated quoted string is also emitted as an argument word, empty
2511be024eeSSimon Tatham   // or not
2522d068e53SAdrian McCarthy   const char Input2[] = R"(a b c d ")";
2531be024eeSSimon Tatham   const char *const Output2[] = {"a", "b", "c", "d", ""};
254f5524745SReid Kleckner   testCommandLineTokenizer(cl::TokenizeWindowsCommandLine, Input2, Output2);
2551be024eeSSimon Tatham   const char Input3[] = R"(a b c d "text)";
2561be024eeSSimon Tatham   const char *const Output3[] = {"a", "b", "c", "d", "text"};
2571be024eeSSimon Tatham   testCommandLineTokenizer(cl::TokenizeWindowsCommandLine, Input3, Output3);
258f5524745SReid Kleckner }
259f5524745SReid Kleckner 
TEST(CommandLineTest,TokenizeWindowsCommandLineExeName)26032814df4SSimon Tatham TEST(CommandLineTest, TokenizeWindowsCommandLineExeName) {
26132814df4SSimon Tatham   const char Input1[] =
26232814df4SSimon Tatham       R"("C:\Program Files\Whatever\"clang.exe z.c -DY=\"x\")";
26332814df4SSimon Tatham   const char *const Output1[] = {"C:\\Program Files\\Whatever\\clang.exe",
26432814df4SSimon Tatham                                  "z.c", "-DY=\"x\""};
26532814df4SSimon Tatham   testCommandLineTokenizer(cl::TokenizeWindowsCommandLineFull, Input1, Output1);
26632814df4SSimon Tatham 
26732814df4SSimon Tatham   const char Input2[] = "\"a\\\"b c\\\"d\n\"e\\\"f g\\\"h\n";
26832814df4SSimon Tatham   const char *const Output2[] = {"a\\b", "c\"d", nullptr,
26932814df4SSimon Tatham                                  "e\\f", "g\"h", nullptr};
27032814df4SSimon Tatham   testCommandLineTokenizer(cl::TokenizeWindowsCommandLineFull, Input2, Output2,
27132814df4SSimon Tatham                            /*MarkEOLs=*/true);
27232814df4SSimon Tatham 
27332814df4SSimon Tatham   const char Input3[] = R"(\\server\share\subdir\clang.exe)";
27432814df4SSimon Tatham   const char *const Output3[] = {"\\\\server\\share\\subdir\\clang.exe"};
27532814df4SSimon Tatham   testCommandLineTokenizer(cl::TokenizeWindowsCommandLineFull, Input3, Output3);
27632814df4SSimon Tatham }
27732814df4SSimon Tatham 
TEST(CommandLineTest,TokenizeAndMarkEOLs)278f5524745SReid Kleckner TEST(CommandLineTest, TokenizeAndMarkEOLs) {
279f5524745SReid Kleckner   // Clang uses EOL marking in response files to support options that consume
280f5524745SReid Kleckner   // the rest of the arguments on the current line, but do not consume arguments
281f5524745SReid Kleckner   // from subsequent lines. For example, given these rsp files contents:
282f5524745SReid Kleckner   // /c /Zi /O2
283f5524745SReid Kleckner   // /Oy- /link /debug /opt:ref
284f5524745SReid Kleckner   // /Zc:ThreadsafeStatics-
285f5524745SReid Kleckner   //
286f5524745SReid Kleckner   // clang-cl needs to treat "/debug /opt:ref" as linker flags, and everything
287f5524745SReid Kleckner   // else as compiler flags. The tokenizer inserts nullptr sentinels into the
288f5524745SReid Kleckner   // output so that clang-cl can find the end of the current line.
289f5524745SReid Kleckner   const char Input[] = "clang -Xclang foo\n\nfoo\"bar\"baz\n x.cpp\n";
290f5524745SReid Kleckner   const char *const Output[] = {"clang", "-Xclang", "foo",
291f5524745SReid Kleckner                                 nullptr, nullptr,   "foobarbaz",
292f5524745SReid Kleckner                                 nullptr, "x.cpp",   nullptr};
293f5524745SReid Kleckner   testCommandLineTokenizer(cl::TokenizeWindowsCommandLine, Input, Output,
294f5524745SReid Kleckner                            /*MarkEOLs=*/true);
295f5524745SReid Kleckner   testCommandLineTokenizer(cl::TokenizeGNUCommandLine, Input, Output,
296f5524745SReid Kleckner                            /*MarkEOLs=*/true);
2972d068e53SAdrian McCarthy }
2982d068e53SAdrian McCarthy 
TEST(CommandLineTest,TokenizeConfigFile1)2999f0ac82fSSerge Pavlov TEST(CommandLineTest, TokenizeConfigFile1) {
3009f0ac82fSSerge Pavlov   const char *Input = "\\";
3019f0ac82fSSerge Pavlov   const char *const Output[] = { "\\" };
302f5524745SReid Kleckner   testCommandLineTokenizer(cl::tokenizeConfigFile, Input, Output);
3039f0ac82fSSerge Pavlov }
3049f0ac82fSSerge Pavlov 
TEST(CommandLineTest,TokenizeConfigFile2)3059f0ac82fSSerge Pavlov TEST(CommandLineTest, TokenizeConfigFile2) {
3069f0ac82fSSerge Pavlov   const char *Input = "\\abc";
3079f0ac82fSSerge Pavlov   const char *const Output[] = { "abc" };
308f5524745SReid Kleckner   testCommandLineTokenizer(cl::tokenizeConfigFile, Input, Output);
3099f0ac82fSSerge Pavlov }
3109f0ac82fSSerge Pavlov 
TEST(CommandLineTest,TokenizeConfigFile3)3119f0ac82fSSerge Pavlov TEST(CommandLineTest, TokenizeConfigFile3) {
3129f0ac82fSSerge Pavlov   const char *Input = "abc\\";
3139f0ac82fSSerge Pavlov   const char *const Output[] = { "abc\\" };
314f5524745SReid Kleckner   testCommandLineTokenizer(cl::tokenizeConfigFile, Input, Output);
3159f0ac82fSSerge Pavlov }
3169f0ac82fSSerge Pavlov 
TEST(CommandLineTest,TokenizeConfigFile4)3179f0ac82fSSerge Pavlov TEST(CommandLineTest, TokenizeConfigFile4) {
3189f0ac82fSSerge Pavlov   const char *Input = "abc\\\n123";
3199f0ac82fSSerge Pavlov   const char *const Output[] = { "abc123" };
320f5524745SReid Kleckner   testCommandLineTokenizer(cl::tokenizeConfigFile, Input, Output);
3219f0ac82fSSerge Pavlov }
3229f0ac82fSSerge Pavlov 
TEST(CommandLineTest,TokenizeConfigFile5)3239f0ac82fSSerge Pavlov TEST(CommandLineTest, TokenizeConfigFile5) {
3249f0ac82fSSerge Pavlov   const char *Input = "abc\\\r\n123";
3259f0ac82fSSerge Pavlov   const char *const Output[] = { "abc123" };
326f5524745SReid Kleckner   testCommandLineTokenizer(cl::tokenizeConfigFile, Input, Output);
3279f0ac82fSSerge Pavlov }
3289f0ac82fSSerge Pavlov 
TEST(CommandLineTest,TokenizeConfigFile6)3299f0ac82fSSerge Pavlov TEST(CommandLineTest, TokenizeConfigFile6) {
3309f0ac82fSSerge Pavlov   const char *Input = "abc\\\n";
3319f0ac82fSSerge Pavlov   const char *const Output[] = { "abc" };
332f5524745SReid Kleckner   testCommandLineTokenizer(cl::tokenizeConfigFile, Input, Output);
3339f0ac82fSSerge Pavlov }
3349f0ac82fSSerge Pavlov 
TEST(CommandLineTest,TokenizeConfigFile7)3359f0ac82fSSerge Pavlov TEST(CommandLineTest, TokenizeConfigFile7) {
3369f0ac82fSSerge Pavlov   const char *Input = "abc\\\r\n";
3379f0ac82fSSerge Pavlov   const char *const Output[] = { "abc" };
338f5524745SReid Kleckner   testCommandLineTokenizer(cl::tokenizeConfigFile, Input, Output);
3399f0ac82fSSerge Pavlov }
3409f0ac82fSSerge Pavlov 
TEST(CommandLineTest,TokenizeConfigFile8)3419f0ac82fSSerge Pavlov TEST(CommandLineTest, TokenizeConfigFile8) {
3429f0ac82fSSerge Pavlov   SmallVector<const char *, 0> Actual;
3439f0ac82fSSerge Pavlov   BumpPtrAllocator A;
3449f0ac82fSSerge Pavlov   StringSaver Saver(A);
3459f0ac82fSSerge Pavlov   cl::tokenizeConfigFile("\\\n", Saver, Actual, /*MarkEOLs=*/false);
3469f0ac82fSSerge Pavlov   EXPECT_TRUE(Actual.empty());
3479f0ac82fSSerge Pavlov }
3489f0ac82fSSerge Pavlov 
TEST(CommandLineTest,TokenizeConfigFile9)3499f0ac82fSSerge Pavlov TEST(CommandLineTest, TokenizeConfigFile9) {
3509f0ac82fSSerge Pavlov   SmallVector<const char *, 0> Actual;
3519f0ac82fSSerge Pavlov   BumpPtrAllocator A;
3529f0ac82fSSerge Pavlov   StringSaver Saver(A);
3539f0ac82fSSerge Pavlov   cl::tokenizeConfigFile("\\\r\n", Saver, Actual, /*MarkEOLs=*/false);
3549f0ac82fSSerge Pavlov   EXPECT_TRUE(Actual.empty());
3559f0ac82fSSerge Pavlov }
3569f0ac82fSSerge Pavlov 
TEST(CommandLineTest,TokenizeConfigFile10)3579f0ac82fSSerge Pavlov TEST(CommandLineTest, TokenizeConfigFile10) {
3589f0ac82fSSerge Pavlov   const char *Input = "\\\nabc";
3599f0ac82fSSerge Pavlov   const char *const Output[] = { "abc" };
360f5524745SReid Kleckner   testCommandLineTokenizer(cl::tokenizeConfigFile, Input, Output);
3619f0ac82fSSerge Pavlov }
3629f0ac82fSSerge Pavlov 
TEST(CommandLineTest,TokenizeConfigFile11)3639f0ac82fSSerge Pavlov TEST(CommandLineTest, TokenizeConfigFile11) {
3649f0ac82fSSerge Pavlov   const char *Input = "\\\r\nabc";
3659f0ac82fSSerge Pavlov   const char *const Output[] = { "abc" };
366f5524745SReid Kleckner   testCommandLineTokenizer(cl::tokenizeConfigFile, Input, Output);
3679f0ac82fSSerge Pavlov }
3689f0ac82fSSerge Pavlov 
TEST(CommandLineTest,AliasesWithArguments)369c25b0c7eSJordan Rose TEST(CommandLineTest, AliasesWithArguments) {
370c25b0c7eSJordan Rose   static const size_t ARGC = 3;
371c25b0c7eSJordan Rose   const char *const Inputs[][ARGC] = {
372c25b0c7eSJordan Rose     { "-tool", "-actual=x", "-extra" },
373c25b0c7eSJordan Rose     { "-tool", "-actual", "x" },
374c25b0c7eSJordan Rose     { "-tool", "-alias=x", "-extra" },
375c25b0c7eSJordan Rose     { "-tool", "-alias", "x" }
376c25b0c7eSJordan Rose   };
377c25b0c7eSJordan Rose 
378f15014ffSBenjamin Kramer   for (size_t i = 0, e = array_lengthof(Inputs); i < e; ++i) {
379c25b0c7eSJordan Rose     StackOption<std::string> Actual("actual");
380c25b0c7eSJordan Rose     StackOption<bool> Extra("extra");
381c25b0c7eSJordan Rose     StackOption<std::string> Input(cl::Positional);
382c25b0c7eSJordan Rose 
383c25b0c7eSJordan Rose     cl::alias Alias("alias", llvm::cl::aliasopt(Actual));
384c25b0c7eSJordan Rose 
385c25b0c7eSJordan Rose     cl::ParseCommandLineOptions(ARGC, Inputs[i]);
386c25b0c7eSJordan Rose     EXPECT_EQ("x", Actual);
387c25b0c7eSJordan Rose     EXPECT_EQ(0, Input.getNumOccurrences());
388c25b0c7eSJordan Rose 
389c25b0c7eSJordan Rose     Alias.removeArgument();
390c25b0c7eSJordan Rose   }
391c25b0c7eSJordan Rose }
392c25b0c7eSJordan Rose 
testAliasRequired(int argc,const char * const * argv)393759645eaSJustin Bogner void testAliasRequired(int argc, const char *const *argv) {
394759645eaSJustin Bogner   StackOption<std::string> Option("option", cl::Required);
395759645eaSJustin Bogner   cl::alias Alias("o", llvm::cl::aliasopt(Option));
396759645eaSJustin Bogner 
397759645eaSJustin Bogner   cl::ParseCommandLineOptions(argc, argv);
398759645eaSJustin Bogner   EXPECT_EQ("x", Option);
399759645eaSJustin Bogner   EXPECT_EQ(1, Option.getNumOccurrences());
400759645eaSJustin Bogner 
401759645eaSJustin Bogner   Alias.removeArgument();
402759645eaSJustin Bogner }
403759645eaSJustin Bogner 
TEST(CommandLineTest,AliasRequired)404759645eaSJustin Bogner TEST(CommandLineTest, AliasRequired) {
405759645eaSJustin Bogner   const char *opts1[] = { "-tool", "-option=x" };
406759645eaSJustin Bogner   const char *opts2[] = { "-tool", "-o", "x" };
407f15014ffSBenjamin Kramer   testAliasRequired(array_lengthof(opts1), opts1);
408f15014ffSBenjamin Kramer   testAliasRequired(array_lengthof(opts2), opts2);
409759645eaSJustin Bogner }
410759645eaSJustin Bogner 
TEST(CommandLineTest,HideUnrelatedOptions)4119e13af7aSChris Bieneman TEST(CommandLineTest, HideUnrelatedOptions) {
41268169362SChris Bieneman   StackOption<int> TestOption1("hide-option-1");
41368169362SChris Bieneman   StackOption<int> TestOption2("hide-option-2", cl::cat(TestCategory));
4149e13af7aSChris Bieneman 
4159e13af7aSChris Bieneman   cl::HideUnrelatedOptions(TestCategory);
4169e13af7aSChris Bieneman 
4179e13af7aSChris Bieneman   ASSERT_EQ(cl::ReallyHidden, TestOption1.getOptionHiddenFlag())
4189e13af7aSChris Bieneman       << "Failed to hide extra option.";
4199e13af7aSChris Bieneman   ASSERT_EQ(cl::NotHidden, TestOption2.getOptionHiddenFlag())
4209e13af7aSChris Bieneman       << "Hid extra option that should be visable.";
421831fc5e8SChris Bieneman 
42207670b3eSZachary Turner   StringMap<cl::Option *> &Map =
42307670b3eSZachary Turner       cl::getRegisteredOptions(*cl::TopLevelSubCommand);
424c32f8f34SYuanfang Chen   ASSERT_TRUE(Map.count("help") == (size_t)0 ||
425c32f8f34SYuanfang Chen               cl::NotHidden == Map["help"]->getOptionHiddenFlag())
426831fc5e8SChris Bieneman       << "Hid default option that should be visable.";
4279e13af7aSChris Bieneman }
428759645eaSJustin Bogner 
42968169362SChris Bieneman cl::OptionCategory TestCategory2("Test Options set 2", "Description");
43068169362SChris Bieneman 
TEST(CommandLineTest,HideUnrelatedOptionsMulti)43168169362SChris Bieneman TEST(CommandLineTest, HideUnrelatedOptionsMulti) {
43268169362SChris Bieneman   StackOption<int> TestOption1("multi-hide-option-1");
43368169362SChris Bieneman   StackOption<int> TestOption2("multi-hide-option-2", cl::cat(TestCategory));
43468169362SChris Bieneman   StackOption<int> TestOption3("multi-hide-option-3", cl::cat(TestCategory2));
43568169362SChris Bieneman 
43668169362SChris Bieneman   const cl::OptionCategory *VisibleCategories[] = {&TestCategory,
43768169362SChris Bieneman                                                    &TestCategory2};
43868169362SChris Bieneman 
43968169362SChris Bieneman   cl::HideUnrelatedOptions(makeArrayRef(VisibleCategories));
44068169362SChris Bieneman 
44168169362SChris Bieneman   ASSERT_EQ(cl::ReallyHidden, TestOption1.getOptionHiddenFlag())
44268169362SChris Bieneman       << "Failed to hide extra option.";
44368169362SChris Bieneman   ASSERT_EQ(cl::NotHidden, TestOption2.getOptionHiddenFlag())
44468169362SChris Bieneman       << "Hid extra option that should be visable.";
44568169362SChris Bieneman   ASSERT_EQ(cl::NotHidden, TestOption3.getOptionHiddenFlag())
44668169362SChris Bieneman       << "Hid extra option that should be visable.";
44768169362SChris Bieneman 
44807670b3eSZachary Turner   StringMap<cl::Option *> &Map =
44907670b3eSZachary Turner       cl::getRegisteredOptions(*cl::TopLevelSubCommand);
450c32f8f34SYuanfang Chen   ASSERT_TRUE(Map.count("help") == (size_t)0 ||
451c32f8f34SYuanfang Chen               cl::NotHidden == Map["help"]->getOptionHiddenFlag())
45268169362SChris Bieneman       << "Hid default option that should be visable.";
45368169362SChris Bieneman }
45468169362SChris Bieneman 
TEST(CommandLineTest,SetMultiValues)455bd0bddc1SFangrui Song TEST(CommandLineTest, SetMultiValues) {
456bd0bddc1SFangrui Song   StackOption<int> Option("option");
457bd0bddc1SFangrui Song   const char *args[] = {"prog", "-option=1", "-option=2"};
458bd0bddc1SFangrui Song   EXPECT_TRUE(cl::ParseCommandLineOptions(array_lengthof(args), args,
459bd0bddc1SFangrui Song                                           StringRef(), &llvm::nulls()));
460bd0bddc1SFangrui Song   EXPECT_EQ(Option, 2);
461bd0bddc1SFangrui Song }
462bd0bddc1SFangrui Song 
TEST(CommandLineTest,SetValueInSubcategories)46307670b3eSZachary Turner TEST(CommandLineTest, SetValueInSubcategories) {
46407670b3eSZachary Turner   cl::ResetCommandLineParser();
46507670b3eSZachary Turner 
46607670b3eSZachary Turner   StackSubCommand SC1("sc1", "First subcommand");
46707670b3eSZachary Turner   StackSubCommand SC2("sc2", "Second subcommand");
46807670b3eSZachary Turner 
46907670b3eSZachary Turner   StackOption<bool> TopLevelOpt("top-level", cl::init(false));
47007670b3eSZachary Turner   StackOption<bool> SC1Opt("sc1", cl::sub(SC1), cl::init(false));
47107670b3eSZachary Turner   StackOption<bool> SC2Opt("sc2", cl::sub(SC2), cl::init(false));
47207670b3eSZachary Turner 
47307670b3eSZachary Turner   EXPECT_FALSE(TopLevelOpt);
47407670b3eSZachary Turner   EXPECT_FALSE(SC1Opt);
47507670b3eSZachary Turner   EXPECT_FALSE(SC2Opt);
47607670b3eSZachary Turner   const char *args[] = {"prog", "-top-level"};
477e51ee066SEric Liu   EXPECT_TRUE(
478e51ee066SEric Liu       cl::ParseCommandLineOptions(2, args, StringRef(), &llvm::nulls()));
47907670b3eSZachary Turner   EXPECT_TRUE(TopLevelOpt);
48007670b3eSZachary Turner   EXPECT_FALSE(SC1Opt);
48107670b3eSZachary Turner   EXPECT_FALSE(SC2Opt);
48207670b3eSZachary Turner 
48307670b3eSZachary Turner   TopLevelOpt = false;
48407670b3eSZachary Turner 
48507670b3eSZachary Turner   cl::ResetAllOptionOccurrences();
48607670b3eSZachary Turner   EXPECT_FALSE(TopLevelOpt);
48707670b3eSZachary Turner   EXPECT_FALSE(SC1Opt);
48807670b3eSZachary Turner   EXPECT_FALSE(SC2Opt);
48907670b3eSZachary Turner   const char *args2[] = {"prog", "sc1", "-sc1"};
490e51ee066SEric Liu   EXPECT_TRUE(
491e51ee066SEric Liu       cl::ParseCommandLineOptions(3, args2, StringRef(), &llvm::nulls()));
49207670b3eSZachary Turner   EXPECT_FALSE(TopLevelOpt);
49307670b3eSZachary Turner   EXPECT_TRUE(SC1Opt);
49407670b3eSZachary Turner   EXPECT_FALSE(SC2Opt);
49507670b3eSZachary Turner 
49607670b3eSZachary Turner   SC1Opt = false;
49707670b3eSZachary Turner 
49807670b3eSZachary Turner   cl::ResetAllOptionOccurrences();
49907670b3eSZachary Turner   EXPECT_FALSE(TopLevelOpt);
50007670b3eSZachary Turner   EXPECT_FALSE(SC1Opt);
50107670b3eSZachary Turner   EXPECT_FALSE(SC2Opt);
50207670b3eSZachary Turner   const char *args3[] = {"prog", "sc2", "-sc2"};
503e51ee066SEric Liu   EXPECT_TRUE(
504e51ee066SEric Liu       cl::ParseCommandLineOptions(3, args3, StringRef(), &llvm::nulls()));
50507670b3eSZachary Turner   EXPECT_FALSE(TopLevelOpt);
50607670b3eSZachary Turner   EXPECT_FALSE(SC1Opt);
50707670b3eSZachary Turner   EXPECT_TRUE(SC2Opt);
50807670b3eSZachary Turner }
50907670b3eSZachary Turner 
TEST(CommandLineTest,LookupFailsInWrongSubCommand)51007670b3eSZachary Turner TEST(CommandLineTest, LookupFailsInWrongSubCommand) {
51107670b3eSZachary Turner   cl::ResetCommandLineParser();
51207670b3eSZachary Turner 
51307670b3eSZachary Turner   StackSubCommand SC1("sc1", "First subcommand");
51407670b3eSZachary Turner   StackSubCommand SC2("sc2", "Second subcommand");
51507670b3eSZachary Turner 
51607670b3eSZachary Turner   StackOption<bool> SC1Opt("sc1", cl::sub(SC1), cl::init(false));
51707670b3eSZachary Turner   StackOption<bool> SC2Opt("sc2", cl::sub(SC2), cl::init(false));
51807670b3eSZachary Turner 
519e51ee066SEric Liu   std::string Errs;
520e51ee066SEric Liu   raw_string_ostream OS(Errs);
521e51ee066SEric Liu 
52207670b3eSZachary Turner   const char *args[] = {"prog", "sc1", "-sc2"};
523e51ee066SEric Liu   EXPECT_FALSE(cl::ParseCommandLineOptions(3, args, StringRef(), &OS));
524e51ee066SEric Liu   OS.flush();
525e51ee066SEric Liu   EXPECT_FALSE(Errs.empty());
52607670b3eSZachary Turner }
52707670b3eSZachary Turner 
TEST(CommandLineTest,AddToAllSubCommands)52807670b3eSZachary Turner TEST(CommandLineTest, AddToAllSubCommands) {
52907670b3eSZachary Turner   cl::ResetCommandLineParser();
53007670b3eSZachary Turner 
53107670b3eSZachary Turner   StackSubCommand SC1("sc1", "First subcommand");
53207670b3eSZachary Turner   StackOption<bool> AllOpt("everywhere", cl::sub(*cl::AllSubCommands),
53307670b3eSZachary Turner                            cl::init(false));
53407670b3eSZachary Turner   StackSubCommand SC2("sc2", "Second subcommand");
53507670b3eSZachary Turner 
53607670b3eSZachary Turner   const char *args[] = {"prog", "-everywhere"};
53707670b3eSZachary Turner   const char *args2[] = {"prog", "sc1", "-everywhere"};
53807670b3eSZachary Turner   const char *args3[] = {"prog", "sc2", "-everywhere"};
53907670b3eSZachary Turner 
540e51ee066SEric Liu   std::string Errs;
541e51ee066SEric Liu   raw_string_ostream OS(Errs);
542e51ee066SEric Liu 
54307670b3eSZachary Turner   EXPECT_FALSE(AllOpt);
544e51ee066SEric Liu   EXPECT_TRUE(cl::ParseCommandLineOptions(2, args, StringRef(), &OS));
54507670b3eSZachary Turner   EXPECT_TRUE(AllOpt);
54607670b3eSZachary Turner 
54707670b3eSZachary Turner   AllOpt = false;
54807670b3eSZachary Turner 
54907670b3eSZachary Turner   cl::ResetAllOptionOccurrences();
55007670b3eSZachary Turner   EXPECT_FALSE(AllOpt);
551e51ee066SEric Liu   EXPECT_TRUE(cl::ParseCommandLineOptions(3, args2, StringRef(), &OS));
55207670b3eSZachary Turner   EXPECT_TRUE(AllOpt);
55307670b3eSZachary Turner 
55407670b3eSZachary Turner   AllOpt = false;
55507670b3eSZachary Turner 
55607670b3eSZachary Turner   cl::ResetAllOptionOccurrences();
55707670b3eSZachary Turner   EXPECT_FALSE(AllOpt);
558e51ee066SEric Liu   EXPECT_TRUE(cl::ParseCommandLineOptions(3, args3, StringRef(), &OS));
55907670b3eSZachary Turner   EXPECT_TRUE(AllOpt);
560e51ee066SEric Liu 
561e51ee066SEric Liu   // Since all parsing succeeded, the error message should be empty.
562e51ee066SEric Liu   OS.flush();
563e51ee066SEric Liu   EXPECT_TRUE(Errs.empty());
56407670b3eSZachary Turner }
56507670b3eSZachary Turner 
TEST(CommandLineTest,ReparseCommandLineOptions)56607670b3eSZachary Turner TEST(CommandLineTest, ReparseCommandLineOptions) {
56707670b3eSZachary Turner   cl::ResetCommandLineParser();
56807670b3eSZachary Turner 
56907670b3eSZachary Turner   StackOption<bool> TopLevelOpt("top-level", cl::sub(*cl::TopLevelSubCommand),
57007670b3eSZachary Turner                                 cl::init(false));
57107670b3eSZachary Turner 
57207670b3eSZachary Turner   const char *args[] = {"prog", "-top-level"};
57307670b3eSZachary Turner 
57407670b3eSZachary Turner   EXPECT_FALSE(TopLevelOpt);
575e51ee066SEric Liu   EXPECT_TRUE(
576e51ee066SEric Liu       cl::ParseCommandLineOptions(2, args, StringRef(), &llvm::nulls()));
57707670b3eSZachary Turner   EXPECT_TRUE(TopLevelOpt);
57807670b3eSZachary Turner 
57907670b3eSZachary Turner   TopLevelOpt = false;
58007670b3eSZachary Turner 
58107670b3eSZachary Turner   cl::ResetAllOptionOccurrences();
58207670b3eSZachary Turner   EXPECT_FALSE(TopLevelOpt);
583e51ee066SEric Liu   EXPECT_TRUE(
584e51ee066SEric Liu       cl::ParseCommandLineOptions(2, args, StringRef(), &llvm::nulls()));
58507670b3eSZachary Turner   EXPECT_TRUE(TopLevelOpt);
58607670b3eSZachary Turner }
58707670b3eSZachary Turner 
TEST(CommandLineTest,RemoveFromRegularSubCommand)58807670b3eSZachary Turner TEST(CommandLineTest, RemoveFromRegularSubCommand) {
58907670b3eSZachary Turner   cl::ResetCommandLineParser();
59007670b3eSZachary Turner 
59107670b3eSZachary Turner   StackSubCommand SC("sc", "Subcommand");
59207670b3eSZachary Turner   StackOption<bool> RemoveOption("remove-option", cl::sub(SC), cl::init(false));
59307670b3eSZachary Turner   StackOption<bool> KeepOption("keep-option", cl::sub(SC), cl::init(false));
59407670b3eSZachary Turner 
59507670b3eSZachary Turner   const char *args[] = {"prog", "sc", "-remove-option"};
59607670b3eSZachary Turner 
597e51ee066SEric Liu   std::string Errs;
598e51ee066SEric Liu   raw_string_ostream OS(Errs);
599e51ee066SEric Liu 
60007670b3eSZachary Turner   EXPECT_FALSE(RemoveOption);
601e51ee066SEric Liu   EXPECT_TRUE(cl::ParseCommandLineOptions(3, args, StringRef(), &OS));
60207670b3eSZachary Turner   EXPECT_TRUE(RemoveOption);
603e51ee066SEric Liu   OS.flush();
604e51ee066SEric Liu   EXPECT_TRUE(Errs.empty());
60507670b3eSZachary Turner 
60607670b3eSZachary Turner   RemoveOption.removeArgument();
60707670b3eSZachary Turner 
60807670b3eSZachary Turner   cl::ResetAllOptionOccurrences();
609e51ee066SEric Liu   EXPECT_FALSE(cl::ParseCommandLineOptions(3, args, StringRef(), &OS));
610e51ee066SEric Liu   OS.flush();
611e51ee066SEric Liu   EXPECT_FALSE(Errs.empty());
61207670b3eSZachary Turner }
61307670b3eSZachary Turner 
TEST(CommandLineTest,RemoveFromTopLevelSubCommand)61407670b3eSZachary Turner TEST(CommandLineTest, RemoveFromTopLevelSubCommand) {
61507670b3eSZachary Turner   cl::ResetCommandLineParser();
61607670b3eSZachary Turner 
61707670b3eSZachary Turner   StackOption<bool> TopLevelRemove(
61807670b3eSZachary Turner       "top-level-remove", cl::sub(*cl::TopLevelSubCommand), cl::init(false));
61907670b3eSZachary Turner   StackOption<bool> TopLevelKeep(
62007670b3eSZachary Turner       "top-level-keep", cl::sub(*cl::TopLevelSubCommand), cl::init(false));
62107670b3eSZachary Turner 
62207670b3eSZachary Turner   const char *args[] = {"prog", "-top-level-remove"};
62307670b3eSZachary Turner 
62407670b3eSZachary Turner   EXPECT_FALSE(TopLevelRemove);
625e51ee066SEric Liu   EXPECT_TRUE(
626e51ee066SEric Liu       cl::ParseCommandLineOptions(2, args, StringRef(), &llvm::nulls()));
62707670b3eSZachary Turner   EXPECT_TRUE(TopLevelRemove);
62807670b3eSZachary Turner 
62907670b3eSZachary Turner   TopLevelRemove.removeArgument();
63007670b3eSZachary Turner 
63107670b3eSZachary Turner   cl::ResetAllOptionOccurrences();
632e51ee066SEric Liu   EXPECT_FALSE(
633e51ee066SEric Liu       cl::ParseCommandLineOptions(2, args, StringRef(), &llvm::nulls()));
63407670b3eSZachary Turner }
63507670b3eSZachary Turner 
TEST(CommandLineTest,RemoveFromAllSubCommands)63607670b3eSZachary Turner TEST(CommandLineTest, RemoveFromAllSubCommands) {
63707670b3eSZachary Turner   cl::ResetCommandLineParser();
63807670b3eSZachary Turner 
63907670b3eSZachary Turner   StackSubCommand SC1("sc1", "First Subcommand");
64007670b3eSZachary Turner   StackSubCommand SC2("sc2", "Second Subcommand");
64107670b3eSZachary Turner   StackOption<bool> RemoveOption("remove-option", cl::sub(*cl::AllSubCommands),
64207670b3eSZachary Turner                                  cl::init(false));
64307670b3eSZachary Turner   StackOption<bool> KeepOption("keep-option", cl::sub(*cl::AllSubCommands),
64407670b3eSZachary Turner                                cl::init(false));
64507670b3eSZachary Turner 
64607670b3eSZachary Turner   const char *args0[] = {"prog", "-remove-option"};
64707670b3eSZachary Turner   const char *args1[] = {"prog", "sc1", "-remove-option"};
64807670b3eSZachary Turner   const char *args2[] = {"prog", "sc2", "-remove-option"};
64907670b3eSZachary Turner 
65007670b3eSZachary Turner   // It should work for all subcommands including the top-level.
65107670b3eSZachary Turner   EXPECT_FALSE(RemoveOption);
652e51ee066SEric Liu   EXPECT_TRUE(
653e51ee066SEric Liu       cl::ParseCommandLineOptions(2, args0, StringRef(), &llvm::nulls()));
65407670b3eSZachary Turner   EXPECT_TRUE(RemoveOption);
65507670b3eSZachary Turner 
65607670b3eSZachary Turner   RemoveOption = false;
65707670b3eSZachary Turner 
65807670b3eSZachary Turner   cl::ResetAllOptionOccurrences();
65907670b3eSZachary Turner   EXPECT_FALSE(RemoveOption);
660e51ee066SEric Liu   EXPECT_TRUE(
661e51ee066SEric Liu       cl::ParseCommandLineOptions(3, args1, StringRef(), &llvm::nulls()));
66207670b3eSZachary Turner   EXPECT_TRUE(RemoveOption);
66307670b3eSZachary Turner 
66407670b3eSZachary Turner   RemoveOption = false;
66507670b3eSZachary Turner 
66607670b3eSZachary Turner   cl::ResetAllOptionOccurrences();
66707670b3eSZachary Turner   EXPECT_FALSE(RemoveOption);
668e51ee066SEric Liu   EXPECT_TRUE(
669e51ee066SEric Liu       cl::ParseCommandLineOptions(3, args2, StringRef(), &llvm::nulls()));
67007670b3eSZachary Turner   EXPECT_TRUE(RemoveOption);
67107670b3eSZachary Turner 
67207670b3eSZachary Turner   RemoveOption.removeArgument();
67307670b3eSZachary Turner 
67407670b3eSZachary Turner   // It should not work for any subcommands including the top-level.
67507670b3eSZachary Turner   cl::ResetAllOptionOccurrences();
676e51ee066SEric Liu   EXPECT_FALSE(
677e51ee066SEric Liu       cl::ParseCommandLineOptions(2, args0, StringRef(), &llvm::nulls()));
67807670b3eSZachary Turner   cl::ResetAllOptionOccurrences();
679e51ee066SEric Liu   EXPECT_FALSE(
680e51ee066SEric Liu       cl::ParseCommandLineOptions(3, args1, StringRef(), &llvm::nulls()));
68107670b3eSZachary Turner   cl::ResetAllOptionOccurrences();
682e51ee066SEric Liu   EXPECT_FALSE(
683e51ee066SEric Liu       cl::ParseCommandLineOptions(3, args2, StringRef(), &llvm::nulls()));
68407670b3eSZachary Turner }
68507670b3eSZachary Turner 
TEST(CommandLineTest,GetRegisteredSubcommands)68627358cffSDean Michael Berris TEST(CommandLineTest, GetRegisteredSubcommands) {
68727358cffSDean Michael Berris   cl::ResetCommandLineParser();
68827358cffSDean Michael Berris 
68927358cffSDean Michael Berris   StackSubCommand SC1("sc1", "First Subcommand");
69027358cffSDean Michael Berris   StackOption<bool> Opt1("opt1", cl::sub(SC1), cl::init(false));
69127358cffSDean Michael Berris   StackSubCommand SC2("sc2", "Second subcommand");
69227358cffSDean Michael Berris   StackOption<bool> Opt2("opt2", cl::sub(SC2), cl::init(false));
69327358cffSDean Michael Berris 
69427358cffSDean Michael Berris   const char *args0[] = {"prog", "sc1"};
69527358cffSDean Michael Berris   const char *args1[] = {"prog", "sc2"};
69627358cffSDean Michael Berris 
697e51ee066SEric Liu   EXPECT_TRUE(
698e51ee066SEric Liu       cl::ParseCommandLineOptions(2, args0, StringRef(), &llvm::nulls()));
69927358cffSDean Michael Berris   EXPECT_FALSE(Opt1);
70027358cffSDean Michael Berris   EXPECT_FALSE(Opt2);
70127358cffSDean Michael Berris   for (auto *S : cl::getRegisteredSubcommands()) {
702fcae62d6SGalina Kistanova     if (*S) {
70327358cffSDean Michael Berris       EXPECT_EQ("sc1", S->getName());
70427358cffSDean Michael Berris     }
705fcae62d6SGalina Kistanova   }
70627358cffSDean Michael Berris 
70727358cffSDean Michael Berris   cl::ResetAllOptionOccurrences();
708e51ee066SEric Liu   EXPECT_TRUE(
709e51ee066SEric Liu       cl::ParseCommandLineOptions(2, args1, StringRef(), &llvm::nulls()));
71027358cffSDean Michael Berris   EXPECT_FALSE(Opt1);
71127358cffSDean Michael Berris   EXPECT_FALSE(Opt2);
71227358cffSDean Michael Berris   for (auto *S : cl::getRegisteredSubcommands()) {
713fcae62d6SGalina Kistanova     if (*S) {
71427358cffSDean Michael Berris       EXPECT_EQ("sc2", S->getName());
71527358cffSDean Michael Berris     }
71627358cffSDean Michael Berris   }
717fcae62d6SGalina Kistanova }
71827358cffSDean Michael Berris 
TEST(CommandLineTest,DefaultOptions)719b85f74a2SDon Hinton TEST(CommandLineTest, DefaultOptions) {
720b85f74a2SDon Hinton   cl::ResetCommandLineParser();
721b85f74a2SDon Hinton 
722b85f74a2SDon Hinton   StackOption<std::string> Bar("bar", cl::sub(*cl::AllSubCommands),
723b85f74a2SDon Hinton                                cl::DefaultOption);
724b85f74a2SDon Hinton   StackOption<std::string, cl::alias> Bar_Alias(
725b85f74a2SDon Hinton       "b", cl::desc("Alias for -bar"), cl::aliasopt(Bar), cl::DefaultOption);
726b85f74a2SDon Hinton 
727b85f74a2SDon Hinton   StackOption<bool> Foo("foo", cl::init(false), cl::sub(*cl::AllSubCommands),
728b85f74a2SDon Hinton                         cl::DefaultOption);
729b85f74a2SDon Hinton   StackOption<bool, cl::alias> Foo_Alias("f", cl::desc("Alias for -foo"),
730b85f74a2SDon Hinton                                          cl::aliasopt(Foo), cl::DefaultOption);
731b85f74a2SDon Hinton 
732b85f74a2SDon Hinton   StackSubCommand SC1("sc1", "First Subcommand");
733b85f74a2SDon Hinton   // Override "-b" and change type in sc1 SubCommand.
734b85f74a2SDon Hinton   StackOption<bool> SC1_B("b", cl::sub(SC1), cl::init(false));
735b85f74a2SDon Hinton   StackSubCommand SC2("sc2", "Second subcommand");
736b85f74a2SDon Hinton   // Override "-foo" and change type in sc2 SubCommand.  Note that this does not
737b85f74a2SDon Hinton   // affect "-f" alias, which continues to work correctly.
738b85f74a2SDon Hinton   StackOption<std::string> SC2_Foo("foo", cl::sub(SC2));
739b85f74a2SDon Hinton 
740b85f74a2SDon Hinton   const char *args0[] = {"prog", "-b", "args0 bar string", "-f"};
741b85f74a2SDon Hinton   EXPECT_TRUE(cl::ParseCommandLineOptions(sizeof(args0) / sizeof(char *), args0,
742b85f74a2SDon Hinton                                           StringRef(), &llvm::nulls()));
74338ac4093SArchibald Elliott   EXPECT_EQ(Bar, "args0 bar string");
744b85f74a2SDon Hinton   EXPECT_TRUE(Foo);
745b85f74a2SDon Hinton   EXPECT_FALSE(SC1_B);
746b85f74a2SDon Hinton   EXPECT_TRUE(SC2_Foo.empty());
747b85f74a2SDon Hinton 
748b85f74a2SDon Hinton   cl::ResetAllOptionOccurrences();
749b85f74a2SDon Hinton 
750b85f74a2SDon Hinton   const char *args1[] = {"prog", "sc1", "-b", "-bar", "args1 bar string", "-f"};
751b85f74a2SDon Hinton   EXPECT_TRUE(cl::ParseCommandLineOptions(sizeof(args1) / sizeof(char *), args1,
752b85f74a2SDon Hinton                                           StringRef(), &llvm::nulls()));
75338ac4093SArchibald Elliott   EXPECT_EQ(Bar, "args1 bar string");
754b85f74a2SDon Hinton   EXPECT_TRUE(Foo);
755b85f74a2SDon Hinton   EXPECT_TRUE(SC1_B);
756b85f74a2SDon Hinton   EXPECT_TRUE(SC2_Foo.empty());
757b85f74a2SDon Hinton   for (auto *S : cl::getRegisteredSubcommands()) {
758b85f74a2SDon Hinton     if (*S) {
759b85f74a2SDon Hinton       EXPECT_EQ("sc1", S->getName());
760b85f74a2SDon Hinton     }
761b85f74a2SDon Hinton   }
762b85f74a2SDon Hinton 
763b85f74a2SDon Hinton   cl::ResetAllOptionOccurrences();
764b85f74a2SDon Hinton 
765b85f74a2SDon Hinton   const char *args2[] = {"prog", "sc2", "-b", "args2 bar string",
766b85f74a2SDon Hinton                          "-f", "-foo", "foo string"};
767b85f74a2SDon Hinton   EXPECT_TRUE(cl::ParseCommandLineOptions(sizeof(args2) / sizeof(char *), args2,
768b85f74a2SDon Hinton                                           StringRef(), &llvm::nulls()));
76938ac4093SArchibald Elliott   EXPECT_EQ(Bar, "args2 bar string");
770b85f74a2SDon Hinton   EXPECT_TRUE(Foo);
771b85f74a2SDon Hinton   EXPECT_FALSE(SC1_B);
77238ac4093SArchibald Elliott   EXPECT_EQ(SC2_Foo, "foo string");
773b85f74a2SDon Hinton   for (auto *S : cl::getRegisteredSubcommands()) {
774b85f74a2SDon Hinton     if (*S) {
775b85f74a2SDon Hinton       EXPECT_EQ("sc2", S->getName());
776b85f74a2SDon Hinton     }
777b85f74a2SDon Hinton   }
778b85f74a2SDon Hinton   cl::ResetCommandLineParser();
779b85f74a2SDon Hinton }
780b85f74a2SDon Hinton 
TEST(CommandLineTest,ArgumentLimit)7818199dadaSSaleem Abdulrasool TEST(CommandLineTest, ArgumentLimit) {
7828199dadaSSaleem Abdulrasool   std::string args(32 * 4096, 'a');
7838199dadaSSaleem Abdulrasool   EXPECT_FALSE(llvm::sys::commandLineFitsWithinSystemLimits("cl", args.data()));
784dab898f9SSerge Pavlov   std::string args2(256, 'a');
785dab898f9SSerge Pavlov   EXPECT_TRUE(llvm::sys::commandLineFitsWithinSystemLimits("cl", args2.data()));
786a0ac6a92SPaul Robinson }
787a0ac6a92SPaul Robinson 
TEST(CommandLineTest,ArgumentLimitWindows)788a0ac6a92SPaul Robinson TEST(CommandLineTest, ArgumentLimitWindows) {
789a0ac6a92SPaul Robinson   if (!Triple(sys::getProcessTriple()).isOSWindows())
790a0ac6a92SPaul Robinson     GTEST_SKIP();
791dab898f9SSerge Pavlov   // We use 32000 as a limit for command line length. Program name ('cl'),
792dab898f9SSerge Pavlov   // separating spaces and termination null character occupy 5 symbols.
793dab898f9SSerge Pavlov   std::string long_arg(32000 - 5, 'b');
794dab898f9SSerge Pavlov   EXPECT_TRUE(
795dab898f9SSerge Pavlov       llvm::sys::commandLineFitsWithinSystemLimits("cl", long_arg.data()));
796dab898f9SSerge Pavlov   long_arg += 'b';
797dab898f9SSerge Pavlov   EXPECT_FALSE(
798dab898f9SSerge Pavlov       llvm::sys::commandLineFitsWithinSystemLimits("cl", long_arg.data()));
799dab898f9SSerge Pavlov }
8008199dadaSSaleem Abdulrasool 
TEST(CommandLineTest,ResponseFileWindows)801430c7ff7SDmitry Mikulin TEST(CommandLineTest, ResponseFileWindows) {
802430c7ff7SDmitry Mikulin   if (!Triple(sys::getProcessTriple()).isOSWindows())
803a0ac6a92SPaul Robinson     GTEST_SKIP();
804430c7ff7SDmitry Mikulin 
8055390e369SEric Liu   StackOption<std::string, cl::list<std::string>> InputFilenames(
806d0d1c416SFangrui Song       cl::Positional, cl::desc("<input files>"));
807430c7ff7SDmitry Mikulin   StackOption<bool> TopLevelOpt("top-level", cl::init(false));
808430c7ff7SDmitry Mikulin 
809430c7ff7SDmitry Mikulin   // Create response file.
810fad75598SSergej Jaskiewicz   TempFile ResponseFile("resp-", ".txt",
811fad75598SSergej Jaskiewicz                         "-top-level\npath\\dir\\file1\npath/dir/file2",
812fad75598SSergej Jaskiewicz                         /*Unique*/ true);
813430c7ff7SDmitry Mikulin 
814430c7ff7SDmitry Mikulin   llvm::SmallString<128> RspOpt;
815430c7ff7SDmitry Mikulin   RspOpt.append(1, '@');
816fad75598SSergej Jaskiewicz   RspOpt.append(ResponseFile.path());
817430c7ff7SDmitry Mikulin   const char *args[] = {"prog", RspOpt.c_str()};
818430c7ff7SDmitry Mikulin   EXPECT_FALSE(TopLevelOpt);
819430c7ff7SDmitry Mikulin   EXPECT_TRUE(
820430c7ff7SDmitry Mikulin       cl::ParseCommandLineOptions(2, args, StringRef(), &llvm::nulls()));
821430c7ff7SDmitry Mikulin   EXPECT_TRUE(TopLevelOpt);
82238ac4093SArchibald Elliott   EXPECT_EQ(InputFilenames[0], "path\\dir\\file1");
82338ac4093SArchibald Elliott   EXPECT_EQ(InputFilenames[1], "path/dir/file2");
824430c7ff7SDmitry Mikulin }
825430c7ff7SDmitry Mikulin 
TEST(CommandLineTest,ResponseFiles)8266ac8e034SSerge Pavlov TEST(CommandLineTest, ResponseFiles) {
827b3b37783SKadir Cetinkaya   vfs::InMemoryFileSystem FS;
828b3b37783SKadir Cetinkaya #ifdef _WIN32
829b3b37783SKadir Cetinkaya   const char *TestRoot = "C:\\";
830b3b37783SKadir Cetinkaya #else
831b3b37783SKadir Cetinkaya   const char *TestRoot = "/";
832b3b37783SKadir Cetinkaya #endif
833b3b37783SKadir Cetinkaya   FS.setCurrentWorkingDirectory(TestRoot);
8346ac8e034SSerge Pavlov 
8356ac8e034SSerge Pavlov   // Create included response file of first level.
836b3b37783SKadir Cetinkaya   llvm::StringRef IncludedFileName = "resp1";
837b3b37783SKadir Cetinkaya   FS.addFile(IncludedFileName, 0,
838b3b37783SKadir Cetinkaya              llvm::MemoryBuffer::getMemBuffer("-option_1 -option_2\n"
8396ac8e034SSerge Pavlov                                               "@incdir/resp2\n"
8405062cf59SShoaib Meenai                                               "-option_3=abcd\n"
8415062cf59SShoaib Meenai                                               "@incdir/resp3\n"
842b3b37783SKadir Cetinkaya                                               "-option_4=efjk\n"));
8436ac8e034SSerge Pavlov 
8446ac8e034SSerge Pavlov   // Directory for included file.
845b3b37783SKadir Cetinkaya   llvm::StringRef IncDir = "incdir";
8466ac8e034SSerge Pavlov 
8476ac8e034SSerge Pavlov   // Create included response file of second level.
8486ac8e034SSerge Pavlov   llvm::SmallString<128> IncludedFileName2;
8496ac8e034SSerge Pavlov   llvm::sys::path::append(IncludedFileName2, IncDir, "resp2");
850b3b37783SKadir Cetinkaya   FS.addFile(IncludedFileName2, 0,
851b3b37783SKadir Cetinkaya              MemoryBuffer::getMemBuffer("-option_21 -option_22\n"
852b3b37783SKadir Cetinkaya                                         "-option_23=abcd\n"));
8536ac8e034SSerge Pavlov 
8545062cf59SShoaib Meenai   // Create second included response file of second level.
8555062cf59SShoaib Meenai   llvm::SmallString<128> IncludedFileName3;
8565062cf59SShoaib Meenai   llvm::sys::path::append(IncludedFileName3, IncDir, "resp3");
857b3b37783SKadir Cetinkaya   FS.addFile(IncludedFileName3, 0,
858b3b37783SKadir Cetinkaya              MemoryBuffer::getMemBuffer("-option_31 -option_32\n"
859b3b37783SKadir Cetinkaya                                         "-option_33=abcd\n"));
8605062cf59SShoaib Meenai 
8616ac8e034SSerge Pavlov   // Prepare 'file' with reference to response file.
8626ac8e034SSerge Pavlov   SmallString<128> IncRef;
8636ac8e034SSerge Pavlov   IncRef.append(1, '@');
864b3b37783SKadir Cetinkaya   IncRef.append(IncludedFileName);
865b3b37783SKadir Cetinkaya   llvm::SmallVector<const char *, 4> Argv = {"test/test", "-flag_1",
866b3b37783SKadir Cetinkaya                                              IncRef.c_str(), "-flag_2"};
8676ac8e034SSerge Pavlov 
8686ac8e034SSerge Pavlov   // Expand response files.
8696ac8e034SSerge Pavlov   llvm::BumpPtrAllocator A;
8706ac8e034SSerge Pavlov   llvm::StringSaver Saver(A);
871b3b37783SKadir Cetinkaya   ASSERT_TRUE(llvm::cl::ExpandResponseFiles(
8729d37d0eaSJack Andersen       Saver, llvm::cl::TokenizeGNUCommandLine, Argv, false, true, false,
873ba7a92c0SNico Weber       /*CurrentDir=*/StringRef(TestRoot), FS));
874b3b37783SKadir Cetinkaya   EXPECT_THAT(Argv, testing::Pointwise(
875b3b37783SKadir Cetinkaya                         StringEquality(),
876b3b37783SKadir Cetinkaya                         {"test/test", "-flag_1", "-option_1", "-option_2",
877b3b37783SKadir Cetinkaya                          "-option_21", "-option_22", "-option_23=abcd",
878b3b37783SKadir Cetinkaya                          "-option_3=abcd", "-option_31", "-option_32",
879b3b37783SKadir Cetinkaya                          "-option_33=abcd", "-option_4=efjk", "-flag_2"}));
8806ac8e034SSerge Pavlov }
8816ac8e034SSerge Pavlov 
TEST(CommandLineTest,RecursiveResponseFiles)8820a61be96SShoaib Meenai TEST(CommandLineTest, RecursiveResponseFiles) {
883b3b37783SKadir Cetinkaya   vfs::InMemoryFileSystem FS;
884b3b37783SKadir Cetinkaya #ifdef _WIN32
885b3b37783SKadir Cetinkaya   const char *TestRoot = "C:\\";
886b3b37783SKadir Cetinkaya #else
887b3b37783SKadir Cetinkaya   const char *TestRoot = "/";
888b3b37783SKadir Cetinkaya #endif
889b3b37783SKadir Cetinkaya   FS.setCurrentWorkingDirectory(TestRoot);
8900a61be96SShoaib Meenai 
891b3b37783SKadir Cetinkaya   StringRef SelfFilePath = "self.rsp";
892b3b37783SKadir Cetinkaya   std::string SelfFileRef = ("@" + SelfFilePath).str();
8930a61be96SShoaib Meenai 
894b3b37783SKadir Cetinkaya   StringRef NestedFilePath = "nested.rsp";
895b3b37783SKadir Cetinkaya   std::string NestedFileRef = ("@" + NestedFilePath).str();
8960a61be96SShoaib Meenai 
897b3b37783SKadir Cetinkaya   StringRef FlagFilePath = "flag.rsp";
898b3b37783SKadir Cetinkaya   std::string FlagFileRef = ("@" + FlagFilePath).str();
8995062cf59SShoaib Meenai 
900b3b37783SKadir Cetinkaya   std::string SelfFileContents;
901b3b37783SKadir Cetinkaya   raw_string_ostream SelfFile(SelfFileContents);
9025062cf59SShoaib Meenai   SelfFile << "-option_1\n";
9035062cf59SShoaib Meenai   SelfFile << FlagFileRef << "\n";
9045062cf59SShoaib Meenai   SelfFile << NestedFileRef << "\n";
9055062cf59SShoaib Meenai   SelfFile << SelfFileRef << "\n";
906b3b37783SKadir Cetinkaya   FS.addFile(SelfFilePath, 0, MemoryBuffer::getMemBuffer(SelfFile.str()));
9075062cf59SShoaib Meenai 
908b3b37783SKadir Cetinkaya   std::string NestedFileContents;
909b3b37783SKadir Cetinkaya   raw_string_ostream NestedFile(NestedFileContents);
9105062cf59SShoaib Meenai   NestedFile << "-option_2\n";
9115062cf59SShoaib Meenai   NestedFile << FlagFileRef << "\n";
9125062cf59SShoaib Meenai   NestedFile << SelfFileRef << "\n";
9135062cf59SShoaib Meenai   NestedFile << NestedFileRef << "\n";
914b3b37783SKadir Cetinkaya   FS.addFile(NestedFilePath, 0, MemoryBuffer::getMemBuffer(NestedFile.str()));
9155062cf59SShoaib Meenai 
916b3b37783SKadir Cetinkaya   std::string FlagFileContents;
917b3b37783SKadir Cetinkaya   raw_string_ostream FlagFile(FlagFileContents);
9185062cf59SShoaib Meenai   FlagFile << "-option_x\n";
919b3b37783SKadir Cetinkaya   FS.addFile(FlagFilePath, 0, MemoryBuffer::getMemBuffer(FlagFile.str()));
9205062cf59SShoaib Meenai 
9215062cf59SShoaib Meenai   // Ensure:
9225062cf59SShoaib Meenai   // Recursive expansion terminates
9235062cf59SShoaib Meenai   // Recursive files never expand
9245062cf59SShoaib Meenai   // Non-recursive repeats are allowed
9255062cf59SShoaib Meenai   SmallVector<const char *, 4> Argv = {"test/test", SelfFileRef.c_str(),
9265062cf59SShoaib Meenai                                        "-option_3"};
9270a61be96SShoaib Meenai   BumpPtrAllocator A;
9280a61be96SShoaib Meenai   StringSaver Saver(A);
9290a61be96SShoaib Meenai #ifdef _WIN32
9300a61be96SShoaib Meenai   cl::TokenizerCallback Tokenizer = cl::TokenizeWindowsCommandLine;
9310a61be96SShoaib Meenai #else
9320a61be96SShoaib Meenai   cl::TokenizerCallback Tokenizer = cl::TokenizeGNUCommandLine;
9330a61be96SShoaib Meenai #endif
9349d37d0eaSJack Andersen   ASSERT_FALSE(
9359d37d0eaSJack Andersen       cl::ExpandResponseFiles(Saver, Tokenizer, Argv, false, false, false,
9369d37d0eaSJack Andersen                               /*CurrentDir=*/llvm::StringRef(TestRoot), FS));
9370a61be96SShoaib Meenai 
938b3b37783SKadir Cetinkaya   EXPECT_THAT(Argv,
939b3b37783SKadir Cetinkaya               testing::Pointwise(StringEquality(),
940b3b37783SKadir Cetinkaya                                  {"test/test", "-option_1", "-option_x",
941b3b37783SKadir Cetinkaya                                   "-option_2", "-option_x", SelfFileRef.c_str(),
942b3b37783SKadir Cetinkaya                                   NestedFileRef.c_str(), SelfFileRef.c_str(),
943b3b37783SKadir Cetinkaya                                   "-option_3"}));
9440a61be96SShoaib Meenai }
9450a61be96SShoaib Meenai 
TEST(CommandLineTest,ResponseFilesAtArguments)9461826095aSShoaib Meenai TEST(CommandLineTest, ResponseFilesAtArguments) {
947b3b37783SKadir Cetinkaya   vfs::InMemoryFileSystem FS;
948b3b37783SKadir Cetinkaya #ifdef _WIN32
949b3b37783SKadir Cetinkaya   const char *TestRoot = "C:\\";
950b3b37783SKadir Cetinkaya #else
951b3b37783SKadir Cetinkaya   const char *TestRoot = "/";
952b3b37783SKadir Cetinkaya #endif
953b3b37783SKadir Cetinkaya   FS.setCurrentWorkingDirectory(TestRoot);
9541826095aSShoaib Meenai 
955b3b37783SKadir Cetinkaya   StringRef ResponseFilePath = "test.rsp";
9561826095aSShoaib Meenai 
957b3b37783SKadir Cetinkaya   std::string ResponseFileContents;
958b3b37783SKadir Cetinkaya   raw_string_ostream ResponseFile(ResponseFileContents);
9591826095aSShoaib Meenai   ResponseFile << "-foo" << "\n";
9601826095aSShoaib Meenai   ResponseFile << "-bar" << "\n";
961b3b37783SKadir Cetinkaya   FS.addFile(ResponseFilePath, 0,
962b3b37783SKadir Cetinkaya              MemoryBuffer::getMemBuffer(ResponseFile.str()));
9631826095aSShoaib Meenai 
9641826095aSShoaib Meenai   // Ensure we expand rsp files after lots of non-rsp arguments starting with @.
9651826095aSShoaib Meenai   constexpr size_t NON_RSP_AT_ARGS = 64;
9661826095aSShoaib Meenai   SmallVector<const char *, 4> Argv = {"test/test"};
9671826095aSShoaib Meenai   Argv.append(NON_RSP_AT_ARGS, "@non_rsp_at_arg");
968b3b37783SKadir Cetinkaya   std::string ResponseFileRef = ("@" + ResponseFilePath).str();
9691826095aSShoaib Meenai   Argv.push_back(ResponseFileRef.c_str());
9701826095aSShoaib Meenai 
9711826095aSShoaib Meenai   BumpPtrAllocator A;
9721826095aSShoaib Meenai   StringSaver Saver(A);
973b3b37783SKadir Cetinkaya   ASSERT_FALSE(cl::ExpandResponseFiles(Saver, cl::TokenizeGNUCommandLine, Argv,
9749d37d0eaSJack Andersen                                        false, false, false,
975ba7a92c0SNico Weber                                        /*CurrentDir=*/StringRef(TestRoot), FS));
9761826095aSShoaib Meenai 
9771826095aSShoaib Meenai   // ASSERT instead of EXPECT to prevent potential out-of-bounds access.
9781826095aSShoaib Meenai   ASSERT_EQ(Argv.size(), 1 + NON_RSP_AT_ARGS + 2);
9791826095aSShoaib Meenai   size_t i = 0;
9801826095aSShoaib Meenai   EXPECT_STREQ(Argv[i++], "test/test");
9811826095aSShoaib Meenai   for (; i < 1 + NON_RSP_AT_ARGS; ++i)
9821826095aSShoaib Meenai     EXPECT_STREQ(Argv[i], "@non_rsp_at_arg");
9831826095aSShoaib Meenai   EXPECT_STREQ(Argv[i++], "-foo");
9841826095aSShoaib Meenai   EXPECT_STREQ(Argv[i++], "-bar");
9851826095aSShoaib Meenai }
9861826095aSShoaib Meenai 
TEST(CommandLineTest,ResponseFileRelativePath)987b3b37783SKadir Cetinkaya TEST(CommandLineTest, ResponseFileRelativePath) {
988b3b37783SKadir Cetinkaya   vfs::InMemoryFileSystem FS;
989b3b37783SKadir Cetinkaya #ifdef _WIN32
990b3b37783SKadir Cetinkaya   const char *TestRoot = "C:\\";
991b3b37783SKadir Cetinkaya #else
992b3b37783SKadir Cetinkaya   const char *TestRoot = "//net";
993b3b37783SKadir Cetinkaya #endif
994b3b37783SKadir Cetinkaya   FS.setCurrentWorkingDirectory(TestRoot);
995b3b37783SKadir Cetinkaya 
996b3b37783SKadir Cetinkaya   StringRef OuterFile = "dir/outer.rsp";
997b3b37783SKadir Cetinkaya   StringRef OuterFileContents = "@inner.rsp";
998b3b37783SKadir Cetinkaya   FS.addFile(OuterFile, 0, MemoryBuffer::getMemBuffer(OuterFileContents));
999b3b37783SKadir Cetinkaya 
1000b3b37783SKadir Cetinkaya   StringRef InnerFile = "dir/inner.rsp";
1001b3b37783SKadir Cetinkaya   StringRef InnerFileContents = "-flag";
1002b3b37783SKadir Cetinkaya   FS.addFile(InnerFile, 0, MemoryBuffer::getMemBuffer(InnerFileContents));
1003b3b37783SKadir Cetinkaya 
1004b3b37783SKadir Cetinkaya   SmallVector<const char *, 2> Argv = {"test/test", "@dir/outer.rsp"};
1005b3b37783SKadir Cetinkaya 
1006b3b37783SKadir Cetinkaya   BumpPtrAllocator A;
1007b3b37783SKadir Cetinkaya   StringSaver Saver(A);
1008b3b37783SKadir Cetinkaya   ASSERT_TRUE(cl::ExpandResponseFiles(Saver, cl::TokenizeGNUCommandLine, Argv,
10099d37d0eaSJack Andersen                                       false, true, false,
1010ba7a92c0SNico Weber                                       /*CurrentDir=*/StringRef(TestRoot), FS));
1011b3b37783SKadir Cetinkaya   EXPECT_THAT(Argv,
1012b3b37783SKadir Cetinkaya               testing::Pointwise(StringEquality(), {"test/test", "-flag"}));
1013b3b37783SKadir Cetinkaya }
1014b3b37783SKadir Cetinkaya 
TEST(CommandLineTest,ResponseFileEOLs)1015f5524745SReid Kleckner TEST(CommandLineTest, ResponseFileEOLs) {
1016f5524745SReid Kleckner   vfs::InMemoryFileSystem FS;
1017f5524745SReid Kleckner #ifdef _WIN32
1018f5524745SReid Kleckner   const char *TestRoot = "C:\\";
1019f5524745SReid Kleckner #else
1020f5524745SReid Kleckner   const char *TestRoot = "//net";
1021f5524745SReid Kleckner #endif
1022f5524745SReid Kleckner   FS.setCurrentWorkingDirectory(TestRoot);
1023f5524745SReid Kleckner   FS.addFile("eols.rsp", 0,
1024f5524745SReid Kleckner              MemoryBuffer::getMemBuffer("-Xclang -Wno-whatever\n input.cpp"));
1025f5524745SReid Kleckner   SmallVector<const char *, 2> Argv = {"clang", "@eols.rsp"};
1026f5524745SReid Kleckner   BumpPtrAllocator A;
1027f5524745SReid Kleckner   StringSaver Saver(A);
1028f5524745SReid Kleckner   ASSERT_TRUE(cl::ExpandResponseFiles(Saver, cl::TokenizeWindowsCommandLine,
10299d37d0eaSJack Andersen                                       Argv, true, true, false,
1030ba7a92c0SNico Weber                                       /*CurrentDir=*/StringRef(TestRoot), FS));
1031f5524745SReid Kleckner   const char *Expected[] = {"clang", "-Xclang", "-Wno-whatever", nullptr,
1032f5524745SReid Kleckner                             "input.cpp"};
1033f15014ffSBenjamin Kramer   ASSERT_EQ(array_lengthof(Expected), Argv.size());
1034f15014ffSBenjamin Kramer   for (size_t I = 0, E = array_lengthof(Expected); I < E; ++I) {
1035f5524745SReid Kleckner     if (Expected[I] == nullptr) {
1036f5524745SReid Kleckner       ASSERT_EQ(Argv[I], nullptr);
1037f5524745SReid Kleckner     } else {
1038f5524745SReid Kleckner       ASSERT_STREQ(Expected[I], Argv[I]);
1039f5524745SReid Kleckner     }
1040f5524745SReid Kleckner   }
1041f5524745SReid Kleckner }
1042f5524745SReid Kleckner 
TEST(CommandLineTest,SetDefautValue)10431587086fSEvgeny Mankov TEST(CommandLineTest, SetDefautValue) {
10441587086fSEvgeny Mankov   cl::ResetCommandLineParser();
10451587086fSEvgeny Mankov 
10461587086fSEvgeny Mankov   StackOption<std::string> Opt1("opt1", cl::init("true"));
10471587086fSEvgeny Mankov   StackOption<bool> Opt2("opt2", cl::init(true));
10481587086fSEvgeny Mankov   cl::alias Alias("alias", llvm::cl::aliasopt(Opt2));
10491587086fSEvgeny Mankov   StackOption<int> Opt3("opt3", cl::init(3));
10501587086fSEvgeny Mankov 
10511587086fSEvgeny Mankov   const char *args[] = {"prog", "-opt1=false", "-opt2", "-opt3"};
10521587086fSEvgeny Mankov 
10531587086fSEvgeny Mankov   EXPECT_TRUE(
10541587086fSEvgeny Mankov     cl::ParseCommandLineOptions(2, args, StringRef(), &llvm::nulls()));
10551587086fSEvgeny Mankov 
105638ac4093SArchibald Elliott   EXPECT_EQ(Opt1, "false");
10571587086fSEvgeny Mankov   EXPECT_TRUE(Opt2);
105838ac4093SArchibald Elliott   EXPECT_EQ(Opt3, 3);
10591587086fSEvgeny Mankov 
10601587086fSEvgeny Mankov   Opt2 = false;
10611587086fSEvgeny Mankov   Opt3 = 1;
10621587086fSEvgeny Mankov 
10631587086fSEvgeny Mankov   cl::ResetAllOptionOccurrences();
10641587086fSEvgeny Mankov 
10651587086fSEvgeny Mankov   for (auto &OM : cl::getRegisteredOptions(*cl::TopLevelSubCommand)) {
10661587086fSEvgeny Mankov     cl::Option *O = OM.second;
10671587086fSEvgeny Mankov     if (O->ArgStr == "opt2") {
10681587086fSEvgeny Mankov       continue;
10691587086fSEvgeny Mankov     }
10701587086fSEvgeny Mankov     O->setDefault();
10711587086fSEvgeny Mankov   }
10721587086fSEvgeny Mankov 
107338ac4093SArchibald Elliott   EXPECT_EQ(Opt1, "true");
10741587086fSEvgeny Mankov   EXPECT_TRUE(Opt2);
107538ac4093SArchibald Elliott   EXPECT_EQ(Opt3, 3);
10765390e369SEric Liu   Alias.removeArgument();
10771587086fSEvgeny Mankov }
10781587086fSEvgeny Mankov 
TEST(CommandLineTest,ReadConfigFile)10799f0ac82fSSerge Pavlov TEST(CommandLineTest, ReadConfigFile) {
10809f0ac82fSSerge Pavlov   llvm::SmallVector<const char *, 1> Argv;
10819f0ac82fSSerge Pavlov 
1082fad75598SSergej Jaskiewicz   TempDir TestDir("unittest", /*Unique*/ true);
10839d37d0eaSJack Andersen   TempDir TestSubDir(TestDir.path("subdir"), /*Unique*/ false);
10849f0ac82fSSerge Pavlov 
10859d37d0eaSJack Andersen   llvm::SmallString<128> TestCfg = TestDir.path("foo");
1086fad75598SSergej Jaskiewicz   TempFile ConfigFile(TestCfg, "",
1087fad75598SSergej Jaskiewicz                       "# Comment\n"
10889f0ac82fSSerge Pavlov                       "-option_1\n"
10899d37d0eaSJack Andersen                       "-option_2=<CFGDIR>/dir1\n"
10909d37d0eaSJack Andersen                       "-option_3=<CFGDIR>\n"
10919d37d0eaSJack Andersen                       "-option_4 <CFGDIR>\n"
10929d37d0eaSJack Andersen                       "-option_5=<CFG\\\n"
10939d37d0eaSJack Andersen                       "DIR>\n"
10949d37d0eaSJack Andersen                       "-option_6=<CFGDIR>/dir1,<CFGDIR>/dir2\n"
10959f0ac82fSSerge Pavlov                       "@subconfig\n"
10969d37d0eaSJack Andersen                       "-option_11=abcd\n"
10979d37d0eaSJack Andersen                       "-option_12=\\\n"
1098fad75598SSergej Jaskiewicz                       "cdef\n");
10999f0ac82fSSerge Pavlov 
11009d37d0eaSJack Andersen   llvm::SmallString<128> TestCfg2 = TestDir.path("subconfig");
1101fad75598SSergej Jaskiewicz   TempFile ConfigFile2(TestCfg2, "",
11029d37d0eaSJack Andersen                        "-option_7\n"
11039d37d0eaSJack Andersen                        "-option_8=<CFGDIR>/dir2\n"
11049d37d0eaSJack Andersen                        "@subdir/subfoo\n"
11059f0ac82fSSerge Pavlov                        "\n"
1106fad75598SSergej Jaskiewicz                        "   # comment\n");
11079f0ac82fSSerge Pavlov 
11089d37d0eaSJack Andersen   llvm::SmallString<128> TestCfg3 = TestSubDir.path("subfoo");
11099d37d0eaSJack Andersen   TempFile ConfigFile3(TestCfg3, "",
11109d37d0eaSJack Andersen                        "-option_9=<CFGDIR>/dir3\n"
11119d37d0eaSJack Andersen                        "@<CFGDIR>/subfoo2\n");
11129d37d0eaSJack Andersen 
11139d37d0eaSJack Andersen   llvm::SmallString<128> TestCfg4 = TestSubDir.path("subfoo2");
11149d37d0eaSJack Andersen   TempFile ConfigFile4(TestCfg4, "", "-option_10\n");
11159d37d0eaSJack Andersen 
11169f0ac82fSSerge Pavlov   // Make sure the current directory is not the directory where config files
11179f0ac82fSSerge Pavlov   // resides. In this case the code that expands response files will not find
11189f0ac82fSSerge Pavlov   // 'subconfig' unless it resolves nested inclusions relative to the including
11199f0ac82fSSerge Pavlov   // file.
11209f0ac82fSSerge Pavlov   llvm::SmallString<128> CurrDir;
1121fad75598SSergej Jaskiewicz   std::error_code EC = llvm::sys::fs::current_path(CurrDir);
11229f0ac82fSSerge Pavlov   EXPECT_TRUE(!EC);
11231def2579SDavid Blaikie   EXPECT_NE(CurrDir.str(), TestDir.path());
11249f0ac82fSSerge Pavlov 
11259f0ac82fSSerge Pavlov   llvm::BumpPtrAllocator A;
11269f0ac82fSSerge Pavlov   llvm::StringSaver Saver(A);
1127fad75598SSergej Jaskiewicz   bool Result = llvm::cl::readConfigFile(ConfigFile.path(), Saver, Argv);
11289f0ac82fSSerge Pavlov 
11299f0ac82fSSerge Pavlov   EXPECT_TRUE(Result);
11309d37d0eaSJack Andersen   EXPECT_EQ(Argv.size(), 13U);
11319f0ac82fSSerge Pavlov   EXPECT_STREQ(Argv[0], "-option_1");
11329d37d0eaSJack Andersen   EXPECT_STREQ(Argv[1],
11339d37d0eaSJack Andersen                ("-option_2=" + TestDir.path() + "/dir1").str().c_str());
11349d37d0eaSJack Andersen   EXPECT_STREQ(Argv[2], ("-option_3=" + TestDir.path()).str().c_str());
11359d37d0eaSJack Andersen   EXPECT_STREQ(Argv[3], "-option_4");
11369d37d0eaSJack Andersen   EXPECT_STREQ(Argv[4], TestDir.path().str().c_str());
11379d37d0eaSJack Andersen   EXPECT_STREQ(Argv[5], ("-option_5=" + TestDir.path()).str().c_str());
11389d37d0eaSJack Andersen   EXPECT_STREQ(Argv[6], ("-option_6=" + TestDir.path() + "/dir1," +
11399d37d0eaSJack Andersen                          TestDir.path() + "/dir2")
11409d37d0eaSJack Andersen                             .str()
11419d37d0eaSJack Andersen                             .c_str());
11429d37d0eaSJack Andersen   EXPECT_STREQ(Argv[7], "-option_7");
11439d37d0eaSJack Andersen   EXPECT_STREQ(Argv[8],
11449d37d0eaSJack Andersen                ("-option_8=" + TestDir.path() + "/dir2").str().c_str());
11459d37d0eaSJack Andersen   EXPECT_STREQ(Argv[9],
11469d37d0eaSJack Andersen                ("-option_9=" + TestSubDir.path() + "/dir3").str().c_str());
11479d37d0eaSJack Andersen   EXPECT_STREQ(Argv[10], "-option_10");
11489d37d0eaSJack Andersen   EXPECT_STREQ(Argv[11], "-option_11=abcd");
11499d37d0eaSJack Andersen   EXPECT_STREQ(Argv[12], "-option_12=cdef");
11509f0ac82fSSerge Pavlov }
11519f0ac82fSSerge Pavlov 
TEST(CommandLineTest,PositionalEatArgsError)11528248d7c6SKeno Fischer TEST(CommandLineTest, PositionalEatArgsError) {
1153cabf1e22SDon Hinton   cl::ResetCommandLineParser();
1154cabf1e22SDon Hinton 
11555390e369SEric Liu   StackOption<std::string, cl::list<std::string>> PosEatArgs(
11565390e369SEric Liu       "positional-eat-args", cl::Positional, cl::desc("<arguments>..."),
1157d86a206fSFangrui Song       cl::PositionalEatsArgs);
1158cabf1e22SDon Hinton   StackOption<std::string, cl::list<std::string>> PosEatArgs2(
1159cabf1e22SDon Hinton       "positional-eat-args2", cl::Positional, cl::desc("Some strings"),
1160*95a13425SFangrui Song       cl::PositionalEatsArgs);
11618248d7c6SKeno Fischer 
11628248d7c6SKeno Fischer   const char *args[] = {"prog", "-positional-eat-args=XXXX"};
11638248d7c6SKeno Fischer   const char *args2[] = {"prog", "-positional-eat-args=XXXX", "-foo"};
11648248d7c6SKeno Fischer   const char *args3[] = {"prog", "-positional-eat-args", "-foo"};
1165cabf1e22SDon Hinton   const char *args4[] = {"prog", "-positional-eat-args",
1166cabf1e22SDon Hinton                          "-foo", "-positional-eat-args2",
1167cabf1e22SDon Hinton                          "-bar", "foo"};
11688248d7c6SKeno Fischer 
11698248d7c6SKeno Fischer   std::string Errs;
11708248d7c6SKeno Fischer   raw_string_ostream OS(Errs);
11718248d7c6SKeno Fischer   EXPECT_FALSE(cl::ParseCommandLineOptions(2, args, StringRef(), &OS)); OS.flush();
11728248d7c6SKeno Fischer   EXPECT_FALSE(Errs.empty()); Errs.clear();
11738248d7c6SKeno Fischer   EXPECT_FALSE(cl::ParseCommandLineOptions(3, args2, StringRef(), &OS)); OS.flush();
11748248d7c6SKeno Fischer   EXPECT_FALSE(Errs.empty()); Errs.clear();
11758248d7c6SKeno Fischer   EXPECT_TRUE(cl::ParseCommandLineOptions(3, args3, StringRef(), &OS)); OS.flush();
1176cabf1e22SDon Hinton   EXPECT_TRUE(Errs.empty()); Errs.clear();
1177cabf1e22SDon Hinton 
1178cabf1e22SDon Hinton   cl::ResetAllOptionOccurrences();
1179cabf1e22SDon Hinton   EXPECT_TRUE(cl::ParseCommandLineOptions(6, args4, StringRef(), &OS)); OS.flush();
118038ac4093SArchibald Elliott   EXPECT_EQ(PosEatArgs.size(), 1u);
118138ac4093SArchibald Elliott   EXPECT_EQ(PosEatArgs2.size(), 2u);
11828248d7c6SKeno Fischer   EXPECT_TRUE(Errs.empty());
11838248d7c6SKeno Fischer }
11848248d7c6SKeno Fischer 
118512ba9ec9SHans Wennborg #ifdef _WIN32
checkSeparators(StringRef Path)1186f4d83c56SMartin Storsjö void checkSeparators(StringRef Path) {
1187f4d83c56SMartin Storsjö   char UndesiredSeparator = sys::path::get_separator()[0] == '/' ? '\\' : '/';
1188f4d83c56SMartin Storsjö   ASSERT_EQ(Path.find(UndesiredSeparator), StringRef::npos);
1189f4d83c56SMartin Storsjö }
1190f4d83c56SMartin Storsjö 
TEST(CommandLineTest,GetCommandLineArguments)119112ba9ec9SHans Wennborg TEST(CommandLineTest, GetCommandLineArguments) {
119212ba9ec9SHans Wennborg   int argc = __argc;
119312ba9ec9SHans Wennborg   char **argv = __argv;
119412ba9ec9SHans Wennborg 
119512ba9ec9SHans Wennborg   // GetCommandLineArguments is called in InitLLVM.
119612ba9ec9SHans Wennborg   llvm::InitLLVM X(argc, argv);
119712ba9ec9SHans Wennborg 
119812ba9ec9SHans Wennborg   EXPECT_EQ(llvm::sys::path::is_absolute(argv[0]),
119912ba9ec9SHans Wennborg             llvm::sys::path::is_absolute(__argv[0]));
1200f4d83c56SMartin Storsjö   checkSeparators(argv[0]);
120112ba9ec9SHans Wennborg 
120242f74e82SMartin Storsjö   EXPECT_TRUE(
120342f74e82SMartin Storsjö       llvm::sys::path::filename(argv[0]).equals_insensitive("supporttests.exe"))
120412ba9ec9SHans Wennborg       << "Filename of test executable is "
120512ba9ec9SHans Wennborg       << llvm::sys::path::filename(argv[0]);
120612ba9ec9SHans Wennborg }
120712ba9ec9SHans Wennborg #endif
120812ba9ec9SHans Wennborg 
12099652652aSJames Henderson class OutputRedirector {
12109652652aSJames Henderson public:
OutputRedirector(int RedirectFD)12119652652aSJames Henderson   OutputRedirector(int RedirectFD)
12129652652aSJames Henderson       : RedirectFD(RedirectFD), OldFD(dup(RedirectFD)) {
12139652652aSJames Henderson     if (OldFD == -1 ||
12149652652aSJames Henderson         sys::fs::createTemporaryFile("unittest-redirect", "", NewFD,
12159652652aSJames Henderson                                      FilePath) ||
12169652652aSJames Henderson         dup2(NewFD, RedirectFD) == -1)
12179652652aSJames Henderson       Valid = false;
12189652652aSJames Henderson   }
12199652652aSJames Henderson 
~OutputRedirector()12209652652aSJames Henderson   ~OutputRedirector() {
12219652652aSJames Henderson     dup2(OldFD, RedirectFD);
12229652652aSJames Henderson     close(OldFD);
12239652652aSJames Henderson     close(NewFD);
12249652652aSJames Henderson   }
12259652652aSJames Henderson 
12269652652aSJames Henderson   SmallVector<char, 128> FilePath;
12279652652aSJames Henderson   bool Valid = true;
12289652652aSJames Henderson 
12299652652aSJames Henderson private:
12309652652aSJames Henderson   int RedirectFD;
12319652652aSJames Henderson   int OldFD;
12329652652aSJames Henderson   int NewFD;
12339652652aSJames Henderson };
12349652652aSJames Henderson 
12359652652aSJames Henderson struct AutoDeleteFile {
12369652652aSJames Henderson   SmallVector<char, 128> FilePath;
~AutoDeleteFile__anon6509acef0111::AutoDeleteFile12379652652aSJames Henderson   ~AutoDeleteFile() {
12389652652aSJames Henderson     if (!FilePath.empty())
12399652652aSJames Henderson       sys::fs::remove(std::string(FilePath.data(), FilePath.size()));
12409652652aSJames Henderson   }
12419652652aSJames Henderson };
12429652652aSJames Henderson 
12439652652aSJames Henderson class PrintOptionInfoTest : public ::testing::Test {
12449652652aSJames Henderson public:
12459652652aSJames Henderson   // Return std::string because the output of a failing EXPECT check is
12469652652aSJames Henderson   // unreadable for StringRef. It also avoids any lifetime issues.
runTest(Ts...OptionAttributes)12479652652aSJames Henderson   template <typename... Ts> std::string runTest(Ts... OptionAttributes) {
12483cce2374SDavid L. Jones     outs().flush();  // flush any output from previous tests
12499652652aSJames Henderson     AutoDeleteFile File;
12509652652aSJames Henderson     {
12519652652aSJames Henderson       OutputRedirector Stdout(fileno(stdout));
12529652652aSJames Henderson       if (!Stdout.Valid)
12539652652aSJames Henderson         return "";
12549652652aSJames Henderson       File.FilePath = Stdout.FilePath;
12559652652aSJames Henderson 
12569652652aSJames Henderson       StackOption<OptionValue> TestOption(Opt, cl::desc(HelpText),
12579652652aSJames Henderson                                           OptionAttributes...);
1258c242be40SDon Hinton       printOptionInfo(TestOption, 26);
12599652652aSJames Henderson       outs().flush();
12609652652aSJames Henderson     }
12619652652aSJames Henderson     auto Buffer = MemoryBuffer::getFile(File.FilePath);
12629652652aSJames Henderson     if (!Buffer)
12639652652aSJames Henderson       return "";
12649652652aSJames Henderson     return Buffer->get()->getBuffer().str();
12659652652aSJames Henderson   }
12669652652aSJames Henderson 
12679652652aSJames Henderson   enum class OptionValue { Val };
12689652652aSJames Henderson   const StringRef Opt = "some-option";
12699652652aSJames Henderson   const StringRef HelpText = "some help";
12709652652aSJames Henderson 
12719652652aSJames Henderson private:
12729652652aSJames Henderson   // This is a workaround for cl::Option sub-classes having their
12739652652aSJames Henderson   // printOptionInfo functions private.
printOptionInfo(const cl::Option & O,size_t Width)12749652652aSJames Henderson   void printOptionInfo(const cl::Option &O, size_t Width) {
12759652652aSJames Henderson     O.printOptionInfo(Width);
12769652652aSJames Henderson   }
12779652652aSJames Henderson };
12789652652aSJames Henderson 
TEST_F(PrintOptionInfoTest,PrintOptionInfoValueOptionalWithoutSentinel)12799652652aSJames Henderson TEST_F(PrintOptionInfoTest, PrintOptionInfoValueOptionalWithoutSentinel) {
12809652652aSJames Henderson   std::string Output =
12819652652aSJames Henderson       runTest(cl::ValueOptional,
12829652652aSJames Henderson               cl::values(clEnumValN(OptionValue::Val, "v1", "desc1")));
12839652652aSJames Henderson 
12849652652aSJames Henderson   // clang-format off
1285c242be40SDon Hinton   EXPECT_EQ(Output, ("  --" + Opt + "=<value> - " + HelpText + "\n"
12869652652aSJames Henderson                      "    =v1                 -   desc1\n")
12879652652aSJames Henderson                         .str());
12889652652aSJames Henderson   // clang-format on
12899652652aSJames Henderson }
12909652652aSJames Henderson 
TEST_F(PrintOptionInfoTest,PrintOptionInfoValueOptionalWithSentinel)12919652652aSJames Henderson TEST_F(PrintOptionInfoTest, PrintOptionInfoValueOptionalWithSentinel) {
12929652652aSJames Henderson   std::string Output = runTest(
12939652652aSJames Henderson       cl::ValueOptional, cl::values(clEnumValN(OptionValue::Val, "v1", "desc1"),
12949652652aSJames Henderson                                     clEnumValN(OptionValue::Val, "", "")));
12959652652aSJames Henderson 
12969652652aSJames Henderson   // clang-format off
12979652652aSJames Henderson   EXPECT_EQ(Output,
1298c242be40SDon Hinton             ("  --" + Opt + "         - " + HelpText + "\n"
1299c242be40SDon Hinton              "  --" + Opt + "=<value> - " + HelpText + "\n"
13009652652aSJames Henderson              "    =v1                 -   desc1\n")
13019652652aSJames Henderson                 .str());
13029652652aSJames Henderson   // clang-format on
13039652652aSJames Henderson }
13049652652aSJames Henderson 
TEST_F(PrintOptionInfoTest,PrintOptionInfoValueOptionalWithSentinelWithHelp)13059652652aSJames Henderson TEST_F(PrintOptionInfoTest, PrintOptionInfoValueOptionalWithSentinelWithHelp) {
13069652652aSJames Henderson   std::string Output = runTest(
13079652652aSJames Henderson       cl::ValueOptional, cl::values(clEnumValN(OptionValue::Val, "v1", "desc1"),
13089652652aSJames Henderson                                     clEnumValN(OptionValue::Val, "", "desc2")));
13099652652aSJames Henderson 
13109652652aSJames Henderson   // clang-format off
1311c242be40SDon Hinton   EXPECT_EQ(Output, ("  --" + Opt + "         - " + HelpText + "\n"
1312c242be40SDon Hinton                      "  --" + Opt + "=<value> - " + HelpText + "\n"
13139652652aSJames Henderson                      "    =v1                 -   desc1\n"
13149652652aSJames Henderson                      "    =<empty>            -   desc2\n")
13159652652aSJames Henderson                         .str());
13169652652aSJames Henderson   // clang-format on
13179652652aSJames Henderson }
13189652652aSJames Henderson 
TEST_F(PrintOptionInfoTest,PrintOptionInfoValueRequiredWithEmptyValueName)13199652652aSJames Henderson TEST_F(PrintOptionInfoTest, PrintOptionInfoValueRequiredWithEmptyValueName) {
13209652652aSJames Henderson   std::string Output = runTest(
13219652652aSJames Henderson       cl::ValueRequired, cl::values(clEnumValN(OptionValue::Val, "v1", "desc1"),
13229652652aSJames Henderson                                     clEnumValN(OptionValue::Val, "", "")));
13239652652aSJames Henderson 
13249652652aSJames Henderson   // clang-format off
1325c242be40SDon Hinton   EXPECT_EQ(Output, ("  --" + Opt + "=<value> - " + HelpText + "\n"
13269652652aSJames Henderson                      "    =v1                 -   desc1\n"
13279652652aSJames Henderson                      "    =<empty>\n")
13289652652aSJames Henderson                         .str());
13299652652aSJames Henderson   // clang-format on
13309652652aSJames Henderson }
13319652652aSJames Henderson 
TEST_F(PrintOptionInfoTest,PrintOptionInfoEmptyValueDescription)13329652652aSJames Henderson TEST_F(PrintOptionInfoTest, PrintOptionInfoEmptyValueDescription) {
13339652652aSJames Henderson   std::string Output = runTest(
13349652652aSJames Henderson       cl::ValueRequired, cl::values(clEnumValN(OptionValue::Val, "v1", "")));
13359652652aSJames Henderson 
13369652652aSJames Henderson   // clang-format off
13379652652aSJames Henderson   EXPECT_EQ(Output,
1338c242be40SDon Hinton             ("  --" + Opt + "=<value> - " + HelpText + "\n"
13399652652aSJames Henderson              "    =v1\n").str());
13409652652aSJames Henderson   // clang-format on
13419652652aSJames Henderson }
13429652652aSJames Henderson 
TEST_F(PrintOptionInfoTest,PrintOptionInfoMultilineValueDescription)1343e3f02302SJoachim Meyer TEST_F(PrintOptionInfoTest, PrintOptionInfoMultilineValueDescription) {
1344e3f02302SJoachim Meyer   std::string Output =
1345e3f02302SJoachim Meyer       runTest(cl::ValueRequired,
1346e3f02302SJoachim Meyer               cl::values(clEnumValN(OptionValue::Val, "v1",
1347e3f02302SJoachim Meyer                                     "This is the first enum value\n"
1348e3f02302SJoachim Meyer                                     "which has a really long description\n"
1349e3f02302SJoachim Meyer                                     "thus it is multi-line."),
1350e3f02302SJoachim Meyer                          clEnumValN(OptionValue::Val, "",
1351e3f02302SJoachim Meyer                                     "This is an unnamed enum value option\n"
1352e3f02302SJoachim Meyer                                     "Should be indented as well")));
1353e3f02302SJoachim Meyer 
1354e3f02302SJoachim Meyer   // clang-format off
1355e3f02302SJoachim Meyer   EXPECT_EQ(Output,
1356e3f02302SJoachim Meyer             ("  --" + Opt + "=<value> - " + HelpText + "\n"
1357e3f02302SJoachim Meyer              "    =v1                 -   This is the first enum value\n"
1358e3f02302SJoachim Meyer              "                            which has a really long description\n"
1359e3f02302SJoachim Meyer              "                            thus it is multi-line.\n"
1360e3f02302SJoachim Meyer              "    =<empty>            -   This is an unnamed enum value option\n"
1361e3f02302SJoachim Meyer              "                            Should be indented as well\n").str());
1362e3f02302SJoachim Meyer   // clang-format on
1363e3f02302SJoachim Meyer }
1364e3f02302SJoachim Meyer 
13659652652aSJames Henderson class GetOptionWidthTest : public ::testing::Test {
13669652652aSJames Henderson public:
13679652652aSJames Henderson   enum class OptionValue { Val };
13689652652aSJames Henderson 
13699652652aSJames Henderson   template <typename... Ts>
runTest(StringRef ArgName,Ts...OptionAttributes)13709652652aSJames Henderson   size_t runTest(StringRef ArgName, Ts... OptionAttributes) {
13719652652aSJames Henderson     StackOption<OptionValue> TestOption(ArgName, cl::desc("some help"),
13729652652aSJames Henderson                                         OptionAttributes...);
13739652652aSJames Henderson     return getOptionWidth(TestOption);
13749652652aSJames Henderson   }
13759652652aSJames Henderson 
13769652652aSJames Henderson private:
13779652652aSJames Henderson   // This is a workaround for cl::Option sub-classes having their
13789652652aSJames Henderson   // printOptionInfo
13799652652aSJames Henderson   // functions private.
getOptionWidth(const cl::Option & O)13809652652aSJames Henderson   size_t getOptionWidth(const cl::Option &O) { return O.getOptionWidth(); }
13819652652aSJames Henderson };
13829652652aSJames Henderson 
TEST_F(GetOptionWidthTest,GetOptionWidthArgNameLonger)13839652652aSJames Henderson TEST_F(GetOptionWidthTest, GetOptionWidthArgNameLonger) {
13849652652aSJames Henderson   StringRef ArgName("a-long-argument-name");
1385c242be40SDon Hinton   size_t ExpectedStrSize = ("  --" + ArgName + "=<value> - ").str().size();
13869652652aSJames Henderson   EXPECT_EQ(
13879652652aSJames Henderson       runTest(ArgName, cl::values(clEnumValN(OptionValue::Val, "v", "help"))),
13889652652aSJames Henderson       ExpectedStrSize);
13899652652aSJames Henderson }
13909652652aSJames Henderson 
TEST_F(GetOptionWidthTest,GetOptionWidthFirstOptionNameLonger)13919652652aSJames Henderson TEST_F(GetOptionWidthTest, GetOptionWidthFirstOptionNameLonger) {
13929652652aSJames Henderson   StringRef OptName("a-long-option-name");
13939652652aSJames Henderson   size_t ExpectedStrSize = ("    =" + OptName + " - ").str().size();
13949652652aSJames Henderson   EXPECT_EQ(
13959652652aSJames Henderson       runTest("a", cl::values(clEnumValN(OptionValue::Val, OptName, "help"),
13969652652aSJames Henderson                               clEnumValN(OptionValue::Val, "b", "help"))),
13979652652aSJames Henderson       ExpectedStrSize);
13989652652aSJames Henderson }
13999652652aSJames Henderson 
TEST_F(GetOptionWidthTest,GetOptionWidthSecondOptionNameLonger)14009652652aSJames Henderson TEST_F(GetOptionWidthTest, GetOptionWidthSecondOptionNameLonger) {
14019652652aSJames Henderson   StringRef OptName("a-long-option-name");
14029652652aSJames Henderson   size_t ExpectedStrSize = ("    =" + OptName + " - ").str().size();
14039652652aSJames Henderson   EXPECT_EQ(
14049652652aSJames Henderson       runTest("a", cl::values(clEnumValN(OptionValue::Val, "b", "help"),
14059652652aSJames Henderson                               clEnumValN(OptionValue::Val, OptName, "help"))),
14069652652aSJames Henderson       ExpectedStrSize);
14079652652aSJames Henderson }
14089652652aSJames Henderson 
TEST_F(GetOptionWidthTest,GetOptionWidthEmptyOptionNameLonger)14099652652aSJames Henderson TEST_F(GetOptionWidthTest, GetOptionWidthEmptyOptionNameLonger) {
14109652652aSJames Henderson   size_t ExpectedStrSize = StringRef("    =<empty> - ").size();
14119652652aSJames Henderson   // The length of a=<value> (including indentation) is actually the same as the
14129652652aSJames Henderson   // =<empty> string, so it is impossible to distinguish via testing the case
14139652652aSJames Henderson   // where the empty string is picked from where the option name is picked.
14149652652aSJames Henderson   EXPECT_EQ(runTest("a", cl::values(clEnumValN(OptionValue::Val, "b", "help"),
14159652652aSJames Henderson                                     clEnumValN(OptionValue::Val, "", "help"))),
14169652652aSJames Henderson             ExpectedStrSize);
14179652652aSJames Henderson }
14189652652aSJames Henderson 
TEST_F(GetOptionWidthTest,GetOptionWidthValueOptionalEmptyOptionWithNoDescription)14199652652aSJames Henderson TEST_F(GetOptionWidthTest,
14209652652aSJames Henderson        GetOptionWidthValueOptionalEmptyOptionWithNoDescription) {
14219652652aSJames Henderson   StringRef ArgName("a");
14229652652aSJames Henderson   // The length of a=<value> (including indentation) is actually the same as the
14239652652aSJames Henderson   // =<empty> string, so it is impossible to distinguish via testing the case
14249652652aSJames Henderson   // where the empty string is ignored from where it is not ignored.
14259652652aSJames Henderson   // The dash will not actually be printed, but the space it would take up is
14269652652aSJames Henderson   // included to ensure a consistent column width.
14279652652aSJames Henderson   size_t ExpectedStrSize = ("  -" + ArgName + "=<value> - ").str().size();
14289652652aSJames Henderson   EXPECT_EQ(runTest(ArgName, cl::ValueOptional,
14299652652aSJames Henderson                     cl::values(clEnumValN(OptionValue::Val, "value", "help"),
14309652652aSJames Henderson                                clEnumValN(OptionValue::Val, "", ""))),
14319652652aSJames Henderson             ExpectedStrSize);
14329652652aSJames Henderson }
14339652652aSJames Henderson 
TEST_F(GetOptionWidthTest,GetOptionWidthValueRequiredEmptyOptionWithNoDescription)14349652652aSJames Henderson TEST_F(GetOptionWidthTest,
14359652652aSJames Henderson        GetOptionWidthValueRequiredEmptyOptionWithNoDescription) {
14369652652aSJames Henderson   // The length of a=<value> (including indentation) is actually the same as the
14379652652aSJames Henderson   // =<empty> string, so it is impossible to distinguish via testing the case
14389652652aSJames Henderson   // where the empty string is picked from where the option name is picked
14399652652aSJames Henderson   size_t ExpectedStrSize = StringRef("    =<empty> - ").size();
14409652652aSJames Henderson   EXPECT_EQ(runTest("a", cl::ValueRequired,
14419652652aSJames Henderson                     cl::values(clEnumValN(OptionValue::Val, "value", "help"),
14429652652aSJames Henderson                                clEnumValN(OptionValue::Val, "", ""))),
14439652652aSJames Henderson             ExpectedStrSize);
14449652652aSJames Henderson }
14459652652aSJames Henderson 
TEST(CommandLineTest,PrefixOptions)1446f929a0f8SThomas Preud'homme TEST(CommandLineTest, PrefixOptions) {
1447f929a0f8SThomas Preud'homme   cl::ResetCommandLineParser();
1448f929a0f8SThomas Preud'homme 
1449f929a0f8SThomas Preud'homme   StackOption<std::string, cl::list<std::string>> IncludeDirs(
1450f929a0f8SThomas Preud'homme       "I", cl::Prefix, cl::desc("Declare an include directory"));
1451f929a0f8SThomas Preud'homme 
1452f929a0f8SThomas Preud'homme   // Test non-prefixed variant works with cl::Prefix options.
1453f929a0f8SThomas Preud'homme   EXPECT_TRUE(IncludeDirs.empty());
1454f929a0f8SThomas Preud'homme   const char *args[] = {"prog", "-I=/usr/include"};
1455f929a0f8SThomas Preud'homme   EXPECT_TRUE(
1456f929a0f8SThomas Preud'homme       cl::ParseCommandLineOptions(2, args, StringRef(), &llvm::nulls()));
145738ac4093SArchibald Elliott   EXPECT_EQ(IncludeDirs.size(), 1u);
145838ac4093SArchibald Elliott   EXPECT_EQ(IncludeDirs.front().compare("/usr/include"), 0);
1459f929a0f8SThomas Preud'homme 
1460f929a0f8SThomas Preud'homme   IncludeDirs.erase(IncludeDirs.begin());
1461f929a0f8SThomas Preud'homme   cl::ResetAllOptionOccurrences();
1462f929a0f8SThomas Preud'homme 
1463f929a0f8SThomas Preud'homme   // Test non-prefixed variant works with cl::Prefix options when value is
1464f929a0f8SThomas Preud'homme   // passed in following argument.
1465f929a0f8SThomas Preud'homme   EXPECT_TRUE(IncludeDirs.empty());
1466f929a0f8SThomas Preud'homme   const char *args2[] = {"prog", "-I", "/usr/include"};
1467f929a0f8SThomas Preud'homme   EXPECT_TRUE(
1468f929a0f8SThomas Preud'homme       cl::ParseCommandLineOptions(3, args2, StringRef(), &llvm::nulls()));
146938ac4093SArchibald Elliott   EXPECT_EQ(IncludeDirs.size(), 1u);
147038ac4093SArchibald Elliott   EXPECT_EQ(IncludeDirs.front().compare("/usr/include"), 0);
1471f929a0f8SThomas Preud'homme 
1472f929a0f8SThomas Preud'homme   IncludeDirs.erase(IncludeDirs.begin());
1473f929a0f8SThomas Preud'homme   cl::ResetAllOptionOccurrences();
1474f929a0f8SThomas Preud'homme 
1475f929a0f8SThomas Preud'homme   // Test prefixed variant works with cl::Prefix options.
1476f929a0f8SThomas Preud'homme   EXPECT_TRUE(IncludeDirs.empty());
1477f929a0f8SThomas Preud'homme   const char *args3[] = {"prog", "-I/usr/include"};
1478f929a0f8SThomas Preud'homme   EXPECT_TRUE(
1479f929a0f8SThomas Preud'homme       cl::ParseCommandLineOptions(2, args3, StringRef(), &llvm::nulls()));
148038ac4093SArchibald Elliott   EXPECT_EQ(IncludeDirs.size(), 1u);
148138ac4093SArchibald Elliott   EXPECT_EQ(IncludeDirs.front().compare("/usr/include"), 0);
1482f929a0f8SThomas Preud'homme 
1483f929a0f8SThomas Preud'homme   StackOption<std::string, cl::list<std::string>> MacroDefs(
1484f929a0f8SThomas Preud'homme       "D", cl::AlwaysPrefix, cl::desc("Define a macro"),
1485f929a0f8SThomas Preud'homme       cl::value_desc("MACRO[=VALUE]"));
1486f929a0f8SThomas Preud'homme 
1487f929a0f8SThomas Preud'homme   cl::ResetAllOptionOccurrences();
1488f929a0f8SThomas Preud'homme 
1489f929a0f8SThomas Preud'homme   // Test non-prefixed variant does not work with cl::AlwaysPrefix options:
1490f929a0f8SThomas Preud'homme   // equal sign is part of the value.
1491f929a0f8SThomas Preud'homme   EXPECT_TRUE(MacroDefs.empty());
1492f929a0f8SThomas Preud'homme   const char *args4[] = {"prog", "-D=HAVE_FOO"};
1493f929a0f8SThomas Preud'homme   EXPECT_TRUE(
1494f929a0f8SThomas Preud'homme       cl::ParseCommandLineOptions(2, args4, StringRef(), &llvm::nulls()));
149538ac4093SArchibald Elliott   EXPECT_EQ(MacroDefs.size(), 1u);
149638ac4093SArchibald Elliott   EXPECT_EQ(MacroDefs.front().compare("=HAVE_FOO"), 0);
1497f929a0f8SThomas Preud'homme 
1498f929a0f8SThomas Preud'homme   MacroDefs.erase(MacroDefs.begin());
1499f929a0f8SThomas Preud'homme   cl::ResetAllOptionOccurrences();
1500f929a0f8SThomas Preud'homme 
1501f929a0f8SThomas Preud'homme   // Test non-prefixed variant does not allow value to be passed in following
1502f929a0f8SThomas Preud'homme   // argument with cl::AlwaysPrefix options.
1503f929a0f8SThomas Preud'homme   EXPECT_TRUE(MacroDefs.empty());
1504f929a0f8SThomas Preud'homme   const char *args5[] = {"prog", "-D", "HAVE_FOO"};
1505f929a0f8SThomas Preud'homme   EXPECT_FALSE(
1506f929a0f8SThomas Preud'homme       cl::ParseCommandLineOptions(3, args5, StringRef(), &llvm::nulls()));
1507f929a0f8SThomas Preud'homme   EXPECT_TRUE(MacroDefs.empty());
1508f929a0f8SThomas Preud'homme 
1509f929a0f8SThomas Preud'homme   cl::ResetAllOptionOccurrences();
1510f929a0f8SThomas Preud'homme 
1511f929a0f8SThomas Preud'homme   // Test prefixed variant works with cl::AlwaysPrefix options.
1512f929a0f8SThomas Preud'homme   EXPECT_TRUE(MacroDefs.empty());
1513f929a0f8SThomas Preud'homme   const char *args6[] = {"prog", "-DHAVE_FOO"};
1514f929a0f8SThomas Preud'homme   EXPECT_TRUE(
1515f929a0f8SThomas Preud'homme       cl::ParseCommandLineOptions(2, args6, StringRef(), &llvm::nulls()));
151638ac4093SArchibald Elliott   EXPECT_EQ(MacroDefs.size(), 1u);
151738ac4093SArchibald Elliott   EXPECT_EQ(MacroDefs.front().compare("HAVE_FOO"), 0);
1518f929a0f8SThomas Preud'homme }
1519f929a0f8SThomas Preud'homme 
TEST(CommandLineTest,GroupingWithValue)1520875f0582SIgor Kudrin TEST(CommandLineTest, GroupingWithValue) {
1521875f0582SIgor Kudrin   cl::ResetCommandLineParser();
1522875f0582SIgor Kudrin 
1523875f0582SIgor Kudrin   StackOption<bool> OptF("f", cl::Grouping, cl::desc("Some flag"));
1524a38432ceSIgor Kudrin   StackOption<bool> OptB("b", cl::Grouping, cl::desc("Another flag"));
1525a38432ceSIgor Kudrin   StackOption<bool> OptD("d", cl::Grouping, cl::ValueDisallowed,
1526a38432ceSIgor Kudrin                          cl::desc("ValueDisallowed option"));
1527875f0582SIgor Kudrin   StackOption<std::string> OptV("v", cl::Grouping,
1528a38432ceSIgor Kudrin                                 cl::desc("ValueRequired option"));
1529a38432ceSIgor Kudrin   StackOption<std::string> OptO("o", cl::Grouping, cl::ValueOptional,
1530a38432ceSIgor Kudrin                                 cl::desc("ValueOptional option"));
1531875f0582SIgor Kudrin 
1532875f0582SIgor Kudrin   // Should be possible to use an option which requires a value
1533875f0582SIgor Kudrin   // at the end of a group.
1534875f0582SIgor Kudrin   const char *args1[] = {"prog", "-fv", "val1"};
1535875f0582SIgor Kudrin   EXPECT_TRUE(
1536875f0582SIgor Kudrin       cl::ParseCommandLineOptions(3, args1, StringRef(), &llvm::nulls()));
1537875f0582SIgor Kudrin   EXPECT_TRUE(OptF);
1538875f0582SIgor Kudrin   EXPECT_STREQ("val1", OptV.c_str());
1539a38432ceSIgor Kudrin   OptV.clear();
1540875f0582SIgor Kudrin   cl::ResetAllOptionOccurrences();
1541875f0582SIgor Kudrin 
1542875f0582SIgor Kudrin   // Should not crash if it is accidentally used elsewhere in the group.
1543875f0582SIgor Kudrin   const char *args2[] = {"prog", "-vf", "val2"};
1544875f0582SIgor Kudrin   EXPECT_FALSE(
1545875f0582SIgor Kudrin       cl::ParseCommandLineOptions(3, args2, StringRef(), &llvm::nulls()));
1546a38432ceSIgor Kudrin   OptV.clear();
1547a38432ceSIgor Kudrin   cl::ResetAllOptionOccurrences();
1548a38432ceSIgor Kudrin 
1549a38432ceSIgor Kudrin   // Should allow the "opt=value" form at the end of the group
1550a38432ceSIgor Kudrin   const char *args3[] = {"prog", "-fv=val3"};
1551a38432ceSIgor Kudrin   EXPECT_TRUE(
1552a38432ceSIgor Kudrin       cl::ParseCommandLineOptions(2, args3, StringRef(), &llvm::nulls()));
1553a38432ceSIgor Kudrin   EXPECT_TRUE(OptF);
1554a38432ceSIgor Kudrin   EXPECT_STREQ("val3", OptV.c_str());
1555a38432ceSIgor Kudrin   OptV.clear();
1556a38432ceSIgor Kudrin   cl::ResetAllOptionOccurrences();
1557a38432ceSIgor Kudrin 
1558a38432ceSIgor Kudrin   // Should allow assigning a value for a ValueOptional option
1559a38432ceSIgor Kudrin   // at the end of the group
1560a38432ceSIgor Kudrin   const char *args4[] = {"prog", "-fo=val4"};
1561a38432ceSIgor Kudrin   EXPECT_TRUE(
1562a38432ceSIgor Kudrin       cl::ParseCommandLineOptions(2, args4, StringRef(), &llvm::nulls()));
1563a38432ceSIgor Kudrin   EXPECT_TRUE(OptF);
1564a38432ceSIgor Kudrin   EXPECT_STREQ("val4", OptO.c_str());
1565a38432ceSIgor Kudrin   OptO.clear();
1566a38432ceSIgor Kudrin   cl::ResetAllOptionOccurrences();
1567a38432ceSIgor Kudrin 
1568a38432ceSIgor Kudrin   // Should assign an empty value if a ValueOptional option is used elsewhere
1569a38432ceSIgor Kudrin   // in the group.
1570a38432ceSIgor Kudrin   const char *args5[] = {"prog", "-fob"};
1571a38432ceSIgor Kudrin   EXPECT_TRUE(
1572a38432ceSIgor Kudrin       cl::ParseCommandLineOptions(2, args5, StringRef(), &llvm::nulls()));
1573a38432ceSIgor Kudrin   EXPECT_TRUE(OptF);
1574a38432ceSIgor Kudrin   EXPECT_EQ(1, OptO.getNumOccurrences());
1575a38432ceSIgor Kudrin   EXPECT_EQ(1, OptB.getNumOccurrences());
1576a38432ceSIgor Kudrin   EXPECT_TRUE(OptO.empty());
1577a38432ceSIgor Kudrin   cl::ResetAllOptionOccurrences();
1578a38432ceSIgor Kudrin 
1579a38432ceSIgor Kudrin   // Should not allow an assignment for a ValueDisallowed option.
1580a38432ceSIgor Kudrin   const char *args6[] = {"prog", "-fd=false"};
1581a38432ceSIgor Kudrin   EXPECT_FALSE(
1582a38432ceSIgor Kudrin       cl::ParseCommandLineOptions(2, args6, StringRef(), &llvm::nulls()));
1583a38432ceSIgor Kudrin }
1584a38432ceSIgor Kudrin 
TEST(CommandLineTest,GroupingAndPrefix)1585a38432ceSIgor Kudrin TEST(CommandLineTest, GroupingAndPrefix) {
1586a38432ceSIgor Kudrin   cl::ResetCommandLineParser();
1587a38432ceSIgor Kudrin 
1588a38432ceSIgor Kudrin   StackOption<bool> OptF("f", cl::Grouping, cl::desc("Some flag"));
1589a38432ceSIgor Kudrin   StackOption<bool> OptB("b", cl::Grouping, cl::desc("Another flag"));
1590a38432ceSIgor Kudrin   StackOption<std::string> OptP("p", cl::Prefix, cl::Grouping,
1591a38432ceSIgor Kudrin                                 cl::desc("Prefix and Grouping"));
1592a38432ceSIgor Kudrin   StackOption<std::string> OptA("a", cl::AlwaysPrefix, cl::Grouping,
1593a38432ceSIgor Kudrin                                 cl::desc("AlwaysPrefix and Grouping"));
1594a38432ceSIgor Kudrin 
1595a38432ceSIgor Kudrin   // Should be possible to use a cl::Prefix option without grouping.
1596a38432ceSIgor Kudrin   const char *args1[] = {"prog", "-pval1"};
1597a38432ceSIgor Kudrin   EXPECT_TRUE(
1598a38432ceSIgor Kudrin       cl::ParseCommandLineOptions(2, args1, StringRef(), &llvm::nulls()));
1599a38432ceSIgor Kudrin   EXPECT_STREQ("val1", OptP.c_str());
1600a38432ceSIgor Kudrin   OptP.clear();
1601a38432ceSIgor Kudrin   cl::ResetAllOptionOccurrences();
1602a38432ceSIgor Kudrin 
1603a38432ceSIgor Kudrin   // Should be possible to pass a value in a separate argument.
1604a38432ceSIgor Kudrin   const char *args2[] = {"prog", "-p", "val2"};
1605a38432ceSIgor Kudrin   EXPECT_TRUE(
1606a38432ceSIgor Kudrin       cl::ParseCommandLineOptions(3, args2, StringRef(), &llvm::nulls()));
1607a38432ceSIgor Kudrin   EXPECT_STREQ("val2", OptP.c_str());
1608a38432ceSIgor Kudrin   OptP.clear();
1609a38432ceSIgor Kudrin   cl::ResetAllOptionOccurrences();
1610a38432ceSIgor Kudrin 
1611a38432ceSIgor Kudrin   // The "-opt=value" form should work, too.
1612a38432ceSIgor Kudrin   const char *args3[] = {"prog", "-p=val3"};
1613a38432ceSIgor Kudrin   EXPECT_TRUE(
1614a38432ceSIgor Kudrin       cl::ParseCommandLineOptions(2, args3, StringRef(), &llvm::nulls()));
1615a38432ceSIgor Kudrin   EXPECT_STREQ("val3", OptP.c_str());
1616a38432ceSIgor Kudrin   OptP.clear();
1617a38432ceSIgor Kudrin   cl::ResetAllOptionOccurrences();
1618a38432ceSIgor Kudrin 
1619a38432ceSIgor Kudrin   // All three previous cases should work the same way if an option with both
1620a38432ceSIgor Kudrin   // cl::Prefix and cl::Grouping modifiers is used at the end of a group.
1621a38432ceSIgor Kudrin   const char *args4[] = {"prog", "-fpval4"};
1622a38432ceSIgor Kudrin   EXPECT_TRUE(
1623a38432ceSIgor Kudrin       cl::ParseCommandLineOptions(2, args4, StringRef(), &llvm::nulls()));
1624a38432ceSIgor Kudrin   EXPECT_TRUE(OptF);
1625a38432ceSIgor Kudrin   EXPECT_STREQ("val4", OptP.c_str());
1626a38432ceSIgor Kudrin   OptP.clear();
1627a38432ceSIgor Kudrin   cl::ResetAllOptionOccurrences();
1628a38432ceSIgor Kudrin 
1629a38432ceSIgor Kudrin   const char *args5[] = {"prog", "-fp", "val5"};
1630a38432ceSIgor Kudrin   EXPECT_TRUE(
1631a38432ceSIgor Kudrin       cl::ParseCommandLineOptions(3, args5, StringRef(), &llvm::nulls()));
1632a38432ceSIgor Kudrin   EXPECT_TRUE(OptF);
1633a38432ceSIgor Kudrin   EXPECT_STREQ("val5", OptP.c_str());
1634a38432ceSIgor Kudrin   OptP.clear();
1635a38432ceSIgor Kudrin   cl::ResetAllOptionOccurrences();
1636a38432ceSIgor Kudrin 
1637a38432ceSIgor Kudrin   const char *args6[] = {"prog", "-fp=val6"};
1638a38432ceSIgor Kudrin   EXPECT_TRUE(
1639a38432ceSIgor Kudrin       cl::ParseCommandLineOptions(2, args6, StringRef(), &llvm::nulls()));
1640a38432ceSIgor Kudrin   EXPECT_TRUE(OptF);
1641a38432ceSIgor Kudrin   EXPECT_STREQ("val6", OptP.c_str());
1642a38432ceSIgor Kudrin   OptP.clear();
1643a38432ceSIgor Kudrin   cl::ResetAllOptionOccurrences();
1644a38432ceSIgor Kudrin 
1645a38432ceSIgor Kudrin   // Should assign a value even if the part after a cl::Prefix option is equal
1646a38432ceSIgor Kudrin   // to the name of another option.
1647a38432ceSIgor Kudrin   const char *args7[] = {"prog", "-fpb"};
1648a38432ceSIgor Kudrin   EXPECT_TRUE(
1649a38432ceSIgor Kudrin       cl::ParseCommandLineOptions(2, args7, StringRef(), &llvm::nulls()));
1650a38432ceSIgor Kudrin   EXPECT_TRUE(OptF);
1651a38432ceSIgor Kudrin   EXPECT_STREQ("b", OptP.c_str());
1652a38432ceSIgor Kudrin   EXPECT_FALSE(OptB);
1653a38432ceSIgor Kudrin   OptP.clear();
1654a38432ceSIgor Kudrin   cl::ResetAllOptionOccurrences();
1655a38432ceSIgor Kudrin 
1656a38432ceSIgor Kudrin   // Should be possible to use a cl::AlwaysPrefix option without grouping.
1657a38432ceSIgor Kudrin   const char *args8[] = {"prog", "-aval8"};
1658a38432ceSIgor Kudrin   EXPECT_TRUE(
1659a38432ceSIgor Kudrin       cl::ParseCommandLineOptions(2, args8, StringRef(), &llvm::nulls()));
1660a38432ceSIgor Kudrin   EXPECT_STREQ("val8", OptA.c_str());
1661a38432ceSIgor Kudrin   OptA.clear();
1662a38432ceSIgor Kudrin   cl::ResetAllOptionOccurrences();
1663a38432ceSIgor Kudrin 
1664a38432ceSIgor Kudrin   // Should not be possible to pass a value in a separate argument.
1665a38432ceSIgor Kudrin   const char *args9[] = {"prog", "-a", "val9"};
1666a38432ceSIgor Kudrin   EXPECT_FALSE(
1667a38432ceSIgor Kudrin       cl::ParseCommandLineOptions(3, args9, StringRef(), &llvm::nulls()));
1668a38432ceSIgor Kudrin   cl::ResetAllOptionOccurrences();
1669a38432ceSIgor Kudrin 
1670a38432ceSIgor Kudrin   // With the "-opt=value" form, the "=" symbol should be preserved.
1671a38432ceSIgor Kudrin   const char *args10[] = {"prog", "-a=val10"};
1672a38432ceSIgor Kudrin   EXPECT_TRUE(
1673a38432ceSIgor Kudrin       cl::ParseCommandLineOptions(2, args10, StringRef(), &llvm::nulls()));
1674a38432ceSIgor Kudrin   EXPECT_STREQ("=val10", OptA.c_str());
1675a38432ceSIgor Kudrin   OptA.clear();
1676a38432ceSIgor Kudrin   cl::ResetAllOptionOccurrences();
1677a38432ceSIgor Kudrin 
1678a38432ceSIgor Kudrin   // All three previous cases should work the same way if an option with both
1679a38432ceSIgor Kudrin   // cl::AlwaysPrefix and cl::Grouping modifiers is used at the end of a group.
1680a38432ceSIgor Kudrin   const char *args11[] = {"prog", "-faval11"};
1681a38432ceSIgor Kudrin   EXPECT_TRUE(
1682a38432ceSIgor Kudrin       cl::ParseCommandLineOptions(2, args11, StringRef(), &llvm::nulls()));
1683a38432ceSIgor Kudrin   EXPECT_TRUE(OptF);
1684a38432ceSIgor Kudrin   EXPECT_STREQ("val11", OptA.c_str());
1685a38432ceSIgor Kudrin   OptA.clear();
1686a38432ceSIgor Kudrin   cl::ResetAllOptionOccurrences();
1687a38432ceSIgor Kudrin 
1688a38432ceSIgor Kudrin   const char *args12[] = {"prog", "-fa", "val12"};
1689a38432ceSIgor Kudrin   EXPECT_FALSE(
1690a38432ceSIgor Kudrin       cl::ParseCommandLineOptions(3, args12, StringRef(), &llvm::nulls()));
1691a38432ceSIgor Kudrin   cl::ResetAllOptionOccurrences();
1692a38432ceSIgor Kudrin 
1693a38432ceSIgor Kudrin   const char *args13[] = {"prog", "-fa=val13"};
1694a38432ceSIgor Kudrin   EXPECT_TRUE(
1695a38432ceSIgor Kudrin       cl::ParseCommandLineOptions(2, args13, StringRef(), &llvm::nulls()));
1696a38432ceSIgor Kudrin   EXPECT_TRUE(OptF);
1697a38432ceSIgor Kudrin   EXPECT_STREQ("=val13", OptA.c_str());
1698a38432ceSIgor Kudrin   OptA.clear();
1699a38432ceSIgor Kudrin   cl::ResetAllOptionOccurrences();
1700a38432ceSIgor Kudrin 
1701a38432ceSIgor Kudrin   // Should assign a value even if the part after a cl::AlwaysPrefix option
1702a38432ceSIgor Kudrin   // is equal to the name of another option.
1703a38432ceSIgor Kudrin   const char *args14[] = {"prog", "-fab"};
1704a38432ceSIgor Kudrin   EXPECT_TRUE(
1705a38432ceSIgor Kudrin       cl::ParseCommandLineOptions(2, args14, StringRef(), &llvm::nulls()));
1706a38432ceSIgor Kudrin   EXPECT_TRUE(OptF);
1707a38432ceSIgor Kudrin   EXPECT_STREQ("b", OptA.c_str());
1708a38432ceSIgor Kudrin   EXPECT_FALSE(OptB);
1709a38432ceSIgor Kudrin   OptA.clear();
1710a38432ceSIgor Kudrin   cl::ResetAllOptionOccurrences();
1711875f0582SIgor Kudrin }
1712875f0582SIgor Kudrin 
TEST(CommandLineTest,LongOptions)17130303e8a3SDon Hinton TEST(CommandLineTest, LongOptions) {
17140303e8a3SDon Hinton   cl::ResetCommandLineParser();
17150303e8a3SDon Hinton 
17160303e8a3SDon Hinton   StackOption<bool> OptA("a", cl::desc("Some flag"));
17170303e8a3SDon Hinton   StackOption<bool> OptBLong("long-flag", cl::desc("Some long flag"));
17180303e8a3SDon Hinton   StackOption<bool, cl::alias> OptB("b", cl::desc("Alias to --long-flag"),
17190303e8a3SDon Hinton                                     cl::aliasopt(OptBLong));
17200303e8a3SDon Hinton   StackOption<std::string> OptAB("ab", cl::desc("Another long option"));
17210303e8a3SDon Hinton 
17220303e8a3SDon Hinton   std::string Errs;
17230303e8a3SDon Hinton   raw_string_ostream OS(Errs);
17240303e8a3SDon Hinton 
17250303e8a3SDon Hinton   const char *args1[] = {"prog", "-a", "-ab", "val1"};
17260303e8a3SDon Hinton   const char *args2[] = {"prog", "-a", "--ab", "val1"};
17270303e8a3SDon Hinton   const char *args3[] = {"prog", "-ab", "--ab", "val1"};
17280303e8a3SDon Hinton 
17290303e8a3SDon Hinton   //
17300303e8a3SDon Hinton   // The following tests treat `-` and `--` the same, and always match the
17310303e8a3SDon Hinton   // longest string.
17320303e8a3SDon Hinton   //
17330303e8a3SDon Hinton 
17340303e8a3SDon Hinton   EXPECT_TRUE(
17350303e8a3SDon Hinton       cl::ParseCommandLineOptions(4, args1, StringRef(), &OS)); OS.flush();
17360303e8a3SDon Hinton   EXPECT_TRUE(OptA);
17370303e8a3SDon Hinton   EXPECT_FALSE(OptBLong);
17380303e8a3SDon Hinton   EXPECT_STREQ("val1", OptAB.c_str());
17390303e8a3SDon Hinton   EXPECT_TRUE(Errs.empty()); Errs.clear();
17400303e8a3SDon Hinton   cl::ResetAllOptionOccurrences();
17410303e8a3SDon Hinton 
17420303e8a3SDon Hinton   EXPECT_TRUE(
17430303e8a3SDon Hinton       cl::ParseCommandLineOptions(4, args2, StringRef(), &OS)); OS.flush();
17440303e8a3SDon Hinton   EXPECT_TRUE(OptA);
17450303e8a3SDon Hinton   EXPECT_FALSE(OptBLong);
17460303e8a3SDon Hinton   EXPECT_STREQ("val1", OptAB.c_str());
17470303e8a3SDon Hinton   EXPECT_TRUE(Errs.empty()); Errs.clear();
17480303e8a3SDon Hinton   cl::ResetAllOptionOccurrences();
17490303e8a3SDon Hinton 
17500303e8a3SDon Hinton   // Fails because `-ab` and `--ab` are treated the same and appear more than
17510303e8a3SDon Hinton   // once.  Also, `val1` is unexpected.
17520303e8a3SDon Hinton   EXPECT_FALSE(
17530303e8a3SDon Hinton       cl::ParseCommandLineOptions(4, args3, StringRef(), &OS)); OS.flush();
17540303e8a3SDon Hinton   outs()<< Errs << "\n";
17550303e8a3SDon Hinton   EXPECT_FALSE(Errs.empty()); Errs.clear();
17560303e8a3SDon Hinton   cl::ResetAllOptionOccurrences();
17570303e8a3SDon Hinton 
17580303e8a3SDon Hinton   //
17590303e8a3SDon Hinton   // The following tests treat `-` and `--` differently, with `-` for short, and
17600303e8a3SDon Hinton   // `--` for long options.
17610303e8a3SDon Hinton   //
17620303e8a3SDon Hinton 
17630303e8a3SDon Hinton   // Fails because `-ab` is treated as `-a -b`, so `-a` is seen twice, and
17640303e8a3SDon Hinton   // `val1` is unexpected.
17650303e8a3SDon Hinton   EXPECT_FALSE(cl::ParseCommandLineOptions(4, args1, StringRef(),
17660303e8a3SDon Hinton                                            &OS, nullptr, true)); OS.flush();
17670303e8a3SDon Hinton   EXPECT_FALSE(Errs.empty()); Errs.clear();
17680303e8a3SDon Hinton   cl::ResetAllOptionOccurrences();
17690303e8a3SDon Hinton 
17700303e8a3SDon Hinton   // Works because `-a` is treated differently than `--ab`.
17710303e8a3SDon Hinton   EXPECT_TRUE(cl::ParseCommandLineOptions(4, args2, StringRef(),
17720303e8a3SDon Hinton                                            &OS, nullptr, true)); OS.flush();
17730303e8a3SDon Hinton   EXPECT_TRUE(Errs.empty()); Errs.clear();
17740303e8a3SDon Hinton   cl::ResetAllOptionOccurrences();
17750303e8a3SDon Hinton 
17760303e8a3SDon Hinton   // Works because `-ab` is treated as `-a -b`, and `--ab` is a long option.
17770303e8a3SDon Hinton   EXPECT_TRUE(cl::ParseCommandLineOptions(4, args3, StringRef(),
17780303e8a3SDon Hinton                                            &OS, nullptr, true));
17790303e8a3SDon Hinton   EXPECT_TRUE(OptA);
17800303e8a3SDon Hinton   EXPECT_TRUE(OptBLong);
17810303e8a3SDon Hinton   EXPECT_STREQ("val1", OptAB.c_str());
17820303e8a3SDon Hinton   OS.flush();
17830303e8a3SDon Hinton   EXPECT_TRUE(Errs.empty()); Errs.clear();
17840303e8a3SDon Hinton   cl::ResetAllOptionOccurrences();
17850303e8a3SDon Hinton }
1786405e8368SDon Hinton 
TEST(CommandLineTest,OptionErrorMessage)1787405e8368SDon Hinton TEST(CommandLineTest, OptionErrorMessage) {
1788405e8368SDon Hinton   // When there is an error, we expect some error message like:
1789405e8368SDon Hinton   //   prog: for the -a option: [...]
1790405e8368SDon Hinton   //
1791405e8368SDon Hinton   // Test whether the "for the -a option"-part is correctly formatted.
1792405e8368SDon Hinton   cl::ResetCommandLineParser();
1793405e8368SDon Hinton 
1794405e8368SDon Hinton   StackOption<bool> OptA("a", cl::desc("Some option"));
1795405e8368SDon Hinton   StackOption<bool> OptLong("long", cl::desc("Some long option"));
1796405e8368SDon Hinton 
1797405e8368SDon Hinton   std::string Errs;
1798405e8368SDon Hinton   raw_string_ostream OS(Errs);
1799405e8368SDon Hinton 
1800405e8368SDon Hinton   OptA.error("custom error", OS);
1801405e8368SDon Hinton   OS.flush();
180238ac4093SArchibald Elliott   EXPECT_NE(Errs.find("for the -a option:"), std::string::npos);
1803405e8368SDon Hinton   Errs.clear();
1804405e8368SDon Hinton 
1805405e8368SDon Hinton   OptLong.error("custom error", OS);
1806405e8368SDon Hinton   OS.flush();
180738ac4093SArchibald Elliott   EXPECT_NE(Errs.find("for the --long option:"), std::string::npos);
1808405e8368SDon Hinton   Errs.clear();
1809405e8368SDon Hinton 
1810405e8368SDon Hinton   cl::ResetAllOptionOccurrences();
1811405e8368SDon Hinton }
1812405e8368SDon Hinton 
TEST(CommandLineTest,OptionErrorMessageSuggest)1813405e8368SDon Hinton TEST(CommandLineTest, OptionErrorMessageSuggest) {
1814405e8368SDon Hinton   // When there is an error, and the edit-distance is not very large,
1815405e8368SDon Hinton   // we expect some error message like:
1816405e8368SDon Hinton   //   prog: did you mean '--option'?
1817405e8368SDon Hinton   //
1818405e8368SDon Hinton   // Test whether this message is well-formatted.
1819405e8368SDon Hinton   cl::ResetCommandLineParser();
1820405e8368SDon Hinton 
1821405e8368SDon Hinton   StackOption<bool> OptLong("aluminium", cl::desc("Some long option"));
1822405e8368SDon Hinton 
1823405e8368SDon Hinton   const char *args[] = {"prog", "--aluminum"};
1824405e8368SDon Hinton 
1825405e8368SDon Hinton   std::string Errs;
1826405e8368SDon Hinton   raw_string_ostream OS(Errs);
1827405e8368SDon Hinton 
1828405e8368SDon Hinton   EXPECT_FALSE(cl::ParseCommandLineOptions(2, args, StringRef(), &OS));
1829405e8368SDon Hinton   OS.flush();
183038ac4093SArchibald Elliott   EXPECT_NE(Errs.find("prog: Did you mean '--aluminium'?\n"),
1831405e8368SDon Hinton             std::string::npos);
1832405e8368SDon Hinton   Errs.clear();
1833405e8368SDon Hinton 
1834405e8368SDon Hinton   cl::ResetAllOptionOccurrences();
1835405e8368SDon Hinton }
18366555995aSDon Hinton 
TEST(CommandLineTest,OptionErrorMessageSuggestNoHidden)18375c621900SMichał Górny TEST(CommandLineTest, OptionErrorMessageSuggestNoHidden) {
18385c621900SMichał Górny   // We expect that 'really hidden' option do not show up in option
18395c621900SMichał Górny   // suggestions.
18405c621900SMichał Górny   cl::ResetCommandLineParser();
18415c621900SMichał Górny 
18425c621900SMichał Górny   StackOption<bool> OptLong("aluminium", cl::desc("Some long option"));
18435c621900SMichał Górny   StackOption<bool> OptLong2("aluminum", cl::desc("Bad option"),
18445c621900SMichał Górny                              cl::ReallyHidden);
18455c621900SMichał Górny 
18465c621900SMichał Górny   const char *args[] = {"prog", "--alumnum"};
18475c621900SMichał Górny 
18485c621900SMichał Górny   std::string Errs;
18495c621900SMichał Górny   raw_string_ostream OS(Errs);
18505c621900SMichał Górny 
18515c621900SMichał Górny   EXPECT_FALSE(cl::ParseCommandLineOptions(2, args, StringRef(), &OS));
18525c621900SMichał Górny   OS.flush();
185338ac4093SArchibald Elliott   EXPECT_NE(Errs.find("prog: Did you mean '--aluminium'?\n"),
18545c621900SMichał Górny             std::string::npos);
18555c621900SMichał Górny   Errs.clear();
18565c621900SMichał Górny 
18575c621900SMichał Górny   cl::ResetAllOptionOccurrences();
18585c621900SMichał Górny }
18595c621900SMichał Górny 
TEST(CommandLineTest,Callback)18606555995aSDon Hinton TEST(CommandLineTest, Callback) {
18616555995aSDon Hinton   cl::ResetCommandLineParser();
18626555995aSDon Hinton 
18636555995aSDon Hinton   StackOption<bool> OptA("a", cl::desc("option a"));
18646555995aSDon Hinton   StackOption<bool> OptB(
18656555995aSDon Hinton       "b", cl::desc("option b -- This option turns on option a"),
18666555995aSDon Hinton       cl::callback([&](const bool &) { OptA = true; }));
18676555995aSDon Hinton   StackOption<bool> OptC(
18686555995aSDon Hinton       "c", cl::desc("option c -- This option turns on options a and b"),
18696555995aSDon Hinton       cl::callback([&](const bool &) { OptB = true; }));
18706555995aSDon Hinton   StackOption<std::string, cl::list<std::string>> List(
18716555995aSDon Hinton       "list",
18726555995aSDon Hinton       cl::desc("option list -- This option turns on options a, b, and c when "
18736555995aSDon Hinton                "'foo' is included in list"),
18746555995aSDon Hinton       cl::CommaSeparated,
18756555995aSDon Hinton       cl::callback([&](const std::string &Str) {
18766555995aSDon Hinton         if (Str == "foo")
18776555995aSDon Hinton           OptC = true;
18786555995aSDon Hinton       }));
18796555995aSDon Hinton 
18806555995aSDon Hinton   const char *args1[] = {"prog", "-a"};
18816555995aSDon Hinton   EXPECT_TRUE(cl::ParseCommandLineOptions(2, args1));
18826555995aSDon Hinton   EXPECT_TRUE(OptA);
18836555995aSDon Hinton   EXPECT_FALSE(OptB);
18846555995aSDon Hinton   EXPECT_FALSE(OptC);
188538ac4093SArchibald Elliott   EXPECT_EQ(List.size(), 0u);
18866555995aSDon Hinton   cl::ResetAllOptionOccurrences();
18876555995aSDon Hinton 
18886555995aSDon Hinton   const char *args2[] = {"prog", "-b"};
18896555995aSDon Hinton   EXPECT_TRUE(cl::ParseCommandLineOptions(2, args2));
18906555995aSDon Hinton   EXPECT_TRUE(OptA);
18916555995aSDon Hinton   EXPECT_TRUE(OptB);
18926555995aSDon Hinton   EXPECT_FALSE(OptC);
189338ac4093SArchibald Elliott   EXPECT_EQ(List.size(), 0u);
18946555995aSDon Hinton   cl::ResetAllOptionOccurrences();
18956555995aSDon Hinton 
18966555995aSDon Hinton   const char *args3[] = {"prog", "-c"};
18976555995aSDon Hinton   EXPECT_TRUE(cl::ParseCommandLineOptions(2, args3));
18986555995aSDon Hinton   EXPECT_TRUE(OptA);
18996555995aSDon Hinton   EXPECT_TRUE(OptB);
19006555995aSDon Hinton   EXPECT_TRUE(OptC);
190138ac4093SArchibald Elliott   EXPECT_EQ(List.size(), 0u);
19026555995aSDon Hinton   cl::ResetAllOptionOccurrences();
19036555995aSDon Hinton 
19046555995aSDon Hinton   const char *args4[] = {"prog", "--list=foo,bar"};
19056555995aSDon Hinton   EXPECT_TRUE(cl::ParseCommandLineOptions(2, args4));
19066555995aSDon Hinton   EXPECT_TRUE(OptA);
19076555995aSDon Hinton   EXPECT_TRUE(OptB);
19086555995aSDon Hinton   EXPECT_TRUE(OptC);
190938ac4093SArchibald Elliott   EXPECT_EQ(List.size(), 2u);
19106555995aSDon Hinton   cl::ResetAllOptionOccurrences();
19116555995aSDon Hinton 
19126555995aSDon Hinton   const char *args5[] = {"prog", "--list=bar"};
19136555995aSDon Hinton   EXPECT_TRUE(cl::ParseCommandLineOptions(2, args5));
19146555995aSDon Hinton   EXPECT_FALSE(OptA);
19156555995aSDon Hinton   EXPECT_FALSE(OptB);
19166555995aSDon Hinton   EXPECT_FALSE(OptC);
191738ac4093SArchibald Elliott   EXPECT_EQ(List.size(), 1u);
19186555995aSDon Hinton 
19196555995aSDon Hinton   cl::ResetAllOptionOccurrences();
19206555995aSDon Hinton }
19214a6e13adSDavid Green 
19224a6e13adSDavid Green enum Enum { Val1, Val2 };
19234a6e13adSDavid Green static cl::bits<Enum> ExampleBits(
19244a6e13adSDavid Green     cl::desc("An example cl::bits to ensure it compiles"),
19254a6e13adSDavid Green     cl::values(
19264a6e13adSDavid Green       clEnumValN(Val1, "bits-val1", "The Val1 value"),
19274a6e13adSDavid Green       clEnumValN(Val1, "bits-val2", "The Val2 value")));
19284a6e13adSDavid Green 
TEST(CommandLineTest,ConsumeAfterOnePositional)192954cfc694SYi-Hong Lyu TEST(CommandLineTest, ConsumeAfterOnePositional) {
193054cfc694SYi-Hong Lyu   cl::ResetCommandLineParser();
193154cfc694SYi-Hong Lyu 
193254cfc694SYi-Hong Lyu   // input [args]
193354cfc694SYi-Hong Lyu   StackOption<std::string, cl::opt<std::string>> Input(cl::Positional,
193454cfc694SYi-Hong Lyu                                                        cl::Required);
193554cfc694SYi-Hong Lyu   StackOption<std::string, cl::list<std::string>> ExtraArgs(cl::ConsumeAfter);
193654cfc694SYi-Hong Lyu 
193754cfc694SYi-Hong Lyu   const char *Args[] = {"prog", "input", "arg1", "arg2"};
193854cfc694SYi-Hong Lyu 
193954cfc694SYi-Hong Lyu   std::string Errs;
194054cfc694SYi-Hong Lyu   raw_string_ostream OS(Errs);
194154cfc694SYi-Hong Lyu   EXPECT_TRUE(cl::ParseCommandLineOptions(4, Args, StringRef(), &OS));
194254cfc694SYi-Hong Lyu   OS.flush();
194354cfc694SYi-Hong Lyu   EXPECT_EQ("input", Input);
194438ac4093SArchibald Elliott   EXPECT_EQ(ExtraArgs.size(), 2u);
194538ac4093SArchibald Elliott   EXPECT_EQ(ExtraArgs[0], "arg1");
194638ac4093SArchibald Elliott   EXPECT_EQ(ExtraArgs[1], "arg2");
194754cfc694SYi-Hong Lyu   EXPECT_TRUE(Errs.empty());
194854cfc694SYi-Hong Lyu }
194954cfc694SYi-Hong Lyu 
TEST(CommandLineTest,ConsumeAfterTwoPositionals)195054cfc694SYi-Hong Lyu TEST(CommandLineTest, ConsumeAfterTwoPositionals) {
195154cfc694SYi-Hong Lyu   cl::ResetCommandLineParser();
195254cfc694SYi-Hong Lyu 
195354cfc694SYi-Hong Lyu   // input1 input2 [args]
195454cfc694SYi-Hong Lyu   StackOption<std::string, cl::opt<std::string>> Input1(cl::Positional,
195554cfc694SYi-Hong Lyu                                                         cl::Required);
195654cfc694SYi-Hong Lyu   StackOption<std::string, cl::opt<std::string>> Input2(cl::Positional,
195754cfc694SYi-Hong Lyu                                                         cl::Required);
195854cfc694SYi-Hong Lyu   StackOption<std::string, cl::list<std::string>> ExtraArgs(cl::ConsumeAfter);
195954cfc694SYi-Hong Lyu 
196054cfc694SYi-Hong Lyu   const char *Args[] = {"prog", "input1", "input2", "arg1", "arg2"};
196154cfc694SYi-Hong Lyu 
196254cfc694SYi-Hong Lyu   std::string Errs;
196354cfc694SYi-Hong Lyu   raw_string_ostream OS(Errs);
196454cfc694SYi-Hong Lyu   EXPECT_TRUE(cl::ParseCommandLineOptions(5, Args, StringRef(), &OS));
196554cfc694SYi-Hong Lyu   OS.flush();
196654cfc694SYi-Hong Lyu   EXPECT_EQ("input1", Input1);
196754cfc694SYi-Hong Lyu   EXPECT_EQ("input2", Input2);
196838ac4093SArchibald Elliott   EXPECT_EQ(ExtraArgs.size(), 2u);
196938ac4093SArchibald Elliott   EXPECT_EQ(ExtraArgs[0], "arg1");
197038ac4093SArchibald Elliott   EXPECT_EQ(ExtraArgs[1], "arg2");
197154cfc694SYi-Hong Lyu   EXPECT_TRUE(Errs.empty());
197254cfc694SYi-Hong Lyu }
197354cfc694SYi-Hong Lyu 
TEST(CommandLineTest,ResetAllOptionOccurrences)197493c55d5eSChristian Sigg TEST(CommandLineTest, ResetAllOptionOccurrences) {
197593c55d5eSChristian Sigg   cl::ResetCommandLineParser();
197693c55d5eSChristian Sigg 
1977fcd9fa41SYevgeny Rouban   // -option -str -enableA -enableC [sink] input [args]
197893c55d5eSChristian Sigg   StackOption<bool> Option("option");
1979fcd9fa41SYevgeny Rouban   StackOption<std::string> Str("str");
198062e4a777SRVP   enum Vals { ValA, ValB, ValC };
198162e4a777SRVP   StackOption<Vals, cl::bits<Vals>> Bits(
198262e4a777SRVP       cl::values(clEnumValN(ValA, "enableA", "Enable A"),
198362e4a777SRVP                  clEnumValN(ValB, "enableB", "Enable B"),
198462e4a777SRVP                  clEnumValN(ValC, "enableC", "Enable C")));
198593c55d5eSChristian Sigg   StackOption<std::string, cl::list<std::string>> Sink(cl::Sink);
198693c55d5eSChristian Sigg   StackOption<std::string> Input(cl::Positional);
198793c55d5eSChristian Sigg   StackOption<std::string, cl::list<std::string>> ExtraArgs(cl::ConsumeAfter);
198893c55d5eSChristian Sigg 
1989fcd9fa41SYevgeny Rouban   const char *Args[] = {"prog",     "-option",  "-str=STR", "-enableA",
1990fcd9fa41SYevgeny Rouban                         "-enableC", "-unknown", "input",    "-arg"};
199193c55d5eSChristian Sigg 
199293c55d5eSChristian Sigg   std::string Errs;
199393c55d5eSChristian Sigg   raw_string_ostream OS(Errs);
1994fcd9fa41SYevgeny Rouban   EXPECT_TRUE(cl::ParseCommandLineOptions(8, Args, StringRef(), &OS));
199593c55d5eSChristian Sigg   EXPECT_TRUE(OS.str().empty());
199693c55d5eSChristian Sigg 
199793c55d5eSChristian Sigg   EXPECT_TRUE(Option);
1998fcd9fa41SYevgeny Rouban   EXPECT_EQ("STR", Str);
199962e4a777SRVP   EXPECT_EQ((1u << ValA) | (1u << ValC), Bits.getBits());
200038ac4093SArchibald Elliott   EXPECT_EQ(1u, Sink.size());
200193c55d5eSChristian Sigg   EXPECT_EQ("-unknown", Sink[0]);
200293c55d5eSChristian Sigg   EXPECT_EQ("input", Input);
200338ac4093SArchibald Elliott   EXPECT_EQ(1u, ExtraArgs.size());
200493c55d5eSChristian Sigg   EXPECT_EQ("-arg", ExtraArgs[0]);
200593c55d5eSChristian Sigg 
200693c55d5eSChristian Sigg   cl::ResetAllOptionOccurrences();
200793c55d5eSChristian Sigg   EXPECT_FALSE(Option);
2008fcd9fa41SYevgeny Rouban   EXPECT_EQ("", Str);
200962e4a777SRVP   EXPECT_EQ(0u, Bits.getBits());
201038ac4093SArchibald Elliott   EXPECT_EQ(0u, Sink.size());
201193c55d5eSChristian Sigg   EXPECT_EQ(0, Input.getNumOccurrences());
201238ac4093SArchibald Elliott   EXPECT_EQ(0u, ExtraArgs.size());
201393c55d5eSChristian Sigg }
201493c55d5eSChristian Sigg 
TEST(CommandLineTest,DefaultValue)2015c5f34d16SYevgeny Rouban TEST(CommandLineTest, DefaultValue) {
2016c5f34d16SYevgeny Rouban   cl::ResetCommandLineParser();
2017c5f34d16SYevgeny Rouban 
2018c5f34d16SYevgeny Rouban   StackOption<bool> BoolOption("bool-option");
2019c5f34d16SYevgeny Rouban   StackOption<std::string> StrOption("str-option");
2020c5f34d16SYevgeny Rouban   StackOption<bool> BoolInitOption("bool-init-option", cl::init(true));
2021c5f34d16SYevgeny Rouban   StackOption<std::string> StrInitOption("str-init-option",
2022c5f34d16SYevgeny Rouban                                          cl::init("str-default-value"));
2023c5f34d16SYevgeny Rouban 
2024c5f34d16SYevgeny Rouban   const char *Args[] = {"prog"}; // no options
2025c5f34d16SYevgeny Rouban 
2026c5f34d16SYevgeny Rouban   std::string Errs;
2027c5f34d16SYevgeny Rouban   raw_string_ostream OS(Errs);
2028c5f34d16SYevgeny Rouban   EXPECT_TRUE(cl::ParseCommandLineOptions(1, Args, StringRef(), &OS));
2029c5f34d16SYevgeny Rouban   EXPECT_TRUE(OS.str().empty());
2030c5f34d16SYevgeny Rouban 
2031c5f34d16SYevgeny Rouban   EXPECT_TRUE(!BoolOption);
2032c5f34d16SYevgeny Rouban   EXPECT_FALSE(BoolOption.Default.hasValue());
2033c5f34d16SYevgeny Rouban   EXPECT_EQ(0, BoolOption.getNumOccurrences());
2034c5f34d16SYevgeny Rouban 
2035c5f34d16SYevgeny Rouban   EXPECT_EQ("", StrOption);
2036c5f34d16SYevgeny Rouban   EXPECT_FALSE(StrOption.Default.hasValue());
2037c5f34d16SYevgeny Rouban   EXPECT_EQ(0, StrOption.getNumOccurrences());
2038c5f34d16SYevgeny Rouban 
2039c5f34d16SYevgeny Rouban   EXPECT_TRUE(BoolInitOption);
2040c5f34d16SYevgeny Rouban   EXPECT_TRUE(BoolInitOption.Default.hasValue());
2041c5f34d16SYevgeny Rouban   EXPECT_EQ(0, BoolInitOption.getNumOccurrences());
2042c5f34d16SYevgeny Rouban 
2043c5f34d16SYevgeny Rouban   EXPECT_EQ("str-default-value", StrInitOption);
2044c5f34d16SYevgeny Rouban   EXPECT_TRUE(StrInitOption.Default.hasValue());
2045c5f34d16SYevgeny Rouban   EXPECT_EQ(0, StrInitOption.getNumOccurrences());
2046c5f34d16SYevgeny Rouban 
2047c5f34d16SYevgeny Rouban   const char *Args2[] = {"prog", "-bool-option", "-str-option=str-value",
2048c5f34d16SYevgeny Rouban                          "-bool-init-option=0",
2049c5f34d16SYevgeny Rouban                          "-str-init-option=str-init-value"};
2050c5f34d16SYevgeny Rouban 
2051c5f34d16SYevgeny Rouban   EXPECT_TRUE(cl::ParseCommandLineOptions(5, Args2, StringRef(), &OS));
2052c5f34d16SYevgeny Rouban   EXPECT_TRUE(OS.str().empty());
2053c5f34d16SYevgeny Rouban 
2054c5f34d16SYevgeny Rouban   EXPECT_TRUE(BoolOption);
2055c5f34d16SYevgeny Rouban   EXPECT_FALSE(BoolOption.Default.hasValue());
2056c5f34d16SYevgeny Rouban   EXPECT_EQ(1, BoolOption.getNumOccurrences());
2057c5f34d16SYevgeny Rouban 
2058c5f34d16SYevgeny Rouban   EXPECT_EQ("str-value", StrOption);
2059c5f34d16SYevgeny Rouban   EXPECT_FALSE(StrOption.Default.hasValue());
2060c5f34d16SYevgeny Rouban   EXPECT_EQ(1, StrOption.getNumOccurrences());
2061c5f34d16SYevgeny Rouban 
2062c5f34d16SYevgeny Rouban   EXPECT_FALSE(BoolInitOption);
2063c5f34d16SYevgeny Rouban   EXPECT_TRUE(BoolInitOption.Default.hasValue());
2064c5f34d16SYevgeny Rouban   EXPECT_EQ(1, BoolInitOption.getNumOccurrences());
2065c5f34d16SYevgeny Rouban 
2066c5f34d16SYevgeny Rouban   EXPECT_EQ("str-init-value", StrInitOption);
2067c5f34d16SYevgeny Rouban   EXPECT_TRUE(StrInitOption.Default.hasValue());
2068c5f34d16SYevgeny Rouban   EXPECT_EQ(1, StrInitOption.getNumOccurrences());
2069c5f34d16SYevgeny Rouban }
2070c5f34d16SYevgeny Rouban 
207191d3cfedSDuncan P. N. Exon Smith } // anonymous namespace
2072