1 //===- llvm/unittest/Support/CommandLineTest.cpp - CommandLine tests ------===//
2 //
3 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4 // See https://llvm.org/LICENSE.txt for license information.
5 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6 //
7 //===----------------------------------------------------------------------===//
8
9 #include "llvm/Support/CommandLine.h"
10 #include "llvm/ADT/STLExtras.h"
11 #include "llvm/ADT/SmallString.h"
12 #include "llvm/ADT/StringRef.h"
13 #include "llvm/ADT/Triple.h"
14 #include "llvm/Config/config.h"
15 #include "llvm/Support/Allocator.h"
16 #include "llvm/Support/FileSystem.h"
17 #include "llvm/Support/Host.h"
18 #include "llvm/Support/InitLLVM.h"
19 #include "llvm/Support/MemoryBuffer.h"
20 #include "llvm/Support/Path.h"
21 #include "llvm/Support/Program.h"
22 #include "llvm/Support/StringSaver.h"
23 #include "llvm/Support/VirtualFileSystem.h"
24 #include "llvm/Support/raw_ostream.h"
25 #include "llvm/Testing/Support/SupportHelpers.h"
26 #include "gmock/gmock.h"
27 #include "gtest/gtest.h"
28 #include <fstream>
29 #include <stdlib.h>
30 #include <string>
31 #include <tuple>
32
33 using namespace llvm;
34 using llvm::unittest::TempDir;
35 using llvm::unittest::TempFile;
36
37 namespace {
38
39 MATCHER(StringEquality, "Checks if two char* are equal as strings") {
40 return std::string(std::get<0>(arg)) == std::string(std::get<1>(arg));
41 }
42
43 class TempEnvVar {
44 public:
TempEnvVar(const char * name,const char * value)45 TempEnvVar(const char *name, const char *value)
46 : name(name) {
47 const char *old_value = getenv(name);
48 EXPECT_EQ(nullptr, old_value) << old_value;
49 #if HAVE_SETENV
50 setenv(name, value, true);
51 #endif
52 }
53
~TempEnvVar()54 ~TempEnvVar() {
55 #if HAVE_SETENV
56 // Assume setenv and unsetenv come together.
57 unsetenv(name);
58 #else
59 (void)name; // Suppress -Wunused-private-field.
60 #endif
61 }
62
63 private:
64 const char *const name;
65 };
66
67 template <typename T, typename Base = cl::opt<T>>
68 class StackOption : public Base {
69 public:
70 template <class... Ts>
StackOption(Ts &&...Ms)71 explicit StackOption(Ts &&... Ms) : Base(std::forward<Ts>(Ms)...) {}
72
~StackOption()73 ~StackOption() override { this->removeArgument(); }
74
operator =(const DT & V)75 template <class DT> StackOption<T> &operator=(const DT &V) {
76 Base::operator=(V);
77 return *this;
78 }
79 };
80
81 class StackSubCommand : public cl::SubCommand {
82 public:
StackSubCommand(StringRef Name,StringRef Description=StringRef ())83 StackSubCommand(StringRef Name,
84 StringRef Description = StringRef())
85 : SubCommand(Name, Description) {}
86
StackSubCommand()87 StackSubCommand() : SubCommand() {}
88
~StackSubCommand()89 ~StackSubCommand() { unregisterSubCommand(); }
90 };
91
92
93 cl::OptionCategory TestCategory("Test Options", "Description");
TEST(CommandLineTest,ModifyExisitingOption)94 TEST(CommandLineTest, ModifyExisitingOption) {
95 StackOption<int> TestOption("test-option", cl::desc("old description"));
96
97 static const char Description[] = "New description";
98 static const char ArgString[] = "new-test-option";
99 static const char ValueString[] = "Integer";
100
101 StringMap<cl::Option *> &Map =
102 cl::getRegisteredOptions(*cl::TopLevelSubCommand);
103
104 ASSERT_EQ(Map.count("test-option"), 1u) << "Could not find option in map.";
105
106 cl::Option *Retrieved = Map["test-option"];
107 ASSERT_EQ(&TestOption, Retrieved) << "Retrieved wrong option.";
108
109 ASSERT_NE(Retrieved->Categories.end(),
110 find_if(Retrieved->Categories,
111 [&](const llvm::cl::OptionCategory *Cat) {
112 return Cat == &cl::getGeneralCategory();
113 }))
114 << "Incorrect default option category.";
115
116 Retrieved->addCategory(TestCategory);
117 ASSERT_NE(Retrieved->Categories.end(),
118 find_if(Retrieved->Categories,
119 [&](const llvm::cl::OptionCategory *Cat) {
120 return Cat == &TestCategory;
121 }))
122 << "Failed to modify option's option category.";
123
124 Retrieved->setDescription(Description);
125 ASSERT_STREQ(Retrieved->HelpStr.data(), Description)
126 << "Changing option description failed.";
127
128 Retrieved->setArgStr(ArgString);
129 ASSERT_STREQ(ArgString, Retrieved->ArgStr.data())
130 << "Failed to modify option's Argument string.";
131
132 Retrieved->setValueStr(ValueString);
133 ASSERT_STREQ(Retrieved->ValueStr.data(), ValueString)
134 << "Failed to modify option's Value string.";
135
136 Retrieved->setHiddenFlag(cl::Hidden);
137 ASSERT_EQ(cl::Hidden, TestOption.getOptionHiddenFlag()) <<
138 "Failed to modify option's hidden flag.";
139 }
140
TEST(CommandLineTest,UseOptionCategory)141 TEST(CommandLineTest, UseOptionCategory) {
142 StackOption<int> TestOption2("test-option", cl::cat(TestCategory));
143
144 ASSERT_NE(TestOption2.Categories.end(),
145 find_if(TestOption2.Categories,
146 [&](const llvm::cl::OptionCategory *Cat) {
147 return Cat == &TestCategory;
148 }))
149 << "Failed to assign Option Category.";
150 }
151
TEST(CommandLineTest,UseMultipleCategories)152 TEST(CommandLineTest, UseMultipleCategories) {
153 StackOption<int> TestOption2("test-option2", cl::cat(TestCategory),
154 cl::cat(cl::getGeneralCategory()),
155 cl::cat(cl::getGeneralCategory()));
156
157 // Make sure cl::getGeneralCategory() wasn't added twice.
158 ASSERT_EQ(TestOption2.Categories.size(), 2U);
159
160 ASSERT_NE(TestOption2.Categories.end(),
161 find_if(TestOption2.Categories,
162 [&](const llvm::cl::OptionCategory *Cat) {
163 return Cat == &TestCategory;
164 }))
165 << "Failed to assign Option Category.";
166 ASSERT_NE(TestOption2.Categories.end(),
167 find_if(TestOption2.Categories,
168 [&](const llvm::cl::OptionCategory *Cat) {
169 return Cat == &cl::getGeneralCategory();
170 }))
171 << "Failed to assign General Category.";
172
173 cl::OptionCategory AnotherCategory("Additional test Options", "Description");
174 StackOption<int> TestOption("test-option", cl::cat(TestCategory),
175 cl::cat(AnotherCategory));
176 ASSERT_EQ(TestOption.Categories.end(),
177 find_if(TestOption.Categories,
178 [&](const llvm::cl::OptionCategory *Cat) {
179 return Cat == &cl::getGeneralCategory();
180 }))
181 << "Failed to remove General Category.";
182 ASSERT_NE(TestOption.Categories.end(),
183 find_if(TestOption.Categories,
184 [&](const llvm::cl::OptionCategory *Cat) {
185 return Cat == &TestCategory;
186 }))
187 << "Failed to assign Option Category.";
188 ASSERT_NE(TestOption.Categories.end(),
189 find_if(TestOption.Categories,
190 [&](const llvm::cl::OptionCategory *Cat) {
191 return Cat == &AnotherCategory;
192 }))
193 << "Failed to assign Another Category.";
194 }
195
196 typedef void ParserFunction(StringRef Source, StringSaver &Saver,
197 SmallVectorImpl<const char *> &NewArgv,
198 bool MarkEOLs);
199
testCommandLineTokenizer(ParserFunction * parse,StringRef Input,ArrayRef<const char * > Output,bool MarkEOLs=false)200 void testCommandLineTokenizer(ParserFunction *parse, StringRef Input,
201 ArrayRef<const char *> Output,
202 bool MarkEOLs = false) {
203 SmallVector<const char *, 0> Actual;
204 BumpPtrAllocator A;
205 StringSaver Saver(A);
206 parse(Input, Saver, Actual, MarkEOLs);
207 EXPECT_EQ(Output.size(), Actual.size());
208 for (unsigned I = 0, E = Actual.size(); I != E; ++I) {
209 if (I < Output.size()) {
210 EXPECT_STREQ(Output[I], Actual[I]);
211 }
212 }
213 }
214
TEST(CommandLineTest,TokenizeGNUCommandLine)215 TEST(CommandLineTest, TokenizeGNUCommandLine) {
216 const char Input[] =
217 "foo\\ bar \"foo bar\" \'foo bar\' 'foo\\\\bar' -DFOO=bar\\(\\) "
218 "foo\"bar\"baz C:\\\\src\\\\foo.cpp \"C:\\src\\foo.cpp\"";
219 const char *const Output[] = {
220 "foo bar", "foo bar", "foo bar", "foo\\bar",
221 "-DFOO=bar()", "foobarbaz", "C:\\src\\foo.cpp", "C:srcfoo.cpp"};
222 testCommandLineTokenizer(cl::TokenizeGNUCommandLine, Input, Output);
223 }
224
TEST(CommandLineTest,TokenizeWindowsCommandLine1)225 TEST(CommandLineTest, TokenizeWindowsCommandLine1) {
226 const char Input[] =
227 R"(a\b c\\d e\\"f g" h\"i j\\\"k "lmn" o pqr "st \"u" \v)";
228 const char *const Output[] = { "a\\b", "c\\\\d", "e\\f g", "h\"i", "j\\\"k",
229 "lmn", "o", "pqr", "st \"u", "\\v" };
230 testCommandLineTokenizer(cl::TokenizeWindowsCommandLine, Input, Output);
231 }
232
TEST(CommandLineTest,TokenizeWindowsCommandLine2)233 TEST(CommandLineTest, TokenizeWindowsCommandLine2) {
234 const char Input[] = "clang -c -DFOO=\"\"\"ABC\"\"\" x.cpp";
235 const char *const Output[] = { "clang", "-c", "-DFOO=\"ABC\"", "x.cpp"};
236 testCommandLineTokenizer(cl::TokenizeWindowsCommandLine, Input, Output);
237 }
238
TEST(CommandLineTest,TokenizeWindowsCommandLineQuotedLastArgument)239 TEST(CommandLineTest, TokenizeWindowsCommandLineQuotedLastArgument) {
240 // Whitespace at the end of the command line doesn't cause an empty last word
241 const char Input0[] = R"(a b c d )";
242 const char *const Output0[] = {"a", "b", "c", "d"};
243 testCommandLineTokenizer(cl::TokenizeWindowsCommandLine, Input0, Output0);
244
245 // But an explicit "" does
246 const char Input1[] = R"(a b c d "")";
247 const char *const Output1[] = {"a", "b", "c", "d", ""};
248 testCommandLineTokenizer(cl::TokenizeWindowsCommandLine, Input1, Output1);
249
250 // An unterminated quoted string is also emitted as an argument word, empty
251 // or not
252 const char Input2[] = R"(a b c d ")";
253 const char *const Output2[] = {"a", "b", "c", "d", ""};
254 testCommandLineTokenizer(cl::TokenizeWindowsCommandLine, Input2, Output2);
255 const char Input3[] = R"(a b c d "text)";
256 const char *const Output3[] = {"a", "b", "c", "d", "text"};
257 testCommandLineTokenizer(cl::TokenizeWindowsCommandLine, Input3, Output3);
258 }
259
TEST(CommandLineTest,TokenizeWindowsCommandLineExeName)260 TEST(CommandLineTest, TokenizeWindowsCommandLineExeName) {
261 const char Input1[] =
262 R"("C:\Program Files\Whatever\"clang.exe z.c -DY=\"x\")";
263 const char *const Output1[] = {"C:\\Program Files\\Whatever\\clang.exe",
264 "z.c", "-DY=\"x\""};
265 testCommandLineTokenizer(cl::TokenizeWindowsCommandLineFull, Input1, Output1);
266
267 const char Input2[] = "\"a\\\"b c\\\"d\n\"e\\\"f g\\\"h\n";
268 const char *const Output2[] = {"a\\b", "c\"d", nullptr,
269 "e\\f", "g\"h", nullptr};
270 testCommandLineTokenizer(cl::TokenizeWindowsCommandLineFull, Input2, Output2,
271 /*MarkEOLs=*/true);
272
273 const char Input3[] = R"(\\server\share\subdir\clang.exe)";
274 const char *const Output3[] = {"\\\\server\\share\\subdir\\clang.exe"};
275 testCommandLineTokenizer(cl::TokenizeWindowsCommandLineFull, Input3, Output3);
276 }
277
TEST(CommandLineTest,TokenizeAndMarkEOLs)278 TEST(CommandLineTest, TokenizeAndMarkEOLs) {
279 // Clang uses EOL marking in response files to support options that consume
280 // the rest of the arguments on the current line, but do not consume arguments
281 // from subsequent lines. For example, given these rsp files contents:
282 // /c /Zi /O2
283 // /Oy- /link /debug /opt:ref
284 // /Zc:ThreadsafeStatics-
285 //
286 // clang-cl needs to treat "/debug /opt:ref" as linker flags, and everything
287 // else as compiler flags. The tokenizer inserts nullptr sentinels into the
288 // output so that clang-cl can find the end of the current line.
289 const char Input[] = "clang -Xclang foo\n\nfoo\"bar\"baz\n x.cpp\n";
290 const char *const Output[] = {"clang", "-Xclang", "foo",
291 nullptr, nullptr, "foobarbaz",
292 nullptr, "x.cpp", nullptr};
293 testCommandLineTokenizer(cl::TokenizeWindowsCommandLine, Input, Output,
294 /*MarkEOLs=*/true);
295 testCommandLineTokenizer(cl::TokenizeGNUCommandLine, Input, Output,
296 /*MarkEOLs=*/true);
297 }
298
TEST(CommandLineTest,TokenizeConfigFile1)299 TEST(CommandLineTest, TokenizeConfigFile1) {
300 const char *Input = "\\";
301 const char *const Output[] = { "\\" };
302 testCommandLineTokenizer(cl::tokenizeConfigFile, Input, Output);
303 }
304
TEST(CommandLineTest,TokenizeConfigFile2)305 TEST(CommandLineTest, TokenizeConfigFile2) {
306 const char *Input = "\\abc";
307 const char *const Output[] = { "abc" };
308 testCommandLineTokenizer(cl::tokenizeConfigFile, Input, Output);
309 }
310
TEST(CommandLineTest,TokenizeConfigFile3)311 TEST(CommandLineTest, TokenizeConfigFile3) {
312 const char *Input = "abc\\";
313 const char *const Output[] = { "abc\\" };
314 testCommandLineTokenizer(cl::tokenizeConfigFile, Input, Output);
315 }
316
TEST(CommandLineTest,TokenizeConfigFile4)317 TEST(CommandLineTest, TokenizeConfigFile4) {
318 const char *Input = "abc\\\n123";
319 const char *const Output[] = { "abc123" };
320 testCommandLineTokenizer(cl::tokenizeConfigFile, Input, Output);
321 }
322
TEST(CommandLineTest,TokenizeConfigFile5)323 TEST(CommandLineTest, TokenizeConfigFile5) {
324 const char *Input = "abc\\\r\n123";
325 const char *const Output[] = { "abc123" };
326 testCommandLineTokenizer(cl::tokenizeConfigFile, Input, Output);
327 }
328
TEST(CommandLineTest,TokenizeConfigFile6)329 TEST(CommandLineTest, TokenizeConfigFile6) {
330 const char *Input = "abc\\\n";
331 const char *const Output[] = { "abc" };
332 testCommandLineTokenizer(cl::tokenizeConfigFile, Input, Output);
333 }
334
TEST(CommandLineTest,TokenizeConfigFile7)335 TEST(CommandLineTest, TokenizeConfigFile7) {
336 const char *Input = "abc\\\r\n";
337 const char *const Output[] = { "abc" };
338 testCommandLineTokenizer(cl::tokenizeConfigFile, Input, Output);
339 }
340
TEST(CommandLineTest,TokenizeConfigFile8)341 TEST(CommandLineTest, TokenizeConfigFile8) {
342 SmallVector<const char *, 0> Actual;
343 BumpPtrAllocator A;
344 StringSaver Saver(A);
345 cl::tokenizeConfigFile("\\\n", Saver, Actual, /*MarkEOLs=*/false);
346 EXPECT_TRUE(Actual.empty());
347 }
348
TEST(CommandLineTest,TokenizeConfigFile9)349 TEST(CommandLineTest, TokenizeConfigFile9) {
350 SmallVector<const char *, 0> Actual;
351 BumpPtrAllocator A;
352 StringSaver Saver(A);
353 cl::tokenizeConfigFile("\\\r\n", Saver, Actual, /*MarkEOLs=*/false);
354 EXPECT_TRUE(Actual.empty());
355 }
356
TEST(CommandLineTest,TokenizeConfigFile10)357 TEST(CommandLineTest, TokenizeConfigFile10) {
358 const char *Input = "\\\nabc";
359 const char *const Output[] = { "abc" };
360 testCommandLineTokenizer(cl::tokenizeConfigFile, Input, Output);
361 }
362
TEST(CommandLineTest,TokenizeConfigFile11)363 TEST(CommandLineTest, TokenizeConfigFile11) {
364 const char *Input = "\\\r\nabc";
365 const char *const Output[] = { "abc" };
366 testCommandLineTokenizer(cl::tokenizeConfigFile, Input, Output);
367 }
368
TEST(CommandLineTest,AliasesWithArguments)369 TEST(CommandLineTest, AliasesWithArguments) {
370 static const size_t ARGC = 3;
371 const char *const Inputs[][ARGC] = {
372 { "-tool", "-actual=x", "-extra" },
373 { "-tool", "-actual", "x" },
374 { "-tool", "-alias=x", "-extra" },
375 { "-tool", "-alias", "x" }
376 };
377
378 for (size_t i = 0, e = array_lengthof(Inputs); i < e; ++i) {
379 StackOption<std::string> Actual("actual");
380 StackOption<bool> Extra("extra");
381 StackOption<std::string> Input(cl::Positional);
382
383 cl::alias Alias("alias", llvm::cl::aliasopt(Actual));
384
385 cl::ParseCommandLineOptions(ARGC, Inputs[i]);
386 EXPECT_EQ("x", Actual);
387 EXPECT_EQ(0, Input.getNumOccurrences());
388
389 Alias.removeArgument();
390 }
391 }
392
testAliasRequired(int argc,const char * const * argv)393 void testAliasRequired(int argc, const char *const *argv) {
394 StackOption<std::string> Option("option", cl::Required);
395 cl::alias Alias("o", llvm::cl::aliasopt(Option));
396
397 cl::ParseCommandLineOptions(argc, argv);
398 EXPECT_EQ("x", Option);
399 EXPECT_EQ(1, Option.getNumOccurrences());
400
401 Alias.removeArgument();
402 }
403
TEST(CommandLineTest,AliasRequired)404 TEST(CommandLineTest, AliasRequired) {
405 const char *opts1[] = { "-tool", "-option=x" };
406 const char *opts2[] = { "-tool", "-o", "x" };
407 testAliasRequired(array_lengthof(opts1), opts1);
408 testAliasRequired(array_lengthof(opts2), opts2);
409 }
410
TEST(CommandLineTest,HideUnrelatedOptions)411 TEST(CommandLineTest, HideUnrelatedOptions) {
412 StackOption<int> TestOption1("hide-option-1");
413 StackOption<int> TestOption2("hide-option-2", cl::cat(TestCategory));
414
415 cl::HideUnrelatedOptions(TestCategory);
416
417 ASSERT_EQ(cl::ReallyHidden, TestOption1.getOptionHiddenFlag())
418 << "Failed to hide extra option.";
419 ASSERT_EQ(cl::NotHidden, TestOption2.getOptionHiddenFlag())
420 << "Hid extra option that should be visable.";
421
422 StringMap<cl::Option *> &Map =
423 cl::getRegisteredOptions(*cl::TopLevelSubCommand);
424 ASSERT_TRUE(Map.count("help") == (size_t)0 ||
425 cl::NotHidden == Map["help"]->getOptionHiddenFlag())
426 << "Hid default option that should be visable.";
427 }
428
429 cl::OptionCategory TestCategory2("Test Options set 2", "Description");
430
TEST(CommandLineTest,HideUnrelatedOptionsMulti)431 TEST(CommandLineTest, HideUnrelatedOptionsMulti) {
432 StackOption<int> TestOption1("multi-hide-option-1");
433 StackOption<int> TestOption2("multi-hide-option-2", cl::cat(TestCategory));
434 StackOption<int> TestOption3("multi-hide-option-3", cl::cat(TestCategory2));
435
436 const cl::OptionCategory *VisibleCategories[] = {&TestCategory,
437 &TestCategory2};
438
439 cl::HideUnrelatedOptions(makeArrayRef(VisibleCategories));
440
441 ASSERT_EQ(cl::ReallyHidden, TestOption1.getOptionHiddenFlag())
442 << "Failed to hide extra option.";
443 ASSERT_EQ(cl::NotHidden, TestOption2.getOptionHiddenFlag())
444 << "Hid extra option that should be visable.";
445 ASSERT_EQ(cl::NotHidden, TestOption3.getOptionHiddenFlag())
446 << "Hid extra option that should be visable.";
447
448 StringMap<cl::Option *> &Map =
449 cl::getRegisteredOptions(*cl::TopLevelSubCommand);
450 ASSERT_TRUE(Map.count("help") == (size_t)0 ||
451 cl::NotHidden == Map["help"]->getOptionHiddenFlag())
452 << "Hid default option that should be visable.";
453 }
454
TEST(CommandLineTest,SetMultiValues)455 TEST(CommandLineTest, SetMultiValues) {
456 StackOption<int> Option("option");
457 const char *args[] = {"prog", "-option=1", "-option=2"};
458 EXPECT_TRUE(cl::ParseCommandLineOptions(array_lengthof(args), args,
459 StringRef(), &llvm::nulls()));
460 EXPECT_EQ(Option, 2);
461 }
462
TEST(CommandLineTest,SetValueInSubcategories)463 TEST(CommandLineTest, SetValueInSubcategories) {
464 cl::ResetCommandLineParser();
465
466 StackSubCommand SC1("sc1", "First subcommand");
467 StackSubCommand SC2("sc2", "Second subcommand");
468
469 StackOption<bool> TopLevelOpt("top-level", cl::init(false));
470 StackOption<bool> SC1Opt("sc1", cl::sub(SC1), cl::init(false));
471 StackOption<bool> SC2Opt("sc2", cl::sub(SC2), cl::init(false));
472
473 EXPECT_FALSE(TopLevelOpt);
474 EXPECT_FALSE(SC1Opt);
475 EXPECT_FALSE(SC2Opt);
476 const char *args[] = {"prog", "-top-level"};
477 EXPECT_TRUE(
478 cl::ParseCommandLineOptions(2, args, StringRef(), &llvm::nulls()));
479 EXPECT_TRUE(TopLevelOpt);
480 EXPECT_FALSE(SC1Opt);
481 EXPECT_FALSE(SC2Opt);
482
483 TopLevelOpt = false;
484
485 cl::ResetAllOptionOccurrences();
486 EXPECT_FALSE(TopLevelOpt);
487 EXPECT_FALSE(SC1Opt);
488 EXPECT_FALSE(SC2Opt);
489 const char *args2[] = {"prog", "sc1", "-sc1"};
490 EXPECT_TRUE(
491 cl::ParseCommandLineOptions(3, args2, StringRef(), &llvm::nulls()));
492 EXPECT_FALSE(TopLevelOpt);
493 EXPECT_TRUE(SC1Opt);
494 EXPECT_FALSE(SC2Opt);
495
496 SC1Opt = false;
497
498 cl::ResetAllOptionOccurrences();
499 EXPECT_FALSE(TopLevelOpt);
500 EXPECT_FALSE(SC1Opt);
501 EXPECT_FALSE(SC2Opt);
502 const char *args3[] = {"prog", "sc2", "-sc2"};
503 EXPECT_TRUE(
504 cl::ParseCommandLineOptions(3, args3, StringRef(), &llvm::nulls()));
505 EXPECT_FALSE(TopLevelOpt);
506 EXPECT_FALSE(SC1Opt);
507 EXPECT_TRUE(SC2Opt);
508 }
509
TEST(CommandLineTest,LookupFailsInWrongSubCommand)510 TEST(CommandLineTest, LookupFailsInWrongSubCommand) {
511 cl::ResetCommandLineParser();
512
513 StackSubCommand SC1("sc1", "First subcommand");
514 StackSubCommand SC2("sc2", "Second subcommand");
515
516 StackOption<bool> SC1Opt("sc1", cl::sub(SC1), cl::init(false));
517 StackOption<bool> SC2Opt("sc2", cl::sub(SC2), cl::init(false));
518
519 std::string Errs;
520 raw_string_ostream OS(Errs);
521
522 const char *args[] = {"prog", "sc1", "-sc2"};
523 EXPECT_FALSE(cl::ParseCommandLineOptions(3, args, StringRef(), &OS));
524 OS.flush();
525 EXPECT_FALSE(Errs.empty());
526 }
527
TEST(CommandLineTest,AddToAllSubCommands)528 TEST(CommandLineTest, AddToAllSubCommands) {
529 cl::ResetCommandLineParser();
530
531 StackSubCommand SC1("sc1", "First subcommand");
532 StackOption<bool> AllOpt("everywhere", cl::sub(*cl::AllSubCommands),
533 cl::init(false));
534 StackSubCommand SC2("sc2", "Second subcommand");
535
536 const char *args[] = {"prog", "-everywhere"};
537 const char *args2[] = {"prog", "sc1", "-everywhere"};
538 const char *args3[] = {"prog", "sc2", "-everywhere"};
539
540 std::string Errs;
541 raw_string_ostream OS(Errs);
542
543 EXPECT_FALSE(AllOpt);
544 EXPECT_TRUE(cl::ParseCommandLineOptions(2, args, StringRef(), &OS));
545 EXPECT_TRUE(AllOpt);
546
547 AllOpt = false;
548
549 cl::ResetAllOptionOccurrences();
550 EXPECT_FALSE(AllOpt);
551 EXPECT_TRUE(cl::ParseCommandLineOptions(3, args2, StringRef(), &OS));
552 EXPECT_TRUE(AllOpt);
553
554 AllOpt = false;
555
556 cl::ResetAllOptionOccurrences();
557 EXPECT_FALSE(AllOpt);
558 EXPECT_TRUE(cl::ParseCommandLineOptions(3, args3, StringRef(), &OS));
559 EXPECT_TRUE(AllOpt);
560
561 // Since all parsing succeeded, the error message should be empty.
562 OS.flush();
563 EXPECT_TRUE(Errs.empty());
564 }
565
TEST(CommandLineTest,ReparseCommandLineOptions)566 TEST(CommandLineTest, ReparseCommandLineOptions) {
567 cl::ResetCommandLineParser();
568
569 StackOption<bool> TopLevelOpt("top-level", cl::sub(*cl::TopLevelSubCommand),
570 cl::init(false));
571
572 const char *args[] = {"prog", "-top-level"};
573
574 EXPECT_FALSE(TopLevelOpt);
575 EXPECT_TRUE(
576 cl::ParseCommandLineOptions(2, args, StringRef(), &llvm::nulls()));
577 EXPECT_TRUE(TopLevelOpt);
578
579 TopLevelOpt = false;
580
581 cl::ResetAllOptionOccurrences();
582 EXPECT_FALSE(TopLevelOpt);
583 EXPECT_TRUE(
584 cl::ParseCommandLineOptions(2, args, StringRef(), &llvm::nulls()));
585 EXPECT_TRUE(TopLevelOpt);
586 }
587
TEST(CommandLineTest,RemoveFromRegularSubCommand)588 TEST(CommandLineTest, RemoveFromRegularSubCommand) {
589 cl::ResetCommandLineParser();
590
591 StackSubCommand SC("sc", "Subcommand");
592 StackOption<bool> RemoveOption("remove-option", cl::sub(SC), cl::init(false));
593 StackOption<bool> KeepOption("keep-option", cl::sub(SC), cl::init(false));
594
595 const char *args[] = {"prog", "sc", "-remove-option"};
596
597 std::string Errs;
598 raw_string_ostream OS(Errs);
599
600 EXPECT_FALSE(RemoveOption);
601 EXPECT_TRUE(cl::ParseCommandLineOptions(3, args, StringRef(), &OS));
602 EXPECT_TRUE(RemoveOption);
603 OS.flush();
604 EXPECT_TRUE(Errs.empty());
605
606 RemoveOption.removeArgument();
607
608 cl::ResetAllOptionOccurrences();
609 EXPECT_FALSE(cl::ParseCommandLineOptions(3, args, StringRef(), &OS));
610 OS.flush();
611 EXPECT_FALSE(Errs.empty());
612 }
613
TEST(CommandLineTest,RemoveFromTopLevelSubCommand)614 TEST(CommandLineTest, RemoveFromTopLevelSubCommand) {
615 cl::ResetCommandLineParser();
616
617 StackOption<bool> TopLevelRemove(
618 "top-level-remove", cl::sub(*cl::TopLevelSubCommand), cl::init(false));
619 StackOption<bool> TopLevelKeep(
620 "top-level-keep", cl::sub(*cl::TopLevelSubCommand), cl::init(false));
621
622 const char *args[] = {"prog", "-top-level-remove"};
623
624 EXPECT_FALSE(TopLevelRemove);
625 EXPECT_TRUE(
626 cl::ParseCommandLineOptions(2, args, StringRef(), &llvm::nulls()));
627 EXPECT_TRUE(TopLevelRemove);
628
629 TopLevelRemove.removeArgument();
630
631 cl::ResetAllOptionOccurrences();
632 EXPECT_FALSE(
633 cl::ParseCommandLineOptions(2, args, StringRef(), &llvm::nulls()));
634 }
635
TEST(CommandLineTest,RemoveFromAllSubCommands)636 TEST(CommandLineTest, RemoveFromAllSubCommands) {
637 cl::ResetCommandLineParser();
638
639 StackSubCommand SC1("sc1", "First Subcommand");
640 StackSubCommand SC2("sc2", "Second Subcommand");
641 StackOption<bool> RemoveOption("remove-option", cl::sub(*cl::AllSubCommands),
642 cl::init(false));
643 StackOption<bool> KeepOption("keep-option", cl::sub(*cl::AllSubCommands),
644 cl::init(false));
645
646 const char *args0[] = {"prog", "-remove-option"};
647 const char *args1[] = {"prog", "sc1", "-remove-option"};
648 const char *args2[] = {"prog", "sc2", "-remove-option"};
649
650 // It should work for all subcommands including the top-level.
651 EXPECT_FALSE(RemoveOption);
652 EXPECT_TRUE(
653 cl::ParseCommandLineOptions(2, args0, StringRef(), &llvm::nulls()));
654 EXPECT_TRUE(RemoveOption);
655
656 RemoveOption = false;
657
658 cl::ResetAllOptionOccurrences();
659 EXPECT_FALSE(RemoveOption);
660 EXPECT_TRUE(
661 cl::ParseCommandLineOptions(3, args1, StringRef(), &llvm::nulls()));
662 EXPECT_TRUE(RemoveOption);
663
664 RemoveOption = false;
665
666 cl::ResetAllOptionOccurrences();
667 EXPECT_FALSE(RemoveOption);
668 EXPECT_TRUE(
669 cl::ParseCommandLineOptions(3, args2, StringRef(), &llvm::nulls()));
670 EXPECT_TRUE(RemoveOption);
671
672 RemoveOption.removeArgument();
673
674 // It should not work for any subcommands including the top-level.
675 cl::ResetAllOptionOccurrences();
676 EXPECT_FALSE(
677 cl::ParseCommandLineOptions(2, args0, StringRef(), &llvm::nulls()));
678 cl::ResetAllOptionOccurrences();
679 EXPECT_FALSE(
680 cl::ParseCommandLineOptions(3, args1, StringRef(), &llvm::nulls()));
681 cl::ResetAllOptionOccurrences();
682 EXPECT_FALSE(
683 cl::ParseCommandLineOptions(3, args2, StringRef(), &llvm::nulls()));
684 }
685
TEST(CommandLineTest,GetRegisteredSubcommands)686 TEST(CommandLineTest, GetRegisteredSubcommands) {
687 cl::ResetCommandLineParser();
688
689 StackSubCommand SC1("sc1", "First Subcommand");
690 StackOption<bool> Opt1("opt1", cl::sub(SC1), cl::init(false));
691 StackSubCommand SC2("sc2", "Second subcommand");
692 StackOption<bool> Opt2("opt2", cl::sub(SC2), cl::init(false));
693
694 const char *args0[] = {"prog", "sc1"};
695 const char *args1[] = {"prog", "sc2"};
696
697 EXPECT_TRUE(
698 cl::ParseCommandLineOptions(2, args0, StringRef(), &llvm::nulls()));
699 EXPECT_FALSE(Opt1);
700 EXPECT_FALSE(Opt2);
701 for (auto *S : cl::getRegisteredSubcommands()) {
702 if (*S) {
703 EXPECT_EQ("sc1", S->getName());
704 }
705 }
706
707 cl::ResetAllOptionOccurrences();
708 EXPECT_TRUE(
709 cl::ParseCommandLineOptions(2, args1, StringRef(), &llvm::nulls()));
710 EXPECT_FALSE(Opt1);
711 EXPECT_FALSE(Opt2);
712 for (auto *S : cl::getRegisteredSubcommands()) {
713 if (*S) {
714 EXPECT_EQ("sc2", S->getName());
715 }
716 }
717 }
718
TEST(CommandLineTest,DefaultOptions)719 TEST(CommandLineTest, DefaultOptions) {
720 cl::ResetCommandLineParser();
721
722 StackOption<std::string> Bar("bar", cl::sub(*cl::AllSubCommands),
723 cl::DefaultOption);
724 StackOption<std::string, cl::alias> Bar_Alias(
725 "b", cl::desc("Alias for -bar"), cl::aliasopt(Bar), cl::DefaultOption);
726
727 StackOption<bool> Foo("foo", cl::init(false), cl::sub(*cl::AllSubCommands),
728 cl::DefaultOption);
729 StackOption<bool, cl::alias> Foo_Alias("f", cl::desc("Alias for -foo"),
730 cl::aliasopt(Foo), cl::DefaultOption);
731
732 StackSubCommand SC1("sc1", "First Subcommand");
733 // Override "-b" and change type in sc1 SubCommand.
734 StackOption<bool> SC1_B("b", cl::sub(SC1), cl::init(false));
735 StackSubCommand SC2("sc2", "Second subcommand");
736 // Override "-foo" and change type in sc2 SubCommand. Note that this does not
737 // affect "-f" alias, which continues to work correctly.
738 StackOption<std::string> SC2_Foo("foo", cl::sub(SC2));
739
740 const char *args0[] = {"prog", "-b", "args0 bar string", "-f"};
741 EXPECT_TRUE(cl::ParseCommandLineOptions(sizeof(args0) / sizeof(char *), args0,
742 StringRef(), &llvm::nulls()));
743 EXPECT_EQ(Bar, "args0 bar string");
744 EXPECT_TRUE(Foo);
745 EXPECT_FALSE(SC1_B);
746 EXPECT_TRUE(SC2_Foo.empty());
747
748 cl::ResetAllOptionOccurrences();
749
750 const char *args1[] = {"prog", "sc1", "-b", "-bar", "args1 bar string", "-f"};
751 EXPECT_TRUE(cl::ParseCommandLineOptions(sizeof(args1) / sizeof(char *), args1,
752 StringRef(), &llvm::nulls()));
753 EXPECT_EQ(Bar, "args1 bar string");
754 EXPECT_TRUE(Foo);
755 EXPECT_TRUE(SC1_B);
756 EXPECT_TRUE(SC2_Foo.empty());
757 for (auto *S : cl::getRegisteredSubcommands()) {
758 if (*S) {
759 EXPECT_EQ("sc1", S->getName());
760 }
761 }
762
763 cl::ResetAllOptionOccurrences();
764
765 const char *args2[] = {"prog", "sc2", "-b", "args2 bar string",
766 "-f", "-foo", "foo string"};
767 EXPECT_TRUE(cl::ParseCommandLineOptions(sizeof(args2) / sizeof(char *), args2,
768 StringRef(), &llvm::nulls()));
769 EXPECT_EQ(Bar, "args2 bar string");
770 EXPECT_TRUE(Foo);
771 EXPECT_FALSE(SC1_B);
772 EXPECT_EQ(SC2_Foo, "foo string");
773 for (auto *S : cl::getRegisteredSubcommands()) {
774 if (*S) {
775 EXPECT_EQ("sc2", S->getName());
776 }
777 }
778 cl::ResetCommandLineParser();
779 }
780
TEST(CommandLineTest,ArgumentLimit)781 TEST(CommandLineTest, ArgumentLimit) {
782 std::string args(32 * 4096, 'a');
783 EXPECT_FALSE(llvm::sys::commandLineFitsWithinSystemLimits("cl", args.data()));
784 std::string args2(256, 'a');
785 EXPECT_TRUE(llvm::sys::commandLineFitsWithinSystemLimits("cl", args2.data()));
786 }
787
TEST(CommandLineTest,ArgumentLimitWindows)788 TEST(CommandLineTest, ArgumentLimitWindows) {
789 if (!Triple(sys::getProcessTriple()).isOSWindows())
790 GTEST_SKIP();
791 // We use 32000 as a limit for command line length. Program name ('cl'),
792 // separating spaces and termination null character occupy 5 symbols.
793 std::string long_arg(32000 - 5, 'b');
794 EXPECT_TRUE(
795 llvm::sys::commandLineFitsWithinSystemLimits("cl", long_arg.data()));
796 long_arg += 'b';
797 EXPECT_FALSE(
798 llvm::sys::commandLineFitsWithinSystemLimits("cl", long_arg.data()));
799 }
800
TEST(CommandLineTest,ResponseFileWindows)801 TEST(CommandLineTest, ResponseFileWindows) {
802 if (!Triple(sys::getProcessTriple()).isOSWindows())
803 GTEST_SKIP();
804
805 StackOption<std::string, cl::list<std::string>> InputFilenames(
806 cl::Positional, cl::desc("<input files>"));
807 StackOption<bool> TopLevelOpt("top-level", cl::init(false));
808
809 // Create response file.
810 TempFile ResponseFile("resp-", ".txt",
811 "-top-level\npath\\dir\\file1\npath/dir/file2",
812 /*Unique*/ true);
813
814 llvm::SmallString<128> RspOpt;
815 RspOpt.append(1, '@');
816 RspOpt.append(ResponseFile.path());
817 const char *args[] = {"prog", RspOpt.c_str()};
818 EXPECT_FALSE(TopLevelOpt);
819 EXPECT_TRUE(
820 cl::ParseCommandLineOptions(2, args, StringRef(), &llvm::nulls()));
821 EXPECT_TRUE(TopLevelOpt);
822 EXPECT_EQ(InputFilenames[0], "path\\dir\\file1");
823 EXPECT_EQ(InputFilenames[1], "path/dir/file2");
824 }
825
TEST(CommandLineTest,ResponseFiles)826 TEST(CommandLineTest, ResponseFiles) {
827 vfs::InMemoryFileSystem FS;
828 #ifdef _WIN32
829 const char *TestRoot = "C:\\";
830 #else
831 const char *TestRoot = "/";
832 #endif
833 FS.setCurrentWorkingDirectory(TestRoot);
834
835 // Create included response file of first level.
836 llvm::StringRef IncludedFileName = "resp1";
837 FS.addFile(IncludedFileName, 0,
838 llvm::MemoryBuffer::getMemBuffer("-option_1 -option_2\n"
839 "@incdir/resp2\n"
840 "-option_3=abcd\n"
841 "@incdir/resp3\n"
842 "-option_4=efjk\n"));
843
844 // Directory for included file.
845 llvm::StringRef IncDir = "incdir";
846
847 // Create included response file of second level.
848 llvm::SmallString<128> IncludedFileName2;
849 llvm::sys::path::append(IncludedFileName2, IncDir, "resp2");
850 FS.addFile(IncludedFileName2, 0,
851 MemoryBuffer::getMemBuffer("-option_21 -option_22\n"
852 "-option_23=abcd\n"));
853
854 // Create second included response file of second level.
855 llvm::SmallString<128> IncludedFileName3;
856 llvm::sys::path::append(IncludedFileName3, IncDir, "resp3");
857 FS.addFile(IncludedFileName3, 0,
858 MemoryBuffer::getMemBuffer("-option_31 -option_32\n"
859 "-option_33=abcd\n"));
860
861 // Prepare 'file' with reference to response file.
862 SmallString<128> IncRef;
863 IncRef.append(1, '@');
864 IncRef.append(IncludedFileName);
865 llvm::SmallVector<const char *, 4> Argv = {"test/test", "-flag_1",
866 IncRef.c_str(), "-flag_2"};
867
868 // Expand response files.
869 llvm::BumpPtrAllocator A;
870 llvm::StringSaver Saver(A);
871 ASSERT_TRUE(llvm::cl::ExpandResponseFiles(
872 Saver, llvm::cl::TokenizeGNUCommandLine, Argv, false, true, false,
873 /*CurrentDir=*/StringRef(TestRoot), FS));
874 EXPECT_THAT(Argv, testing::Pointwise(
875 StringEquality(),
876 {"test/test", "-flag_1", "-option_1", "-option_2",
877 "-option_21", "-option_22", "-option_23=abcd",
878 "-option_3=abcd", "-option_31", "-option_32",
879 "-option_33=abcd", "-option_4=efjk", "-flag_2"}));
880 }
881
TEST(CommandLineTest,RecursiveResponseFiles)882 TEST(CommandLineTest, RecursiveResponseFiles) {
883 vfs::InMemoryFileSystem FS;
884 #ifdef _WIN32
885 const char *TestRoot = "C:\\";
886 #else
887 const char *TestRoot = "/";
888 #endif
889 FS.setCurrentWorkingDirectory(TestRoot);
890
891 StringRef SelfFilePath = "self.rsp";
892 std::string SelfFileRef = ("@" + SelfFilePath).str();
893
894 StringRef NestedFilePath = "nested.rsp";
895 std::string NestedFileRef = ("@" + NestedFilePath).str();
896
897 StringRef FlagFilePath = "flag.rsp";
898 std::string FlagFileRef = ("@" + FlagFilePath).str();
899
900 std::string SelfFileContents;
901 raw_string_ostream SelfFile(SelfFileContents);
902 SelfFile << "-option_1\n";
903 SelfFile << FlagFileRef << "\n";
904 SelfFile << NestedFileRef << "\n";
905 SelfFile << SelfFileRef << "\n";
906 FS.addFile(SelfFilePath, 0, MemoryBuffer::getMemBuffer(SelfFile.str()));
907
908 std::string NestedFileContents;
909 raw_string_ostream NestedFile(NestedFileContents);
910 NestedFile << "-option_2\n";
911 NestedFile << FlagFileRef << "\n";
912 NestedFile << SelfFileRef << "\n";
913 NestedFile << NestedFileRef << "\n";
914 FS.addFile(NestedFilePath, 0, MemoryBuffer::getMemBuffer(NestedFile.str()));
915
916 std::string FlagFileContents;
917 raw_string_ostream FlagFile(FlagFileContents);
918 FlagFile << "-option_x\n";
919 FS.addFile(FlagFilePath, 0, MemoryBuffer::getMemBuffer(FlagFile.str()));
920
921 // Ensure:
922 // Recursive expansion terminates
923 // Recursive files never expand
924 // Non-recursive repeats are allowed
925 SmallVector<const char *, 4> Argv = {"test/test", SelfFileRef.c_str(),
926 "-option_3"};
927 BumpPtrAllocator A;
928 StringSaver Saver(A);
929 #ifdef _WIN32
930 cl::TokenizerCallback Tokenizer = cl::TokenizeWindowsCommandLine;
931 #else
932 cl::TokenizerCallback Tokenizer = cl::TokenizeGNUCommandLine;
933 #endif
934 ASSERT_FALSE(
935 cl::ExpandResponseFiles(Saver, Tokenizer, Argv, false, false, false,
936 /*CurrentDir=*/llvm::StringRef(TestRoot), FS));
937
938 EXPECT_THAT(Argv,
939 testing::Pointwise(StringEquality(),
940 {"test/test", "-option_1", "-option_x",
941 "-option_2", "-option_x", SelfFileRef.c_str(),
942 NestedFileRef.c_str(), SelfFileRef.c_str(),
943 "-option_3"}));
944 }
945
TEST(CommandLineTest,ResponseFilesAtArguments)946 TEST(CommandLineTest, ResponseFilesAtArguments) {
947 vfs::InMemoryFileSystem FS;
948 #ifdef _WIN32
949 const char *TestRoot = "C:\\";
950 #else
951 const char *TestRoot = "/";
952 #endif
953 FS.setCurrentWorkingDirectory(TestRoot);
954
955 StringRef ResponseFilePath = "test.rsp";
956
957 std::string ResponseFileContents;
958 raw_string_ostream ResponseFile(ResponseFileContents);
959 ResponseFile << "-foo" << "\n";
960 ResponseFile << "-bar" << "\n";
961 FS.addFile(ResponseFilePath, 0,
962 MemoryBuffer::getMemBuffer(ResponseFile.str()));
963
964 // Ensure we expand rsp files after lots of non-rsp arguments starting with @.
965 constexpr size_t NON_RSP_AT_ARGS = 64;
966 SmallVector<const char *, 4> Argv = {"test/test"};
967 Argv.append(NON_RSP_AT_ARGS, "@non_rsp_at_arg");
968 std::string ResponseFileRef = ("@" + ResponseFilePath).str();
969 Argv.push_back(ResponseFileRef.c_str());
970
971 BumpPtrAllocator A;
972 StringSaver Saver(A);
973 ASSERT_FALSE(cl::ExpandResponseFiles(Saver, cl::TokenizeGNUCommandLine, Argv,
974 false, false, false,
975 /*CurrentDir=*/StringRef(TestRoot), FS));
976
977 // ASSERT instead of EXPECT to prevent potential out-of-bounds access.
978 ASSERT_EQ(Argv.size(), 1 + NON_RSP_AT_ARGS + 2);
979 size_t i = 0;
980 EXPECT_STREQ(Argv[i++], "test/test");
981 for (; i < 1 + NON_RSP_AT_ARGS; ++i)
982 EXPECT_STREQ(Argv[i], "@non_rsp_at_arg");
983 EXPECT_STREQ(Argv[i++], "-foo");
984 EXPECT_STREQ(Argv[i++], "-bar");
985 }
986
TEST(CommandLineTest,ResponseFileRelativePath)987 TEST(CommandLineTest, ResponseFileRelativePath) {
988 vfs::InMemoryFileSystem FS;
989 #ifdef _WIN32
990 const char *TestRoot = "C:\\";
991 #else
992 const char *TestRoot = "//net";
993 #endif
994 FS.setCurrentWorkingDirectory(TestRoot);
995
996 StringRef OuterFile = "dir/outer.rsp";
997 StringRef OuterFileContents = "@inner.rsp";
998 FS.addFile(OuterFile, 0, MemoryBuffer::getMemBuffer(OuterFileContents));
999
1000 StringRef InnerFile = "dir/inner.rsp";
1001 StringRef InnerFileContents = "-flag";
1002 FS.addFile(InnerFile, 0, MemoryBuffer::getMemBuffer(InnerFileContents));
1003
1004 SmallVector<const char *, 2> Argv = {"test/test", "@dir/outer.rsp"};
1005
1006 BumpPtrAllocator A;
1007 StringSaver Saver(A);
1008 ASSERT_TRUE(cl::ExpandResponseFiles(Saver, cl::TokenizeGNUCommandLine, Argv,
1009 false, true, false,
1010 /*CurrentDir=*/StringRef(TestRoot), FS));
1011 EXPECT_THAT(Argv,
1012 testing::Pointwise(StringEquality(), {"test/test", "-flag"}));
1013 }
1014
TEST(CommandLineTest,ResponseFileEOLs)1015 TEST(CommandLineTest, ResponseFileEOLs) {
1016 vfs::InMemoryFileSystem FS;
1017 #ifdef _WIN32
1018 const char *TestRoot = "C:\\";
1019 #else
1020 const char *TestRoot = "//net";
1021 #endif
1022 FS.setCurrentWorkingDirectory(TestRoot);
1023 FS.addFile("eols.rsp", 0,
1024 MemoryBuffer::getMemBuffer("-Xclang -Wno-whatever\n input.cpp"));
1025 SmallVector<const char *, 2> Argv = {"clang", "@eols.rsp"};
1026 BumpPtrAllocator A;
1027 StringSaver Saver(A);
1028 ASSERT_TRUE(cl::ExpandResponseFiles(Saver, cl::TokenizeWindowsCommandLine,
1029 Argv, true, true, false,
1030 /*CurrentDir=*/StringRef(TestRoot), FS));
1031 const char *Expected[] = {"clang", "-Xclang", "-Wno-whatever", nullptr,
1032 "input.cpp"};
1033 ASSERT_EQ(array_lengthof(Expected), Argv.size());
1034 for (size_t I = 0, E = array_lengthof(Expected); I < E; ++I) {
1035 if (Expected[I] == nullptr) {
1036 ASSERT_EQ(Argv[I], nullptr);
1037 } else {
1038 ASSERT_STREQ(Expected[I], Argv[I]);
1039 }
1040 }
1041 }
1042
TEST(CommandLineTest,SetDefautValue)1043 TEST(CommandLineTest, SetDefautValue) {
1044 cl::ResetCommandLineParser();
1045
1046 StackOption<std::string> Opt1("opt1", cl::init("true"));
1047 StackOption<bool> Opt2("opt2", cl::init(true));
1048 cl::alias Alias("alias", llvm::cl::aliasopt(Opt2));
1049 StackOption<int> Opt3("opt3", cl::init(3));
1050
1051 const char *args[] = {"prog", "-opt1=false", "-opt2", "-opt3"};
1052
1053 EXPECT_TRUE(
1054 cl::ParseCommandLineOptions(2, args, StringRef(), &llvm::nulls()));
1055
1056 EXPECT_EQ(Opt1, "false");
1057 EXPECT_TRUE(Opt2);
1058 EXPECT_EQ(Opt3, 3);
1059
1060 Opt2 = false;
1061 Opt3 = 1;
1062
1063 cl::ResetAllOptionOccurrences();
1064
1065 for (auto &OM : cl::getRegisteredOptions(*cl::TopLevelSubCommand)) {
1066 cl::Option *O = OM.second;
1067 if (O->ArgStr == "opt2") {
1068 continue;
1069 }
1070 O->setDefault();
1071 }
1072
1073 EXPECT_EQ(Opt1, "true");
1074 EXPECT_TRUE(Opt2);
1075 EXPECT_EQ(Opt3, 3);
1076 Alias.removeArgument();
1077 }
1078
TEST(CommandLineTest,ReadConfigFile)1079 TEST(CommandLineTest, ReadConfigFile) {
1080 llvm::SmallVector<const char *, 1> Argv;
1081
1082 TempDir TestDir("unittest", /*Unique*/ true);
1083 TempDir TestSubDir(TestDir.path("subdir"), /*Unique*/ false);
1084
1085 llvm::SmallString<128> TestCfg = TestDir.path("foo");
1086 TempFile ConfigFile(TestCfg, "",
1087 "# Comment\n"
1088 "-option_1\n"
1089 "-option_2=<CFGDIR>/dir1\n"
1090 "-option_3=<CFGDIR>\n"
1091 "-option_4 <CFGDIR>\n"
1092 "-option_5=<CFG\\\n"
1093 "DIR>\n"
1094 "-option_6=<CFGDIR>/dir1,<CFGDIR>/dir2\n"
1095 "@subconfig\n"
1096 "-option_11=abcd\n"
1097 "-option_12=\\\n"
1098 "cdef\n");
1099
1100 llvm::SmallString<128> TestCfg2 = TestDir.path("subconfig");
1101 TempFile ConfigFile2(TestCfg2, "",
1102 "-option_7\n"
1103 "-option_8=<CFGDIR>/dir2\n"
1104 "@subdir/subfoo\n"
1105 "\n"
1106 " # comment\n");
1107
1108 llvm::SmallString<128> TestCfg3 = TestSubDir.path("subfoo");
1109 TempFile ConfigFile3(TestCfg3, "",
1110 "-option_9=<CFGDIR>/dir3\n"
1111 "@<CFGDIR>/subfoo2\n");
1112
1113 llvm::SmallString<128> TestCfg4 = TestSubDir.path("subfoo2");
1114 TempFile ConfigFile4(TestCfg4, "", "-option_10\n");
1115
1116 // Make sure the current directory is not the directory where config files
1117 // resides. In this case the code that expands response files will not find
1118 // 'subconfig' unless it resolves nested inclusions relative to the including
1119 // file.
1120 llvm::SmallString<128> CurrDir;
1121 std::error_code EC = llvm::sys::fs::current_path(CurrDir);
1122 EXPECT_TRUE(!EC);
1123 EXPECT_NE(CurrDir.str(), TestDir.path());
1124
1125 llvm::BumpPtrAllocator A;
1126 llvm::StringSaver Saver(A);
1127 bool Result = llvm::cl::readConfigFile(ConfigFile.path(), Saver, Argv);
1128
1129 EXPECT_TRUE(Result);
1130 EXPECT_EQ(Argv.size(), 13U);
1131 EXPECT_STREQ(Argv[0], "-option_1");
1132 EXPECT_STREQ(Argv[1],
1133 ("-option_2=" + TestDir.path() + "/dir1").str().c_str());
1134 EXPECT_STREQ(Argv[2], ("-option_3=" + TestDir.path()).str().c_str());
1135 EXPECT_STREQ(Argv[3], "-option_4");
1136 EXPECT_STREQ(Argv[4], TestDir.path().str().c_str());
1137 EXPECT_STREQ(Argv[5], ("-option_5=" + TestDir.path()).str().c_str());
1138 EXPECT_STREQ(Argv[6], ("-option_6=" + TestDir.path() + "/dir1," +
1139 TestDir.path() + "/dir2")
1140 .str()
1141 .c_str());
1142 EXPECT_STREQ(Argv[7], "-option_7");
1143 EXPECT_STREQ(Argv[8],
1144 ("-option_8=" + TestDir.path() + "/dir2").str().c_str());
1145 EXPECT_STREQ(Argv[9],
1146 ("-option_9=" + TestSubDir.path() + "/dir3").str().c_str());
1147 EXPECT_STREQ(Argv[10], "-option_10");
1148 EXPECT_STREQ(Argv[11], "-option_11=abcd");
1149 EXPECT_STREQ(Argv[12], "-option_12=cdef");
1150 }
1151
TEST(CommandLineTest,PositionalEatArgsError)1152 TEST(CommandLineTest, PositionalEatArgsError) {
1153 cl::ResetCommandLineParser();
1154
1155 StackOption<std::string, cl::list<std::string>> PosEatArgs(
1156 "positional-eat-args", cl::Positional, cl::desc("<arguments>..."),
1157 cl::PositionalEatsArgs);
1158 StackOption<std::string, cl::list<std::string>> PosEatArgs2(
1159 "positional-eat-args2", cl::Positional, cl::desc("Some strings"),
1160 cl::PositionalEatsArgs);
1161
1162 const char *args[] = {"prog", "-positional-eat-args=XXXX"};
1163 const char *args2[] = {"prog", "-positional-eat-args=XXXX", "-foo"};
1164 const char *args3[] = {"prog", "-positional-eat-args", "-foo"};
1165 const char *args4[] = {"prog", "-positional-eat-args",
1166 "-foo", "-positional-eat-args2",
1167 "-bar", "foo"};
1168
1169 std::string Errs;
1170 raw_string_ostream OS(Errs);
1171 EXPECT_FALSE(cl::ParseCommandLineOptions(2, args, StringRef(), &OS)); OS.flush();
1172 EXPECT_FALSE(Errs.empty()); Errs.clear();
1173 EXPECT_FALSE(cl::ParseCommandLineOptions(3, args2, StringRef(), &OS)); OS.flush();
1174 EXPECT_FALSE(Errs.empty()); Errs.clear();
1175 EXPECT_TRUE(cl::ParseCommandLineOptions(3, args3, StringRef(), &OS)); OS.flush();
1176 EXPECT_TRUE(Errs.empty()); Errs.clear();
1177
1178 cl::ResetAllOptionOccurrences();
1179 EXPECT_TRUE(cl::ParseCommandLineOptions(6, args4, StringRef(), &OS)); OS.flush();
1180 EXPECT_EQ(PosEatArgs.size(), 1u);
1181 EXPECT_EQ(PosEatArgs2.size(), 2u);
1182 EXPECT_TRUE(Errs.empty());
1183 }
1184
1185 #ifdef _WIN32
checkSeparators(StringRef Path)1186 void checkSeparators(StringRef Path) {
1187 char UndesiredSeparator = sys::path::get_separator()[0] == '/' ? '\\' : '/';
1188 ASSERT_EQ(Path.find(UndesiredSeparator), StringRef::npos);
1189 }
1190
TEST(CommandLineTest,GetCommandLineArguments)1191 TEST(CommandLineTest, GetCommandLineArguments) {
1192 int argc = __argc;
1193 char **argv = __argv;
1194
1195 // GetCommandLineArguments is called in InitLLVM.
1196 llvm::InitLLVM X(argc, argv);
1197
1198 EXPECT_EQ(llvm::sys::path::is_absolute(argv[0]),
1199 llvm::sys::path::is_absolute(__argv[0]));
1200 checkSeparators(argv[0]);
1201
1202 EXPECT_TRUE(
1203 llvm::sys::path::filename(argv[0]).equals_insensitive("supporttests.exe"))
1204 << "Filename of test executable is "
1205 << llvm::sys::path::filename(argv[0]);
1206 }
1207 #endif
1208
1209 class OutputRedirector {
1210 public:
OutputRedirector(int RedirectFD)1211 OutputRedirector(int RedirectFD)
1212 : RedirectFD(RedirectFD), OldFD(dup(RedirectFD)) {
1213 if (OldFD == -1 ||
1214 sys::fs::createTemporaryFile("unittest-redirect", "", NewFD,
1215 FilePath) ||
1216 dup2(NewFD, RedirectFD) == -1)
1217 Valid = false;
1218 }
1219
~OutputRedirector()1220 ~OutputRedirector() {
1221 dup2(OldFD, RedirectFD);
1222 close(OldFD);
1223 close(NewFD);
1224 }
1225
1226 SmallVector<char, 128> FilePath;
1227 bool Valid = true;
1228
1229 private:
1230 int RedirectFD;
1231 int OldFD;
1232 int NewFD;
1233 };
1234
1235 struct AutoDeleteFile {
1236 SmallVector<char, 128> FilePath;
~AutoDeleteFile__anon6509acef0111::AutoDeleteFile1237 ~AutoDeleteFile() {
1238 if (!FilePath.empty())
1239 sys::fs::remove(std::string(FilePath.data(), FilePath.size()));
1240 }
1241 };
1242
1243 class PrintOptionInfoTest : public ::testing::Test {
1244 public:
1245 // Return std::string because the output of a failing EXPECT check is
1246 // unreadable for StringRef. It also avoids any lifetime issues.
runTest(Ts...OptionAttributes)1247 template <typename... Ts> std::string runTest(Ts... OptionAttributes) {
1248 outs().flush(); // flush any output from previous tests
1249 AutoDeleteFile File;
1250 {
1251 OutputRedirector Stdout(fileno(stdout));
1252 if (!Stdout.Valid)
1253 return "";
1254 File.FilePath = Stdout.FilePath;
1255
1256 StackOption<OptionValue> TestOption(Opt, cl::desc(HelpText),
1257 OptionAttributes...);
1258 printOptionInfo(TestOption, 26);
1259 outs().flush();
1260 }
1261 auto Buffer = MemoryBuffer::getFile(File.FilePath);
1262 if (!Buffer)
1263 return "";
1264 return Buffer->get()->getBuffer().str();
1265 }
1266
1267 enum class OptionValue { Val };
1268 const StringRef Opt = "some-option";
1269 const StringRef HelpText = "some help";
1270
1271 private:
1272 // This is a workaround for cl::Option sub-classes having their
1273 // printOptionInfo functions private.
printOptionInfo(const cl::Option & O,size_t Width)1274 void printOptionInfo(const cl::Option &O, size_t Width) {
1275 O.printOptionInfo(Width);
1276 }
1277 };
1278
TEST_F(PrintOptionInfoTest,PrintOptionInfoValueOptionalWithoutSentinel)1279 TEST_F(PrintOptionInfoTest, PrintOptionInfoValueOptionalWithoutSentinel) {
1280 std::string Output =
1281 runTest(cl::ValueOptional,
1282 cl::values(clEnumValN(OptionValue::Val, "v1", "desc1")));
1283
1284 // clang-format off
1285 EXPECT_EQ(Output, (" --" + Opt + "=<value> - " + HelpText + "\n"
1286 " =v1 - desc1\n")
1287 .str());
1288 // clang-format on
1289 }
1290
TEST_F(PrintOptionInfoTest,PrintOptionInfoValueOptionalWithSentinel)1291 TEST_F(PrintOptionInfoTest, PrintOptionInfoValueOptionalWithSentinel) {
1292 std::string Output = runTest(
1293 cl::ValueOptional, cl::values(clEnumValN(OptionValue::Val, "v1", "desc1"),
1294 clEnumValN(OptionValue::Val, "", "")));
1295
1296 // clang-format off
1297 EXPECT_EQ(Output,
1298 (" --" + Opt + " - " + HelpText + "\n"
1299 " --" + Opt + "=<value> - " + HelpText + "\n"
1300 " =v1 - desc1\n")
1301 .str());
1302 // clang-format on
1303 }
1304
TEST_F(PrintOptionInfoTest,PrintOptionInfoValueOptionalWithSentinelWithHelp)1305 TEST_F(PrintOptionInfoTest, PrintOptionInfoValueOptionalWithSentinelWithHelp) {
1306 std::string Output = runTest(
1307 cl::ValueOptional, cl::values(clEnumValN(OptionValue::Val, "v1", "desc1"),
1308 clEnumValN(OptionValue::Val, "", "desc2")));
1309
1310 // clang-format off
1311 EXPECT_EQ(Output, (" --" + Opt + " - " + HelpText + "\n"
1312 " --" + Opt + "=<value> - " + HelpText + "\n"
1313 " =v1 - desc1\n"
1314 " =<empty> - desc2\n")
1315 .str());
1316 // clang-format on
1317 }
1318
TEST_F(PrintOptionInfoTest,PrintOptionInfoValueRequiredWithEmptyValueName)1319 TEST_F(PrintOptionInfoTest, PrintOptionInfoValueRequiredWithEmptyValueName) {
1320 std::string Output = runTest(
1321 cl::ValueRequired, cl::values(clEnumValN(OptionValue::Val, "v1", "desc1"),
1322 clEnumValN(OptionValue::Val, "", "")));
1323
1324 // clang-format off
1325 EXPECT_EQ(Output, (" --" + Opt + "=<value> - " + HelpText + "\n"
1326 " =v1 - desc1\n"
1327 " =<empty>\n")
1328 .str());
1329 // clang-format on
1330 }
1331
TEST_F(PrintOptionInfoTest,PrintOptionInfoEmptyValueDescription)1332 TEST_F(PrintOptionInfoTest, PrintOptionInfoEmptyValueDescription) {
1333 std::string Output = runTest(
1334 cl::ValueRequired, cl::values(clEnumValN(OptionValue::Val, "v1", "")));
1335
1336 // clang-format off
1337 EXPECT_EQ(Output,
1338 (" --" + Opt + "=<value> - " + HelpText + "\n"
1339 " =v1\n").str());
1340 // clang-format on
1341 }
1342
TEST_F(PrintOptionInfoTest,PrintOptionInfoMultilineValueDescription)1343 TEST_F(PrintOptionInfoTest, PrintOptionInfoMultilineValueDescription) {
1344 std::string Output =
1345 runTest(cl::ValueRequired,
1346 cl::values(clEnumValN(OptionValue::Val, "v1",
1347 "This is the first enum value\n"
1348 "which has a really long description\n"
1349 "thus it is multi-line."),
1350 clEnumValN(OptionValue::Val, "",
1351 "This is an unnamed enum value option\n"
1352 "Should be indented as well")));
1353
1354 // clang-format off
1355 EXPECT_EQ(Output,
1356 (" --" + Opt + "=<value> - " + HelpText + "\n"
1357 " =v1 - This is the first enum value\n"
1358 " which has a really long description\n"
1359 " thus it is multi-line.\n"
1360 " =<empty> - This is an unnamed enum value option\n"
1361 " Should be indented as well\n").str());
1362 // clang-format on
1363 }
1364
1365 class GetOptionWidthTest : public ::testing::Test {
1366 public:
1367 enum class OptionValue { Val };
1368
1369 template <typename... Ts>
runTest(StringRef ArgName,Ts...OptionAttributes)1370 size_t runTest(StringRef ArgName, Ts... OptionAttributes) {
1371 StackOption<OptionValue> TestOption(ArgName, cl::desc("some help"),
1372 OptionAttributes...);
1373 return getOptionWidth(TestOption);
1374 }
1375
1376 private:
1377 // This is a workaround for cl::Option sub-classes having their
1378 // printOptionInfo
1379 // functions private.
getOptionWidth(const cl::Option & O)1380 size_t getOptionWidth(const cl::Option &O) { return O.getOptionWidth(); }
1381 };
1382
TEST_F(GetOptionWidthTest,GetOptionWidthArgNameLonger)1383 TEST_F(GetOptionWidthTest, GetOptionWidthArgNameLonger) {
1384 StringRef ArgName("a-long-argument-name");
1385 size_t ExpectedStrSize = (" --" + ArgName + "=<value> - ").str().size();
1386 EXPECT_EQ(
1387 runTest(ArgName, cl::values(clEnumValN(OptionValue::Val, "v", "help"))),
1388 ExpectedStrSize);
1389 }
1390
TEST_F(GetOptionWidthTest,GetOptionWidthFirstOptionNameLonger)1391 TEST_F(GetOptionWidthTest, GetOptionWidthFirstOptionNameLonger) {
1392 StringRef OptName("a-long-option-name");
1393 size_t ExpectedStrSize = (" =" + OptName + " - ").str().size();
1394 EXPECT_EQ(
1395 runTest("a", cl::values(clEnumValN(OptionValue::Val, OptName, "help"),
1396 clEnumValN(OptionValue::Val, "b", "help"))),
1397 ExpectedStrSize);
1398 }
1399
TEST_F(GetOptionWidthTest,GetOptionWidthSecondOptionNameLonger)1400 TEST_F(GetOptionWidthTest, GetOptionWidthSecondOptionNameLonger) {
1401 StringRef OptName("a-long-option-name");
1402 size_t ExpectedStrSize = (" =" + OptName + " - ").str().size();
1403 EXPECT_EQ(
1404 runTest("a", cl::values(clEnumValN(OptionValue::Val, "b", "help"),
1405 clEnumValN(OptionValue::Val, OptName, "help"))),
1406 ExpectedStrSize);
1407 }
1408
TEST_F(GetOptionWidthTest,GetOptionWidthEmptyOptionNameLonger)1409 TEST_F(GetOptionWidthTest, GetOptionWidthEmptyOptionNameLonger) {
1410 size_t ExpectedStrSize = StringRef(" =<empty> - ").size();
1411 // The length of a=<value> (including indentation) is actually the same as the
1412 // =<empty> string, so it is impossible to distinguish via testing the case
1413 // where the empty string is picked from where the option name is picked.
1414 EXPECT_EQ(runTest("a", cl::values(clEnumValN(OptionValue::Val, "b", "help"),
1415 clEnumValN(OptionValue::Val, "", "help"))),
1416 ExpectedStrSize);
1417 }
1418
TEST_F(GetOptionWidthTest,GetOptionWidthValueOptionalEmptyOptionWithNoDescription)1419 TEST_F(GetOptionWidthTest,
1420 GetOptionWidthValueOptionalEmptyOptionWithNoDescription) {
1421 StringRef ArgName("a");
1422 // The length of a=<value> (including indentation) is actually the same as the
1423 // =<empty> string, so it is impossible to distinguish via testing the case
1424 // where the empty string is ignored from where it is not ignored.
1425 // The dash will not actually be printed, but the space it would take up is
1426 // included to ensure a consistent column width.
1427 size_t ExpectedStrSize = (" -" + ArgName + "=<value> - ").str().size();
1428 EXPECT_EQ(runTest(ArgName, cl::ValueOptional,
1429 cl::values(clEnumValN(OptionValue::Val, "value", "help"),
1430 clEnumValN(OptionValue::Val, "", ""))),
1431 ExpectedStrSize);
1432 }
1433
TEST_F(GetOptionWidthTest,GetOptionWidthValueRequiredEmptyOptionWithNoDescription)1434 TEST_F(GetOptionWidthTest,
1435 GetOptionWidthValueRequiredEmptyOptionWithNoDescription) {
1436 // The length of a=<value> (including indentation) is actually the same as the
1437 // =<empty> string, so it is impossible to distinguish via testing the case
1438 // where the empty string is picked from where the option name is picked
1439 size_t ExpectedStrSize = StringRef(" =<empty> - ").size();
1440 EXPECT_EQ(runTest("a", cl::ValueRequired,
1441 cl::values(clEnumValN(OptionValue::Val, "value", "help"),
1442 clEnumValN(OptionValue::Val, "", ""))),
1443 ExpectedStrSize);
1444 }
1445
TEST(CommandLineTest,PrefixOptions)1446 TEST(CommandLineTest, PrefixOptions) {
1447 cl::ResetCommandLineParser();
1448
1449 StackOption<std::string, cl::list<std::string>> IncludeDirs(
1450 "I", cl::Prefix, cl::desc("Declare an include directory"));
1451
1452 // Test non-prefixed variant works with cl::Prefix options.
1453 EXPECT_TRUE(IncludeDirs.empty());
1454 const char *args[] = {"prog", "-I=/usr/include"};
1455 EXPECT_TRUE(
1456 cl::ParseCommandLineOptions(2, args, StringRef(), &llvm::nulls()));
1457 EXPECT_EQ(IncludeDirs.size(), 1u);
1458 EXPECT_EQ(IncludeDirs.front().compare("/usr/include"), 0);
1459
1460 IncludeDirs.erase(IncludeDirs.begin());
1461 cl::ResetAllOptionOccurrences();
1462
1463 // Test non-prefixed variant works with cl::Prefix options when value is
1464 // passed in following argument.
1465 EXPECT_TRUE(IncludeDirs.empty());
1466 const char *args2[] = {"prog", "-I", "/usr/include"};
1467 EXPECT_TRUE(
1468 cl::ParseCommandLineOptions(3, args2, StringRef(), &llvm::nulls()));
1469 EXPECT_EQ(IncludeDirs.size(), 1u);
1470 EXPECT_EQ(IncludeDirs.front().compare("/usr/include"), 0);
1471
1472 IncludeDirs.erase(IncludeDirs.begin());
1473 cl::ResetAllOptionOccurrences();
1474
1475 // Test prefixed variant works with cl::Prefix options.
1476 EXPECT_TRUE(IncludeDirs.empty());
1477 const char *args3[] = {"prog", "-I/usr/include"};
1478 EXPECT_TRUE(
1479 cl::ParseCommandLineOptions(2, args3, StringRef(), &llvm::nulls()));
1480 EXPECT_EQ(IncludeDirs.size(), 1u);
1481 EXPECT_EQ(IncludeDirs.front().compare("/usr/include"), 0);
1482
1483 StackOption<std::string, cl::list<std::string>> MacroDefs(
1484 "D", cl::AlwaysPrefix, cl::desc("Define a macro"),
1485 cl::value_desc("MACRO[=VALUE]"));
1486
1487 cl::ResetAllOptionOccurrences();
1488
1489 // Test non-prefixed variant does not work with cl::AlwaysPrefix options:
1490 // equal sign is part of the value.
1491 EXPECT_TRUE(MacroDefs.empty());
1492 const char *args4[] = {"prog", "-D=HAVE_FOO"};
1493 EXPECT_TRUE(
1494 cl::ParseCommandLineOptions(2, args4, StringRef(), &llvm::nulls()));
1495 EXPECT_EQ(MacroDefs.size(), 1u);
1496 EXPECT_EQ(MacroDefs.front().compare("=HAVE_FOO"), 0);
1497
1498 MacroDefs.erase(MacroDefs.begin());
1499 cl::ResetAllOptionOccurrences();
1500
1501 // Test non-prefixed variant does not allow value to be passed in following
1502 // argument with cl::AlwaysPrefix options.
1503 EXPECT_TRUE(MacroDefs.empty());
1504 const char *args5[] = {"prog", "-D", "HAVE_FOO"};
1505 EXPECT_FALSE(
1506 cl::ParseCommandLineOptions(3, args5, StringRef(), &llvm::nulls()));
1507 EXPECT_TRUE(MacroDefs.empty());
1508
1509 cl::ResetAllOptionOccurrences();
1510
1511 // Test prefixed variant works with cl::AlwaysPrefix options.
1512 EXPECT_TRUE(MacroDefs.empty());
1513 const char *args6[] = {"prog", "-DHAVE_FOO"};
1514 EXPECT_TRUE(
1515 cl::ParseCommandLineOptions(2, args6, StringRef(), &llvm::nulls()));
1516 EXPECT_EQ(MacroDefs.size(), 1u);
1517 EXPECT_EQ(MacroDefs.front().compare("HAVE_FOO"), 0);
1518 }
1519
TEST(CommandLineTest,GroupingWithValue)1520 TEST(CommandLineTest, GroupingWithValue) {
1521 cl::ResetCommandLineParser();
1522
1523 StackOption<bool> OptF("f", cl::Grouping, cl::desc("Some flag"));
1524 StackOption<bool> OptB("b", cl::Grouping, cl::desc("Another flag"));
1525 StackOption<bool> OptD("d", cl::Grouping, cl::ValueDisallowed,
1526 cl::desc("ValueDisallowed option"));
1527 StackOption<std::string> OptV("v", cl::Grouping,
1528 cl::desc("ValueRequired option"));
1529 StackOption<std::string> OptO("o", cl::Grouping, cl::ValueOptional,
1530 cl::desc("ValueOptional option"));
1531
1532 // Should be possible to use an option which requires a value
1533 // at the end of a group.
1534 const char *args1[] = {"prog", "-fv", "val1"};
1535 EXPECT_TRUE(
1536 cl::ParseCommandLineOptions(3, args1, StringRef(), &llvm::nulls()));
1537 EXPECT_TRUE(OptF);
1538 EXPECT_STREQ("val1", OptV.c_str());
1539 OptV.clear();
1540 cl::ResetAllOptionOccurrences();
1541
1542 // Should not crash if it is accidentally used elsewhere in the group.
1543 const char *args2[] = {"prog", "-vf", "val2"};
1544 EXPECT_FALSE(
1545 cl::ParseCommandLineOptions(3, args2, StringRef(), &llvm::nulls()));
1546 OptV.clear();
1547 cl::ResetAllOptionOccurrences();
1548
1549 // Should allow the "opt=value" form at the end of the group
1550 const char *args3[] = {"prog", "-fv=val3"};
1551 EXPECT_TRUE(
1552 cl::ParseCommandLineOptions(2, args3, StringRef(), &llvm::nulls()));
1553 EXPECT_TRUE(OptF);
1554 EXPECT_STREQ("val3", OptV.c_str());
1555 OptV.clear();
1556 cl::ResetAllOptionOccurrences();
1557
1558 // Should allow assigning a value for a ValueOptional option
1559 // at the end of the group
1560 const char *args4[] = {"prog", "-fo=val4"};
1561 EXPECT_TRUE(
1562 cl::ParseCommandLineOptions(2, args4, StringRef(), &llvm::nulls()));
1563 EXPECT_TRUE(OptF);
1564 EXPECT_STREQ("val4", OptO.c_str());
1565 OptO.clear();
1566 cl::ResetAllOptionOccurrences();
1567
1568 // Should assign an empty value if a ValueOptional option is used elsewhere
1569 // in the group.
1570 const char *args5[] = {"prog", "-fob"};
1571 EXPECT_TRUE(
1572 cl::ParseCommandLineOptions(2, args5, StringRef(), &llvm::nulls()));
1573 EXPECT_TRUE(OptF);
1574 EXPECT_EQ(1, OptO.getNumOccurrences());
1575 EXPECT_EQ(1, OptB.getNumOccurrences());
1576 EXPECT_TRUE(OptO.empty());
1577 cl::ResetAllOptionOccurrences();
1578
1579 // Should not allow an assignment for a ValueDisallowed option.
1580 const char *args6[] = {"prog", "-fd=false"};
1581 EXPECT_FALSE(
1582 cl::ParseCommandLineOptions(2, args6, StringRef(), &llvm::nulls()));
1583 }
1584
TEST(CommandLineTest,GroupingAndPrefix)1585 TEST(CommandLineTest, GroupingAndPrefix) {
1586 cl::ResetCommandLineParser();
1587
1588 StackOption<bool> OptF("f", cl::Grouping, cl::desc("Some flag"));
1589 StackOption<bool> OptB("b", cl::Grouping, cl::desc("Another flag"));
1590 StackOption<std::string> OptP("p", cl::Prefix, cl::Grouping,
1591 cl::desc("Prefix and Grouping"));
1592 StackOption<std::string> OptA("a", cl::AlwaysPrefix, cl::Grouping,
1593 cl::desc("AlwaysPrefix and Grouping"));
1594
1595 // Should be possible to use a cl::Prefix option without grouping.
1596 const char *args1[] = {"prog", "-pval1"};
1597 EXPECT_TRUE(
1598 cl::ParseCommandLineOptions(2, args1, StringRef(), &llvm::nulls()));
1599 EXPECT_STREQ("val1", OptP.c_str());
1600 OptP.clear();
1601 cl::ResetAllOptionOccurrences();
1602
1603 // Should be possible to pass a value in a separate argument.
1604 const char *args2[] = {"prog", "-p", "val2"};
1605 EXPECT_TRUE(
1606 cl::ParseCommandLineOptions(3, args2, StringRef(), &llvm::nulls()));
1607 EXPECT_STREQ("val2", OptP.c_str());
1608 OptP.clear();
1609 cl::ResetAllOptionOccurrences();
1610
1611 // The "-opt=value" form should work, too.
1612 const char *args3[] = {"prog", "-p=val3"};
1613 EXPECT_TRUE(
1614 cl::ParseCommandLineOptions(2, args3, StringRef(), &llvm::nulls()));
1615 EXPECT_STREQ("val3", OptP.c_str());
1616 OptP.clear();
1617 cl::ResetAllOptionOccurrences();
1618
1619 // All three previous cases should work the same way if an option with both
1620 // cl::Prefix and cl::Grouping modifiers is used at the end of a group.
1621 const char *args4[] = {"prog", "-fpval4"};
1622 EXPECT_TRUE(
1623 cl::ParseCommandLineOptions(2, args4, StringRef(), &llvm::nulls()));
1624 EXPECT_TRUE(OptF);
1625 EXPECT_STREQ("val4", OptP.c_str());
1626 OptP.clear();
1627 cl::ResetAllOptionOccurrences();
1628
1629 const char *args5[] = {"prog", "-fp", "val5"};
1630 EXPECT_TRUE(
1631 cl::ParseCommandLineOptions(3, args5, StringRef(), &llvm::nulls()));
1632 EXPECT_TRUE(OptF);
1633 EXPECT_STREQ("val5", OptP.c_str());
1634 OptP.clear();
1635 cl::ResetAllOptionOccurrences();
1636
1637 const char *args6[] = {"prog", "-fp=val6"};
1638 EXPECT_TRUE(
1639 cl::ParseCommandLineOptions(2, args6, StringRef(), &llvm::nulls()));
1640 EXPECT_TRUE(OptF);
1641 EXPECT_STREQ("val6", OptP.c_str());
1642 OptP.clear();
1643 cl::ResetAllOptionOccurrences();
1644
1645 // Should assign a value even if the part after a cl::Prefix option is equal
1646 // to the name of another option.
1647 const char *args7[] = {"prog", "-fpb"};
1648 EXPECT_TRUE(
1649 cl::ParseCommandLineOptions(2, args7, StringRef(), &llvm::nulls()));
1650 EXPECT_TRUE(OptF);
1651 EXPECT_STREQ("b", OptP.c_str());
1652 EXPECT_FALSE(OptB);
1653 OptP.clear();
1654 cl::ResetAllOptionOccurrences();
1655
1656 // Should be possible to use a cl::AlwaysPrefix option without grouping.
1657 const char *args8[] = {"prog", "-aval8"};
1658 EXPECT_TRUE(
1659 cl::ParseCommandLineOptions(2, args8, StringRef(), &llvm::nulls()));
1660 EXPECT_STREQ("val8", OptA.c_str());
1661 OptA.clear();
1662 cl::ResetAllOptionOccurrences();
1663
1664 // Should not be possible to pass a value in a separate argument.
1665 const char *args9[] = {"prog", "-a", "val9"};
1666 EXPECT_FALSE(
1667 cl::ParseCommandLineOptions(3, args9, StringRef(), &llvm::nulls()));
1668 cl::ResetAllOptionOccurrences();
1669
1670 // With the "-opt=value" form, the "=" symbol should be preserved.
1671 const char *args10[] = {"prog", "-a=val10"};
1672 EXPECT_TRUE(
1673 cl::ParseCommandLineOptions(2, args10, StringRef(), &llvm::nulls()));
1674 EXPECT_STREQ("=val10", OptA.c_str());
1675 OptA.clear();
1676 cl::ResetAllOptionOccurrences();
1677
1678 // All three previous cases should work the same way if an option with both
1679 // cl::AlwaysPrefix and cl::Grouping modifiers is used at the end of a group.
1680 const char *args11[] = {"prog", "-faval11"};
1681 EXPECT_TRUE(
1682 cl::ParseCommandLineOptions(2, args11, StringRef(), &llvm::nulls()));
1683 EXPECT_TRUE(OptF);
1684 EXPECT_STREQ("val11", OptA.c_str());
1685 OptA.clear();
1686 cl::ResetAllOptionOccurrences();
1687
1688 const char *args12[] = {"prog", "-fa", "val12"};
1689 EXPECT_FALSE(
1690 cl::ParseCommandLineOptions(3, args12, StringRef(), &llvm::nulls()));
1691 cl::ResetAllOptionOccurrences();
1692
1693 const char *args13[] = {"prog", "-fa=val13"};
1694 EXPECT_TRUE(
1695 cl::ParseCommandLineOptions(2, args13, StringRef(), &llvm::nulls()));
1696 EXPECT_TRUE(OptF);
1697 EXPECT_STREQ("=val13", OptA.c_str());
1698 OptA.clear();
1699 cl::ResetAllOptionOccurrences();
1700
1701 // Should assign a value even if the part after a cl::AlwaysPrefix option
1702 // is equal to the name of another option.
1703 const char *args14[] = {"prog", "-fab"};
1704 EXPECT_TRUE(
1705 cl::ParseCommandLineOptions(2, args14, StringRef(), &llvm::nulls()));
1706 EXPECT_TRUE(OptF);
1707 EXPECT_STREQ("b", OptA.c_str());
1708 EXPECT_FALSE(OptB);
1709 OptA.clear();
1710 cl::ResetAllOptionOccurrences();
1711 }
1712
TEST(CommandLineTest,LongOptions)1713 TEST(CommandLineTest, LongOptions) {
1714 cl::ResetCommandLineParser();
1715
1716 StackOption<bool> OptA("a", cl::desc("Some flag"));
1717 StackOption<bool> OptBLong("long-flag", cl::desc("Some long flag"));
1718 StackOption<bool, cl::alias> OptB("b", cl::desc("Alias to --long-flag"),
1719 cl::aliasopt(OptBLong));
1720 StackOption<std::string> OptAB("ab", cl::desc("Another long option"));
1721
1722 std::string Errs;
1723 raw_string_ostream OS(Errs);
1724
1725 const char *args1[] = {"prog", "-a", "-ab", "val1"};
1726 const char *args2[] = {"prog", "-a", "--ab", "val1"};
1727 const char *args3[] = {"prog", "-ab", "--ab", "val1"};
1728
1729 //
1730 // The following tests treat `-` and `--` the same, and always match the
1731 // longest string.
1732 //
1733
1734 EXPECT_TRUE(
1735 cl::ParseCommandLineOptions(4, args1, StringRef(), &OS)); OS.flush();
1736 EXPECT_TRUE(OptA);
1737 EXPECT_FALSE(OptBLong);
1738 EXPECT_STREQ("val1", OptAB.c_str());
1739 EXPECT_TRUE(Errs.empty()); Errs.clear();
1740 cl::ResetAllOptionOccurrences();
1741
1742 EXPECT_TRUE(
1743 cl::ParseCommandLineOptions(4, args2, StringRef(), &OS)); OS.flush();
1744 EXPECT_TRUE(OptA);
1745 EXPECT_FALSE(OptBLong);
1746 EXPECT_STREQ("val1", OptAB.c_str());
1747 EXPECT_TRUE(Errs.empty()); Errs.clear();
1748 cl::ResetAllOptionOccurrences();
1749
1750 // Fails because `-ab` and `--ab` are treated the same and appear more than
1751 // once. Also, `val1` is unexpected.
1752 EXPECT_FALSE(
1753 cl::ParseCommandLineOptions(4, args3, StringRef(), &OS)); OS.flush();
1754 outs()<< Errs << "\n";
1755 EXPECT_FALSE(Errs.empty()); Errs.clear();
1756 cl::ResetAllOptionOccurrences();
1757
1758 //
1759 // The following tests treat `-` and `--` differently, with `-` for short, and
1760 // `--` for long options.
1761 //
1762
1763 // Fails because `-ab` is treated as `-a -b`, so `-a` is seen twice, and
1764 // `val1` is unexpected.
1765 EXPECT_FALSE(cl::ParseCommandLineOptions(4, args1, StringRef(),
1766 &OS, nullptr, true)); OS.flush();
1767 EXPECT_FALSE(Errs.empty()); Errs.clear();
1768 cl::ResetAllOptionOccurrences();
1769
1770 // Works because `-a` is treated differently than `--ab`.
1771 EXPECT_TRUE(cl::ParseCommandLineOptions(4, args2, StringRef(),
1772 &OS, nullptr, true)); OS.flush();
1773 EXPECT_TRUE(Errs.empty()); Errs.clear();
1774 cl::ResetAllOptionOccurrences();
1775
1776 // Works because `-ab` is treated as `-a -b`, and `--ab` is a long option.
1777 EXPECT_TRUE(cl::ParseCommandLineOptions(4, args3, StringRef(),
1778 &OS, nullptr, true));
1779 EXPECT_TRUE(OptA);
1780 EXPECT_TRUE(OptBLong);
1781 EXPECT_STREQ("val1", OptAB.c_str());
1782 OS.flush();
1783 EXPECT_TRUE(Errs.empty()); Errs.clear();
1784 cl::ResetAllOptionOccurrences();
1785 }
1786
TEST(CommandLineTest,OptionErrorMessage)1787 TEST(CommandLineTest, OptionErrorMessage) {
1788 // When there is an error, we expect some error message like:
1789 // prog: for the -a option: [...]
1790 //
1791 // Test whether the "for the -a option"-part is correctly formatted.
1792 cl::ResetCommandLineParser();
1793
1794 StackOption<bool> OptA("a", cl::desc("Some option"));
1795 StackOption<bool> OptLong("long", cl::desc("Some long option"));
1796
1797 std::string Errs;
1798 raw_string_ostream OS(Errs);
1799
1800 OptA.error("custom error", OS);
1801 OS.flush();
1802 EXPECT_NE(Errs.find("for the -a option:"), std::string::npos);
1803 Errs.clear();
1804
1805 OptLong.error("custom error", OS);
1806 OS.flush();
1807 EXPECT_NE(Errs.find("for the --long option:"), std::string::npos);
1808 Errs.clear();
1809
1810 cl::ResetAllOptionOccurrences();
1811 }
1812
TEST(CommandLineTest,OptionErrorMessageSuggest)1813 TEST(CommandLineTest, OptionErrorMessageSuggest) {
1814 // When there is an error, and the edit-distance is not very large,
1815 // we expect some error message like:
1816 // prog: did you mean '--option'?
1817 //
1818 // Test whether this message is well-formatted.
1819 cl::ResetCommandLineParser();
1820
1821 StackOption<bool> OptLong("aluminium", cl::desc("Some long option"));
1822
1823 const char *args[] = {"prog", "--aluminum"};
1824
1825 std::string Errs;
1826 raw_string_ostream OS(Errs);
1827
1828 EXPECT_FALSE(cl::ParseCommandLineOptions(2, args, StringRef(), &OS));
1829 OS.flush();
1830 EXPECT_NE(Errs.find("prog: Did you mean '--aluminium'?\n"),
1831 std::string::npos);
1832 Errs.clear();
1833
1834 cl::ResetAllOptionOccurrences();
1835 }
1836
TEST(CommandLineTest,OptionErrorMessageSuggestNoHidden)1837 TEST(CommandLineTest, OptionErrorMessageSuggestNoHidden) {
1838 // We expect that 'really hidden' option do not show up in option
1839 // suggestions.
1840 cl::ResetCommandLineParser();
1841
1842 StackOption<bool> OptLong("aluminium", cl::desc("Some long option"));
1843 StackOption<bool> OptLong2("aluminum", cl::desc("Bad option"),
1844 cl::ReallyHidden);
1845
1846 const char *args[] = {"prog", "--alumnum"};
1847
1848 std::string Errs;
1849 raw_string_ostream OS(Errs);
1850
1851 EXPECT_FALSE(cl::ParseCommandLineOptions(2, args, StringRef(), &OS));
1852 OS.flush();
1853 EXPECT_NE(Errs.find("prog: Did you mean '--aluminium'?\n"),
1854 std::string::npos);
1855 Errs.clear();
1856
1857 cl::ResetAllOptionOccurrences();
1858 }
1859
TEST(CommandLineTest,Callback)1860 TEST(CommandLineTest, Callback) {
1861 cl::ResetCommandLineParser();
1862
1863 StackOption<bool> OptA("a", cl::desc("option a"));
1864 StackOption<bool> OptB(
1865 "b", cl::desc("option b -- This option turns on option a"),
1866 cl::callback([&](const bool &) { OptA = true; }));
1867 StackOption<bool> OptC(
1868 "c", cl::desc("option c -- This option turns on options a and b"),
1869 cl::callback([&](const bool &) { OptB = true; }));
1870 StackOption<std::string, cl::list<std::string>> List(
1871 "list",
1872 cl::desc("option list -- This option turns on options a, b, and c when "
1873 "'foo' is included in list"),
1874 cl::CommaSeparated,
1875 cl::callback([&](const std::string &Str) {
1876 if (Str == "foo")
1877 OptC = true;
1878 }));
1879
1880 const char *args1[] = {"prog", "-a"};
1881 EXPECT_TRUE(cl::ParseCommandLineOptions(2, args1));
1882 EXPECT_TRUE(OptA);
1883 EXPECT_FALSE(OptB);
1884 EXPECT_FALSE(OptC);
1885 EXPECT_EQ(List.size(), 0u);
1886 cl::ResetAllOptionOccurrences();
1887
1888 const char *args2[] = {"prog", "-b"};
1889 EXPECT_TRUE(cl::ParseCommandLineOptions(2, args2));
1890 EXPECT_TRUE(OptA);
1891 EXPECT_TRUE(OptB);
1892 EXPECT_FALSE(OptC);
1893 EXPECT_EQ(List.size(), 0u);
1894 cl::ResetAllOptionOccurrences();
1895
1896 const char *args3[] = {"prog", "-c"};
1897 EXPECT_TRUE(cl::ParseCommandLineOptions(2, args3));
1898 EXPECT_TRUE(OptA);
1899 EXPECT_TRUE(OptB);
1900 EXPECT_TRUE(OptC);
1901 EXPECT_EQ(List.size(), 0u);
1902 cl::ResetAllOptionOccurrences();
1903
1904 const char *args4[] = {"prog", "--list=foo,bar"};
1905 EXPECT_TRUE(cl::ParseCommandLineOptions(2, args4));
1906 EXPECT_TRUE(OptA);
1907 EXPECT_TRUE(OptB);
1908 EXPECT_TRUE(OptC);
1909 EXPECT_EQ(List.size(), 2u);
1910 cl::ResetAllOptionOccurrences();
1911
1912 const char *args5[] = {"prog", "--list=bar"};
1913 EXPECT_TRUE(cl::ParseCommandLineOptions(2, args5));
1914 EXPECT_FALSE(OptA);
1915 EXPECT_FALSE(OptB);
1916 EXPECT_FALSE(OptC);
1917 EXPECT_EQ(List.size(), 1u);
1918
1919 cl::ResetAllOptionOccurrences();
1920 }
1921
1922 enum Enum { Val1, Val2 };
1923 static cl::bits<Enum> ExampleBits(
1924 cl::desc("An example cl::bits to ensure it compiles"),
1925 cl::values(
1926 clEnumValN(Val1, "bits-val1", "The Val1 value"),
1927 clEnumValN(Val1, "bits-val2", "The Val2 value")));
1928
TEST(CommandLineTest,ConsumeAfterOnePositional)1929 TEST(CommandLineTest, ConsumeAfterOnePositional) {
1930 cl::ResetCommandLineParser();
1931
1932 // input [args]
1933 StackOption<std::string, cl::opt<std::string>> Input(cl::Positional,
1934 cl::Required);
1935 StackOption<std::string, cl::list<std::string>> ExtraArgs(cl::ConsumeAfter);
1936
1937 const char *Args[] = {"prog", "input", "arg1", "arg2"};
1938
1939 std::string Errs;
1940 raw_string_ostream OS(Errs);
1941 EXPECT_TRUE(cl::ParseCommandLineOptions(4, Args, StringRef(), &OS));
1942 OS.flush();
1943 EXPECT_EQ("input", Input);
1944 EXPECT_EQ(ExtraArgs.size(), 2u);
1945 EXPECT_EQ(ExtraArgs[0], "arg1");
1946 EXPECT_EQ(ExtraArgs[1], "arg2");
1947 EXPECT_TRUE(Errs.empty());
1948 }
1949
TEST(CommandLineTest,ConsumeAfterTwoPositionals)1950 TEST(CommandLineTest, ConsumeAfterTwoPositionals) {
1951 cl::ResetCommandLineParser();
1952
1953 // input1 input2 [args]
1954 StackOption<std::string, cl::opt<std::string>> Input1(cl::Positional,
1955 cl::Required);
1956 StackOption<std::string, cl::opt<std::string>> Input2(cl::Positional,
1957 cl::Required);
1958 StackOption<std::string, cl::list<std::string>> ExtraArgs(cl::ConsumeAfter);
1959
1960 const char *Args[] = {"prog", "input1", "input2", "arg1", "arg2"};
1961
1962 std::string Errs;
1963 raw_string_ostream OS(Errs);
1964 EXPECT_TRUE(cl::ParseCommandLineOptions(5, Args, StringRef(), &OS));
1965 OS.flush();
1966 EXPECT_EQ("input1", Input1);
1967 EXPECT_EQ("input2", Input2);
1968 EXPECT_EQ(ExtraArgs.size(), 2u);
1969 EXPECT_EQ(ExtraArgs[0], "arg1");
1970 EXPECT_EQ(ExtraArgs[1], "arg2");
1971 EXPECT_TRUE(Errs.empty());
1972 }
1973
TEST(CommandLineTest,ResetAllOptionOccurrences)1974 TEST(CommandLineTest, ResetAllOptionOccurrences) {
1975 cl::ResetCommandLineParser();
1976
1977 // -option -str -enableA -enableC [sink] input [args]
1978 StackOption<bool> Option("option");
1979 StackOption<std::string> Str("str");
1980 enum Vals { ValA, ValB, ValC };
1981 StackOption<Vals, cl::bits<Vals>> Bits(
1982 cl::values(clEnumValN(ValA, "enableA", "Enable A"),
1983 clEnumValN(ValB, "enableB", "Enable B"),
1984 clEnumValN(ValC, "enableC", "Enable C")));
1985 StackOption<std::string, cl::list<std::string>> Sink(cl::Sink);
1986 StackOption<std::string> Input(cl::Positional);
1987 StackOption<std::string, cl::list<std::string>> ExtraArgs(cl::ConsumeAfter);
1988
1989 const char *Args[] = {"prog", "-option", "-str=STR", "-enableA",
1990 "-enableC", "-unknown", "input", "-arg"};
1991
1992 std::string Errs;
1993 raw_string_ostream OS(Errs);
1994 EXPECT_TRUE(cl::ParseCommandLineOptions(8, Args, StringRef(), &OS));
1995 EXPECT_TRUE(OS.str().empty());
1996
1997 EXPECT_TRUE(Option);
1998 EXPECT_EQ("STR", Str);
1999 EXPECT_EQ((1u << ValA) | (1u << ValC), Bits.getBits());
2000 EXPECT_EQ(1u, Sink.size());
2001 EXPECT_EQ("-unknown", Sink[0]);
2002 EXPECT_EQ("input", Input);
2003 EXPECT_EQ(1u, ExtraArgs.size());
2004 EXPECT_EQ("-arg", ExtraArgs[0]);
2005
2006 cl::ResetAllOptionOccurrences();
2007 EXPECT_FALSE(Option);
2008 EXPECT_EQ("", Str);
2009 EXPECT_EQ(0u, Bits.getBits());
2010 EXPECT_EQ(0u, Sink.size());
2011 EXPECT_EQ(0, Input.getNumOccurrences());
2012 EXPECT_EQ(0u, ExtraArgs.size());
2013 }
2014
TEST(CommandLineTest,DefaultValue)2015 TEST(CommandLineTest, DefaultValue) {
2016 cl::ResetCommandLineParser();
2017
2018 StackOption<bool> BoolOption("bool-option");
2019 StackOption<std::string> StrOption("str-option");
2020 StackOption<bool> BoolInitOption("bool-init-option", cl::init(true));
2021 StackOption<std::string> StrInitOption("str-init-option",
2022 cl::init("str-default-value"));
2023
2024 const char *Args[] = {"prog"}; // no options
2025
2026 std::string Errs;
2027 raw_string_ostream OS(Errs);
2028 EXPECT_TRUE(cl::ParseCommandLineOptions(1, Args, StringRef(), &OS));
2029 EXPECT_TRUE(OS.str().empty());
2030
2031 EXPECT_TRUE(!BoolOption);
2032 EXPECT_FALSE(BoolOption.Default.hasValue());
2033 EXPECT_EQ(0, BoolOption.getNumOccurrences());
2034
2035 EXPECT_EQ("", StrOption);
2036 EXPECT_FALSE(StrOption.Default.hasValue());
2037 EXPECT_EQ(0, StrOption.getNumOccurrences());
2038
2039 EXPECT_TRUE(BoolInitOption);
2040 EXPECT_TRUE(BoolInitOption.Default.hasValue());
2041 EXPECT_EQ(0, BoolInitOption.getNumOccurrences());
2042
2043 EXPECT_EQ("str-default-value", StrInitOption);
2044 EXPECT_TRUE(StrInitOption.Default.hasValue());
2045 EXPECT_EQ(0, StrInitOption.getNumOccurrences());
2046
2047 const char *Args2[] = {"prog", "-bool-option", "-str-option=str-value",
2048 "-bool-init-option=0",
2049 "-str-init-option=str-init-value"};
2050
2051 EXPECT_TRUE(cl::ParseCommandLineOptions(5, Args2, StringRef(), &OS));
2052 EXPECT_TRUE(OS.str().empty());
2053
2054 EXPECT_TRUE(BoolOption);
2055 EXPECT_FALSE(BoolOption.Default.hasValue());
2056 EXPECT_EQ(1, BoolOption.getNumOccurrences());
2057
2058 EXPECT_EQ("str-value", StrOption);
2059 EXPECT_FALSE(StrOption.Default.hasValue());
2060 EXPECT_EQ(1, StrOption.getNumOccurrences());
2061
2062 EXPECT_FALSE(BoolInitOption);
2063 EXPECT_TRUE(BoolInitOption.Default.hasValue());
2064 EXPECT_EQ(1, BoolInitOption.getNumOccurrences());
2065
2066 EXPECT_EQ("str-init-value", StrInitOption);
2067 EXPECT_TRUE(StrInitOption.Default.hasValue());
2068 EXPECT_EQ(1, StrInitOption.getNumOccurrences());
2069 }
2070
2071 } // anonymous namespace
2072