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