Mercurial > hg > CbC > CbC_llvm
comparison unittests/Support/CommandLineTest.cpp @ 148:63bd29f05246
merged
author | Shinji KONO <kono@ie.u-ryukyu.ac.jp> |
---|---|
date | Wed, 14 Aug 2019 19:46:37 +0900 |
parents | c2174574ed3a |
children |
comparison
equal
deleted
inserted
replaced
146:3fc4d5c3e21e | 148:63bd29f05246 |
---|---|
1 //===- llvm/unittest/Support/CommandLineTest.cpp - CommandLine tests ------===// | 1 //===- llvm/unittest/Support/CommandLineTest.cpp - CommandLine tests ------===// |
2 // | 2 // |
3 // The LLVM Compiler Infrastructure | 3 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. |
4 // | 4 // See https://llvm.org/LICENSE.txt for license information. |
5 // This file is distributed under the University of Illinois Open Source | 5 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception |
6 // License. See LICENSE.TXT for details. | |
7 // | 6 // |
8 //===----------------------------------------------------------------------===// | 7 //===----------------------------------------------------------------------===// |
9 | 8 |
10 #include "llvm/Support/CommandLine.h" | 9 #include "llvm/Support/CommandLine.h" |
11 #include "llvm/ADT/STLExtras.h" | 10 #include "llvm/ADT/STLExtras.h" |
12 #include "llvm/ADT/SmallString.h" | 11 #include "llvm/ADT/SmallString.h" |
12 #include "llvm/ADT/Triple.h" | |
13 #include "llvm/Config/config.h" | 13 #include "llvm/Config/config.h" |
14 #include "llvm/Support/FileSystem.h" | 14 #include "llvm/Support/FileSystem.h" |
15 #include "llvm/Support/InitLLVM.h" | |
16 #include "llvm/Support/MemoryBuffer.h" | |
15 #include "llvm/Support/Path.h" | 17 #include "llvm/Support/Path.h" |
16 #include "llvm/Support/Program.h" | 18 #include "llvm/Support/Program.h" |
17 #include "llvm/Support/StringSaver.h" | 19 #include "llvm/Support/StringSaver.h" |
18 #include "gtest/gtest.h" | 20 #include "gtest/gtest.h" |
19 #include <fstream> | 21 #include <fstream> |
48 | 50 |
49 private: | 51 private: |
50 const char *const name; | 52 const char *const name; |
51 }; | 53 }; |
52 | 54 |
53 template <typename T> | 55 template <typename T, typename Base = cl::opt<T>> |
54 class StackOption : public cl::opt<T> { | 56 class StackOption : public Base { |
55 typedef cl::opt<T> Base; | |
56 public: | 57 public: |
57 // One option... | 58 template <class... Ts> |
58 template<class M0t> | 59 explicit StackOption(Ts &&... Ms) : Base(std::forward<Ts>(Ms)...) {} |
59 explicit StackOption(const M0t &M0) : Base(M0) {} | |
60 | |
61 // Two options... | |
62 template<class M0t, class M1t> | |
63 StackOption(const M0t &M0, const M1t &M1) : Base(M0, M1) {} | |
64 | |
65 // Three options... | |
66 template<class M0t, class M1t, class M2t> | |
67 StackOption(const M0t &M0, const M1t &M1, const M2t &M2) : Base(M0, M1, M2) {} | |
68 | |
69 // Four options... | |
70 template<class M0t, class M1t, class M2t, class M3t> | |
71 StackOption(const M0t &M0, const M1t &M1, const M2t &M2, const M3t &M3) | |
72 : Base(M0, M1, M2, M3) {} | |
73 | 60 |
74 ~StackOption() override { this->removeArgument(); } | 61 ~StackOption() override { this->removeArgument(); } |
75 | 62 |
76 template <class DT> StackOption<T> &operator=(const DT &V) { | 63 template <class DT> StackOption<T> &operator=(const DT &V) { |
77 this->setValue(V); | 64 this->setValue(V); |
93 | 80 |
94 cl::OptionCategory TestCategory("Test Options", "Description"); | 81 cl::OptionCategory TestCategory("Test Options", "Description"); |
95 TEST(CommandLineTest, ModifyExisitingOption) { | 82 TEST(CommandLineTest, ModifyExisitingOption) { |
96 StackOption<int> TestOption("test-option", cl::desc("old description")); | 83 StackOption<int> TestOption("test-option", cl::desc("old description")); |
97 | 84 |
98 const char Description[] = "New description"; | 85 static const char Description[] = "New description"; |
99 const char ArgString[] = "new-test-option"; | 86 static const char ArgString[] = "new-test-option"; |
100 const char ValueString[] = "Integer"; | 87 static const char ValueString[] = "Integer"; |
101 | 88 |
102 StringMap<cl::Option *> &Map = | 89 StringMap<cl::Option *> &Map = |
103 cl::getRegisteredOptions(*cl::TopLevelSubCommand); | 90 cl::getRegisteredOptions(*cl::TopLevelSubCommand); |
104 | 91 |
105 ASSERT_TRUE(Map.count("test-option") == 1) << | 92 ASSERT_TRUE(Map.count("test-option") == 1) << |
106 "Could not find option in map."; | 93 "Could not find option in map."; |
107 | 94 |
108 cl::Option *Retrieved = Map["test-option"]; | 95 cl::Option *Retrieved = Map["test-option"]; |
109 ASSERT_EQ(&TestOption, Retrieved) << "Retrieved wrong option."; | 96 ASSERT_EQ(&TestOption, Retrieved) << "Retrieved wrong option."; |
110 | 97 |
111 ASSERT_EQ(&cl::GeneralCategory,Retrieved->Category) << | 98 ASSERT_NE(Retrieved->Categories.end(), |
112 "Incorrect default option category."; | 99 find_if(Retrieved->Categories, |
113 | 100 [&](const llvm::cl::OptionCategory *Cat) { |
114 Retrieved->setCategory(TestCategory); | 101 return Cat == &cl::GeneralCategory; |
115 ASSERT_EQ(&TestCategory,Retrieved->Category) << | 102 })) |
116 "Failed to modify option's option category."; | 103 << "Incorrect default option category."; |
104 | |
105 Retrieved->addCategory(TestCategory); | |
106 ASSERT_NE(Retrieved->Categories.end(), | |
107 find_if(Retrieved->Categories, | |
108 [&](const llvm::cl::OptionCategory *Cat) { | |
109 return Cat == &TestCategory; | |
110 })) | |
111 << "Failed to modify option's option category."; | |
117 | 112 |
118 Retrieved->setDescription(Description); | 113 Retrieved->setDescription(Description); |
119 ASSERT_STREQ(Retrieved->HelpStr.data(), Description) | 114 ASSERT_STREQ(Retrieved->HelpStr.data(), Description) |
120 << "Changing option description failed."; | 115 << "Changing option description failed."; |
121 | 116 |
163 #endif // SKIP_ENVIRONMENT_TESTS | 158 #endif // SKIP_ENVIRONMENT_TESTS |
164 | 159 |
165 TEST(CommandLineTest, UseOptionCategory) { | 160 TEST(CommandLineTest, UseOptionCategory) { |
166 StackOption<int> TestOption2("test-option", cl::cat(TestCategory)); | 161 StackOption<int> TestOption2("test-option", cl::cat(TestCategory)); |
167 | 162 |
168 ASSERT_EQ(&TestCategory,TestOption2.Category) << "Failed to assign Option " | 163 ASSERT_NE(TestOption2.Categories.end(), |
169 "Category."; | 164 find_if(TestOption2.Categories, |
165 [&](const llvm::cl::OptionCategory *Cat) { | |
166 return Cat == &TestCategory; | |
167 })) | |
168 << "Failed to assign Option Category."; | |
169 } | |
170 | |
171 TEST(CommandLineTest, UseMultipleCategories) { | |
172 StackOption<int> TestOption2("test-option2", cl::cat(TestCategory), | |
173 cl::cat(cl::GeneralCategory), | |
174 cl::cat(cl::GeneralCategory)); | |
175 | |
176 // Make sure cl::GeneralCategory wasn't added twice. | |
177 ASSERT_EQ(TestOption2.Categories.size(), 2U); | |
178 | |
179 ASSERT_NE(TestOption2.Categories.end(), | |
180 find_if(TestOption2.Categories, | |
181 [&](const llvm::cl::OptionCategory *Cat) { | |
182 return Cat == &TestCategory; | |
183 })) | |
184 << "Failed to assign Option Category."; | |
185 ASSERT_NE(TestOption2.Categories.end(), | |
186 find_if(TestOption2.Categories, | |
187 [&](const llvm::cl::OptionCategory *Cat) { | |
188 return Cat == &cl::GeneralCategory; | |
189 })) | |
190 << "Failed to assign General Category."; | |
191 | |
192 cl::OptionCategory AnotherCategory("Additional test Options", "Description"); | |
193 StackOption<int> TestOption("test-option", cl::cat(TestCategory), | |
194 cl::cat(AnotherCategory)); | |
195 ASSERT_EQ(TestOption.Categories.end(), | |
196 find_if(TestOption.Categories, | |
197 [&](const llvm::cl::OptionCategory *Cat) { | |
198 return Cat == &cl::GeneralCategory; | |
199 })) | |
200 << "Failed to remove General Category."; | |
201 ASSERT_NE(TestOption.Categories.end(), | |
202 find_if(TestOption.Categories, | |
203 [&](const llvm::cl::OptionCategory *Cat) { | |
204 return Cat == &TestCategory; | |
205 })) | |
206 << "Failed to assign Option Category."; | |
207 ASSERT_NE(TestOption.Categories.end(), | |
208 find_if(TestOption.Categories, | |
209 [&](const llvm::cl::OptionCategory *Cat) { | |
210 return Cat == &AnotherCategory; | |
211 })) | |
212 << "Failed to assign Another Category."; | |
170 } | 213 } |
171 | 214 |
172 typedef void ParserFunction(StringRef Source, StringSaver &Saver, | 215 typedef void ParserFunction(StringRef Source, StringSaver &Saver, |
173 SmallVectorImpl<const char *> &NewArgv, | 216 SmallVectorImpl<const char *> &NewArgv, |
174 bool MarkEOLs); | 217 bool MarkEOLs); |
196 "-DFOO=bar()", "foobarbaz", "C:\\src\\foo.cpp", "C:srcfoo.cpp"}; | 239 "-DFOO=bar()", "foobarbaz", "C:\\src\\foo.cpp", "C:srcfoo.cpp"}; |
197 testCommandLineTokenizer(cl::TokenizeGNUCommandLine, Input, Output, | 240 testCommandLineTokenizer(cl::TokenizeGNUCommandLine, Input, Output, |
198 array_lengthof(Output)); | 241 array_lengthof(Output)); |
199 } | 242 } |
200 | 243 |
201 TEST(CommandLineTest, TokenizeWindowsCommandLine) { | 244 TEST(CommandLineTest, TokenizeWindowsCommandLine1) { |
202 const char Input[] = "a\\b c\\\\d e\\\\\"f g\" h\\\"i j\\\\\\\"k \"lmn\" o pqr " | 245 const char Input[] = "a\\b c\\\\d e\\\\\"f g\" h\\\"i j\\\\\\\"k \"lmn\" o pqr " |
203 "\"st \\\"u\" \\v"; | 246 "\"st \\\"u\" \\v"; |
204 const char *const Output[] = { "a\\b", "c\\\\d", "e\\f g", "h\"i", "j\\\"k", | 247 const char *const Output[] = { "a\\b", "c\\\\d", "e\\f g", "h\"i", "j\\\"k", |
205 "lmn", "o", "pqr", "st \"u", "\\v" }; | 248 "lmn", "o", "pqr", "st \"u", "\\v" }; |
249 testCommandLineTokenizer(cl::TokenizeWindowsCommandLine, Input, Output, | |
250 array_lengthof(Output)); | |
251 } | |
252 | |
253 TEST(CommandLineTest, TokenizeWindowsCommandLine2) { | |
254 const char Input[] = "clang -c -DFOO=\"\"\"ABC\"\"\" x.cpp"; | |
255 const char *const Output[] = { "clang", "-c", "-DFOO=\"ABC\"", "x.cpp"}; | |
206 testCommandLineTokenizer(cl::TokenizeWindowsCommandLine, Input, Output, | 256 testCommandLineTokenizer(cl::TokenizeWindowsCommandLine, Input, Output, |
207 array_lengthof(Output)); | 257 array_lengthof(Output)); |
208 } | 258 } |
209 | 259 |
210 TEST(CommandLineTest, TokenizeConfigFile1) { | 260 TEST(CommandLineTest, TokenizeConfigFile1) { |
624 EXPECT_EQ("sc2", S->getName()); | 674 EXPECT_EQ("sc2", S->getName()); |
625 } | 675 } |
626 } | 676 } |
627 } | 677 } |
628 | 678 |
679 TEST(CommandLineTest, DefaultOptions) { | |
680 cl::ResetCommandLineParser(); | |
681 | |
682 StackOption<std::string> Bar("bar", cl::sub(*cl::AllSubCommands), | |
683 cl::DefaultOption); | |
684 StackOption<std::string, cl::alias> Bar_Alias( | |
685 "b", cl::desc("Alias for -bar"), cl::aliasopt(Bar), cl::DefaultOption); | |
686 | |
687 StackOption<bool> Foo("foo", cl::init(false), cl::sub(*cl::AllSubCommands), | |
688 cl::DefaultOption); | |
689 StackOption<bool, cl::alias> Foo_Alias("f", cl::desc("Alias for -foo"), | |
690 cl::aliasopt(Foo), cl::DefaultOption); | |
691 | |
692 StackSubCommand SC1("sc1", "First Subcommand"); | |
693 // Override "-b" and change type in sc1 SubCommand. | |
694 StackOption<bool> SC1_B("b", cl::sub(SC1), cl::init(false)); | |
695 StackSubCommand SC2("sc2", "Second subcommand"); | |
696 // Override "-foo" and change type in sc2 SubCommand. Note that this does not | |
697 // affect "-f" alias, which continues to work correctly. | |
698 StackOption<std::string> SC2_Foo("foo", cl::sub(SC2)); | |
699 | |
700 const char *args0[] = {"prog", "-b", "args0 bar string", "-f"}; | |
701 EXPECT_TRUE(cl::ParseCommandLineOptions(sizeof(args0) / sizeof(char *), args0, | |
702 StringRef(), &llvm::nulls())); | |
703 EXPECT_TRUE(Bar == "args0 bar string"); | |
704 EXPECT_TRUE(Foo); | |
705 EXPECT_FALSE(SC1_B); | |
706 EXPECT_TRUE(SC2_Foo.empty()); | |
707 | |
708 cl::ResetAllOptionOccurrences(); | |
709 | |
710 const char *args1[] = {"prog", "sc1", "-b", "-bar", "args1 bar string", "-f"}; | |
711 EXPECT_TRUE(cl::ParseCommandLineOptions(sizeof(args1) / sizeof(char *), args1, | |
712 StringRef(), &llvm::nulls())); | |
713 EXPECT_TRUE(Bar == "args1 bar string"); | |
714 EXPECT_TRUE(Foo); | |
715 EXPECT_TRUE(SC1_B); | |
716 EXPECT_TRUE(SC2_Foo.empty()); | |
717 for (auto *S : cl::getRegisteredSubcommands()) { | |
718 if (*S) { | |
719 EXPECT_EQ("sc1", S->getName()); | |
720 } | |
721 } | |
722 | |
723 cl::ResetAllOptionOccurrences(); | |
724 | |
725 const char *args2[] = {"prog", "sc2", "-b", "args2 bar string", | |
726 "-f", "-foo", "foo string"}; | |
727 EXPECT_TRUE(cl::ParseCommandLineOptions(sizeof(args2) / sizeof(char *), args2, | |
728 StringRef(), &llvm::nulls())); | |
729 EXPECT_TRUE(Bar == "args2 bar string"); | |
730 EXPECT_TRUE(Foo); | |
731 EXPECT_FALSE(SC1_B); | |
732 EXPECT_TRUE(SC2_Foo == "foo string"); | |
733 for (auto *S : cl::getRegisteredSubcommands()) { | |
734 if (*S) { | |
735 EXPECT_EQ("sc2", S->getName()); | |
736 } | |
737 } | |
738 cl::ResetCommandLineParser(); | |
739 } | |
740 | |
629 TEST(CommandLineTest, ArgumentLimit) { | 741 TEST(CommandLineTest, ArgumentLimit) { |
630 std::string args(32 * 4096, 'a'); | 742 std::string args(32 * 4096, 'a'); |
631 EXPECT_FALSE(llvm::sys::commandLineFitsWithinSystemLimits("cl", args.data())); | 743 EXPECT_FALSE(llvm::sys::commandLineFitsWithinSystemLimits("cl", args.data())); |
744 } | |
745 | |
746 TEST(CommandLineTest, ResponseFileWindows) { | |
747 if (!Triple(sys::getProcessTriple()).isOSWindows()) | |
748 return; | |
749 | |
750 StackOption<std::string, cl::list<std::string>> InputFilenames( | |
751 cl::Positional, cl::desc("<input files>"), cl::ZeroOrMore); | |
752 StackOption<bool> TopLevelOpt("top-level", cl::init(false)); | |
753 | |
754 // Create response file. | |
755 int FileDescriptor; | |
756 SmallString<64> TempPath; | |
757 std::error_code EC = | |
758 llvm::sys::fs::createTemporaryFile("resp-", ".txt", FileDescriptor, TempPath); | |
759 EXPECT_TRUE(!EC); | |
760 | |
761 std::ofstream RspFile(TempPath.c_str()); | |
762 EXPECT_TRUE(RspFile.is_open()); | |
763 RspFile << "-top-level\npath\\dir\\file1\npath/dir/file2"; | |
764 RspFile.close(); | |
765 | |
766 llvm::SmallString<128> RspOpt; | |
767 RspOpt.append(1, '@'); | |
768 RspOpt.append(TempPath.c_str()); | |
769 const char *args[] = {"prog", RspOpt.c_str()}; | |
770 EXPECT_FALSE(TopLevelOpt); | |
771 EXPECT_TRUE( | |
772 cl::ParseCommandLineOptions(2, args, StringRef(), &llvm::nulls())); | |
773 EXPECT_TRUE(TopLevelOpt); | |
774 EXPECT_TRUE(InputFilenames[0] == "path\\dir\\file1"); | |
775 EXPECT_TRUE(InputFilenames[1] == "path/dir/file2"); | |
776 | |
777 llvm::sys::fs::remove(TempPath.c_str()); | |
632 } | 778 } |
633 | 779 |
634 TEST(CommandLineTest, ResponseFiles) { | 780 TEST(CommandLineTest, ResponseFiles) { |
635 llvm::SmallString<128> TestDir; | 781 llvm::SmallString<128> TestDir; |
636 std::error_code EC = | 782 std::error_code EC = |
642 llvm::sys::path::append(IncludedFileName, TestDir, "resp1"); | 788 llvm::sys::path::append(IncludedFileName, TestDir, "resp1"); |
643 std::ofstream IncludedFile(IncludedFileName.c_str()); | 789 std::ofstream IncludedFile(IncludedFileName.c_str()); |
644 EXPECT_TRUE(IncludedFile.is_open()); | 790 EXPECT_TRUE(IncludedFile.is_open()); |
645 IncludedFile << "-option_1 -option_2\n" | 791 IncludedFile << "-option_1 -option_2\n" |
646 "@incdir/resp2\n" | 792 "@incdir/resp2\n" |
647 "-option_3=abcd\n"; | 793 "-option_3=abcd\n" |
794 "@incdir/resp3\n" | |
795 "-option_4=efjk\n"; | |
648 IncludedFile.close(); | 796 IncludedFile.close(); |
649 | 797 |
650 // Directory for included file. | 798 // Directory for included file. |
651 llvm::SmallString<128> IncDir; | 799 llvm::SmallString<128> IncDir; |
652 llvm::sys::path::append(IncDir, TestDir, "incdir"); | 800 llvm::sys::path::append(IncDir, TestDir, "incdir"); |
660 EXPECT_TRUE(IncludedFile2.is_open()); | 808 EXPECT_TRUE(IncludedFile2.is_open()); |
661 IncludedFile2 << "-option_21 -option_22\n"; | 809 IncludedFile2 << "-option_21 -option_22\n"; |
662 IncludedFile2 << "-option_23=abcd\n"; | 810 IncludedFile2 << "-option_23=abcd\n"; |
663 IncludedFile2.close(); | 811 IncludedFile2.close(); |
664 | 812 |
813 // Create second included response file of second level. | |
814 llvm::SmallString<128> IncludedFileName3; | |
815 llvm::sys::path::append(IncludedFileName3, IncDir, "resp3"); | |
816 std::ofstream IncludedFile3(IncludedFileName3.c_str()); | |
817 EXPECT_TRUE(IncludedFile3.is_open()); | |
818 IncludedFile3 << "-option_31 -option_32\n"; | |
819 IncludedFile3 << "-option_33=abcd\n"; | |
820 IncludedFile3.close(); | |
821 | |
665 // Prepare 'file' with reference to response file. | 822 // Prepare 'file' with reference to response file. |
666 SmallString<128> IncRef; | 823 SmallString<128> IncRef; |
667 IncRef.append(1, '@'); | 824 IncRef.append(1, '@'); |
668 IncRef.append(IncludedFileName.c_str()); | 825 IncRef.append(IncludedFileName.c_str()); |
669 llvm::SmallVector<const char *, 4> Argv = | 826 llvm::SmallVector<const char *, 4> Argv = |
673 llvm::BumpPtrAllocator A; | 830 llvm::BumpPtrAllocator A; |
674 llvm::StringSaver Saver(A); | 831 llvm::StringSaver Saver(A); |
675 bool Res = llvm::cl::ExpandResponseFiles( | 832 bool Res = llvm::cl::ExpandResponseFiles( |
676 Saver, llvm::cl::TokenizeGNUCommandLine, Argv, false, true); | 833 Saver, llvm::cl::TokenizeGNUCommandLine, Argv, false, true); |
677 EXPECT_TRUE(Res); | 834 EXPECT_TRUE(Res); |
678 EXPECT_EQ(Argv.size(), 9U); | 835 EXPECT_EQ(Argv.size(), 13U); |
679 EXPECT_STREQ(Argv[0], "test/test"); | 836 EXPECT_STREQ(Argv[0], "test/test"); |
680 EXPECT_STREQ(Argv[1], "-flag_1"); | 837 EXPECT_STREQ(Argv[1], "-flag_1"); |
681 EXPECT_STREQ(Argv[2], "-option_1"); | 838 EXPECT_STREQ(Argv[2], "-option_1"); |
682 EXPECT_STREQ(Argv[3], "-option_2"); | 839 EXPECT_STREQ(Argv[3], "-option_2"); |
683 EXPECT_STREQ(Argv[4], "-option_21"); | 840 EXPECT_STREQ(Argv[4], "-option_21"); |
684 EXPECT_STREQ(Argv[5], "-option_22"); | 841 EXPECT_STREQ(Argv[5], "-option_22"); |
685 EXPECT_STREQ(Argv[6], "-option_23=abcd"); | 842 EXPECT_STREQ(Argv[6], "-option_23=abcd"); |
686 EXPECT_STREQ(Argv[7], "-option_3=abcd"); | 843 EXPECT_STREQ(Argv[7], "-option_3=abcd"); |
687 EXPECT_STREQ(Argv[8], "-flag_2"); | 844 EXPECT_STREQ(Argv[8], "-option_31"); |
688 | 845 EXPECT_STREQ(Argv[9], "-option_32"); |
846 EXPECT_STREQ(Argv[10], "-option_33=abcd"); | |
847 EXPECT_STREQ(Argv[11], "-option_4=efjk"); | |
848 EXPECT_STREQ(Argv[12], "-flag_2"); | |
849 | |
850 llvm::sys::fs::remove(IncludedFileName3); | |
689 llvm::sys::fs::remove(IncludedFileName2); | 851 llvm::sys::fs::remove(IncludedFileName2); |
690 llvm::sys::fs::remove(IncDir); | 852 llvm::sys::fs::remove(IncDir); |
691 llvm::sys::fs::remove(IncludedFileName); | 853 llvm::sys::fs::remove(IncludedFileName); |
692 llvm::sys::fs::remove(TestDir); | 854 llvm::sys::fs::remove(TestDir); |
855 } | |
856 | |
857 TEST(CommandLineTest, RecursiveResponseFiles) { | |
858 SmallString<128> TestDir; | |
859 std::error_code EC = sys::fs::createUniqueDirectory("unittest", TestDir); | |
860 EXPECT_TRUE(!EC); | |
861 | |
862 SmallString<128> SelfFilePath; | |
863 sys::path::append(SelfFilePath, TestDir, "self.rsp"); | |
864 std::string SelfFileRef = std::string("@") + SelfFilePath.c_str(); | |
865 | |
866 SmallString<128> NestedFilePath; | |
867 sys::path::append(NestedFilePath, TestDir, "nested.rsp"); | |
868 std::string NestedFileRef = std::string("@") + NestedFilePath.c_str(); | |
869 | |
870 SmallString<128> FlagFilePath; | |
871 sys::path::append(FlagFilePath, TestDir, "flag.rsp"); | |
872 std::string FlagFileRef = std::string("@") + FlagFilePath.c_str(); | |
873 | |
874 std::ofstream SelfFile(SelfFilePath.str()); | |
875 EXPECT_TRUE(SelfFile.is_open()); | |
876 SelfFile << "-option_1\n"; | |
877 SelfFile << FlagFileRef << "\n"; | |
878 SelfFile << NestedFileRef << "\n"; | |
879 SelfFile << SelfFileRef << "\n"; | |
880 SelfFile.close(); | |
881 | |
882 std::ofstream NestedFile(NestedFilePath.str()); | |
883 EXPECT_TRUE(NestedFile.is_open()); | |
884 NestedFile << "-option_2\n"; | |
885 NestedFile << FlagFileRef << "\n"; | |
886 NestedFile << SelfFileRef << "\n"; | |
887 NestedFile << NestedFileRef << "\n"; | |
888 NestedFile.close(); | |
889 | |
890 std::ofstream FlagFile(FlagFilePath.str()); | |
891 EXPECT_TRUE(FlagFile.is_open()); | |
892 FlagFile << "-option_x\n"; | |
893 FlagFile.close(); | |
894 | |
895 // Ensure: | |
896 // Recursive expansion terminates | |
897 // Recursive files never expand | |
898 // Non-recursive repeats are allowed | |
899 SmallVector<const char *, 4> Argv = {"test/test", SelfFileRef.c_str(), | |
900 "-option_3"}; | |
901 BumpPtrAllocator A; | |
902 StringSaver Saver(A); | |
903 #ifdef _WIN32 | |
904 cl::TokenizerCallback Tokenizer = cl::TokenizeWindowsCommandLine; | |
905 #else | |
906 cl::TokenizerCallback Tokenizer = cl::TokenizeGNUCommandLine; | |
907 #endif | |
908 bool Res = cl::ExpandResponseFiles(Saver, Tokenizer, Argv, false, false); | |
909 EXPECT_FALSE(Res); | |
910 | |
911 EXPECT_EQ(Argv.size(), 9U); | |
912 EXPECT_STREQ(Argv[0], "test/test"); | |
913 EXPECT_STREQ(Argv[1], "-option_1"); | |
914 EXPECT_STREQ(Argv[2], "-option_x"); | |
915 EXPECT_STREQ(Argv[3], "-option_2"); | |
916 EXPECT_STREQ(Argv[4], "-option_x"); | |
917 EXPECT_STREQ(Argv[5], SelfFileRef.c_str()); | |
918 EXPECT_STREQ(Argv[6], NestedFileRef.c_str()); | |
919 EXPECT_STREQ(Argv[7], SelfFileRef.c_str()); | |
920 EXPECT_STREQ(Argv[8], "-option_3"); | |
921 } | |
922 | |
923 TEST(CommandLineTest, ResponseFilesAtArguments) { | |
924 SmallString<128> TestDir; | |
925 std::error_code EC = sys::fs::createUniqueDirectory("unittest", TestDir); | |
926 EXPECT_TRUE(!EC); | |
927 | |
928 SmallString<128> ResponseFilePath; | |
929 sys::path::append(ResponseFilePath, TestDir, "test.rsp"); | |
930 | |
931 std::ofstream ResponseFile(ResponseFilePath.c_str()); | |
932 EXPECT_TRUE(ResponseFile.is_open()); | |
933 ResponseFile << "-foo" << "\n"; | |
934 ResponseFile << "-bar" << "\n"; | |
935 ResponseFile.close(); | |
936 | |
937 // Ensure we expand rsp files after lots of non-rsp arguments starting with @. | |
938 constexpr size_t NON_RSP_AT_ARGS = 64; | |
939 SmallVector<const char *, 4> Argv = {"test/test"}; | |
940 Argv.append(NON_RSP_AT_ARGS, "@non_rsp_at_arg"); | |
941 std::string ResponseFileRef = std::string("@") + ResponseFilePath.c_str(); | |
942 Argv.push_back(ResponseFileRef.c_str()); | |
943 | |
944 BumpPtrAllocator A; | |
945 StringSaver Saver(A); | |
946 bool Res = cl::ExpandResponseFiles(Saver, cl::TokenizeGNUCommandLine, Argv, | |
947 false, false); | |
948 EXPECT_FALSE(Res); | |
949 | |
950 // ASSERT instead of EXPECT to prevent potential out-of-bounds access. | |
951 ASSERT_EQ(Argv.size(), 1 + NON_RSP_AT_ARGS + 2); | |
952 size_t i = 0; | |
953 EXPECT_STREQ(Argv[i++], "test/test"); | |
954 for (; i < 1 + NON_RSP_AT_ARGS; ++i) | |
955 EXPECT_STREQ(Argv[i], "@non_rsp_at_arg"); | |
956 EXPECT_STREQ(Argv[i++], "-foo"); | |
957 EXPECT_STREQ(Argv[i++], "-bar"); | |
693 } | 958 } |
694 | 959 |
695 TEST(CommandLineTest, SetDefautValue) { | 960 TEST(CommandLineTest, SetDefautValue) { |
696 cl::ResetCommandLineParser(); | 961 cl::ResetCommandLineParser(); |
697 | 962 |
723 } | 988 } |
724 | 989 |
725 EXPECT_TRUE(Opt1 == "true"); | 990 EXPECT_TRUE(Opt1 == "true"); |
726 EXPECT_TRUE(Opt2); | 991 EXPECT_TRUE(Opt2); |
727 EXPECT_TRUE(Opt3 == 3); | 992 EXPECT_TRUE(Opt3 == 3); |
993 Alias.removeArgument(); | |
728 } | 994 } |
729 | 995 |
730 TEST(CommandLineTest, ReadConfigFile) { | 996 TEST(CommandLineTest, ReadConfigFile) { |
731 llvm::SmallVector<const char *, 1> Argv; | 997 llvm::SmallVector<const char *, 1> Argv; |
732 | 998 |
779 llvm::sys::fs::remove(TestCfg2); | 1045 llvm::sys::fs::remove(TestCfg2); |
780 llvm::sys::fs::remove(TestCfg); | 1046 llvm::sys::fs::remove(TestCfg); |
781 llvm::sys::fs::remove(TestDir); | 1047 llvm::sys::fs::remove(TestDir); |
782 } | 1048 } |
783 | 1049 |
1050 TEST(CommandLineTest, PositionalEatArgsError) { | |
1051 cl::ResetCommandLineParser(); | |
1052 | |
1053 StackOption<std::string, cl::list<std::string>> PosEatArgs( | |
1054 "positional-eat-args", cl::Positional, cl::desc("<arguments>..."), | |
1055 cl::ZeroOrMore, cl::PositionalEatsArgs); | |
1056 StackOption<std::string, cl::list<std::string>> PosEatArgs2( | |
1057 "positional-eat-args2", cl::Positional, cl::desc("Some strings"), | |
1058 cl::ZeroOrMore, cl::PositionalEatsArgs); | |
1059 | |
1060 const char *args[] = {"prog", "-positional-eat-args=XXXX"}; | |
1061 const char *args2[] = {"prog", "-positional-eat-args=XXXX", "-foo"}; | |
1062 const char *args3[] = {"prog", "-positional-eat-args", "-foo"}; | |
1063 const char *args4[] = {"prog", "-positional-eat-args", | |
1064 "-foo", "-positional-eat-args2", | |
1065 "-bar", "foo"}; | |
1066 | |
1067 std::string Errs; | |
1068 raw_string_ostream OS(Errs); | |
1069 EXPECT_FALSE(cl::ParseCommandLineOptions(2, args, StringRef(), &OS)); OS.flush(); | |
1070 EXPECT_FALSE(Errs.empty()); Errs.clear(); | |
1071 EXPECT_FALSE(cl::ParseCommandLineOptions(3, args2, StringRef(), &OS)); OS.flush(); | |
1072 EXPECT_FALSE(Errs.empty()); Errs.clear(); | |
1073 EXPECT_TRUE(cl::ParseCommandLineOptions(3, args3, StringRef(), &OS)); OS.flush(); | |
1074 EXPECT_TRUE(Errs.empty()); Errs.clear(); | |
1075 | |
1076 cl::ResetAllOptionOccurrences(); | |
1077 EXPECT_TRUE(cl::ParseCommandLineOptions(6, args4, StringRef(), &OS)); OS.flush(); | |
1078 EXPECT_TRUE(PosEatArgs.size() == 1); | |
1079 EXPECT_TRUE(PosEatArgs2.size() == 2); | |
1080 EXPECT_TRUE(Errs.empty()); | |
1081 } | |
1082 | |
1083 #ifdef _WIN32 | |
1084 TEST(CommandLineTest, GetCommandLineArguments) { | |
1085 int argc = __argc; | |
1086 char **argv = __argv; | |
1087 | |
1088 // GetCommandLineArguments is called in InitLLVM. | |
1089 llvm::InitLLVM X(argc, argv); | |
1090 | |
1091 EXPECT_EQ(llvm::sys::path::is_absolute(argv[0]), | |
1092 llvm::sys::path::is_absolute(__argv[0])); | |
1093 | |
1094 EXPECT_TRUE(llvm::sys::path::filename(argv[0]) | |
1095 .equals_lower("supporttests.exe")) | |
1096 << "Filename of test executable is " | |
1097 << llvm::sys::path::filename(argv[0]); | |
1098 } | |
1099 #endif | |
1100 | |
1101 class OutputRedirector { | |
1102 public: | |
1103 OutputRedirector(int RedirectFD) | |
1104 : RedirectFD(RedirectFD), OldFD(dup(RedirectFD)) { | |
1105 if (OldFD == -1 || | |
1106 sys::fs::createTemporaryFile("unittest-redirect", "", NewFD, | |
1107 FilePath) || | |
1108 dup2(NewFD, RedirectFD) == -1) | |
1109 Valid = false; | |
1110 } | |
1111 | |
1112 ~OutputRedirector() { | |
1113 dup2(OldFD, RedirectFD); | |
1114 close(OldFD); | |
1115 close(NewFD); | |
1116 } | |
1117 | |
1118 SmallVector<char, 128> FilePath; | |
1119 bool Valid = true; | |
1120 | |
1121 private: | |
1122 int RedirectFD; | |
1123 int OldFD; | |
1124 int NewFD; | |
1125 }; | |
1126 | |
1127 struct AutoDeleteFile { | |
1128 SmallVector<char, 128> FilePath; | |
1129 ~AutoDeleteFile() { | |
1130 if (!FilePath.empty()) | |
1131 sys::fs::remove(std::string(FilePath.data(), FilePath.size())); | |
1132 } | |
1133 }; | |
1134 | |
1135 class PrintOptionInfoTest : public ::testing::Test { | |
1136 public: | |
1137 // Return std::string because the output of a failing EXPECT check is | |
1138 // unreadable for StringRef. It also avoids any lifetime issues. | |
1139 template <typename... Ts> std::string runTest(Ts... OptionAttributes) { | |
1140 outs().flush(); // flush any output from previous tests | |
1141 AutoDeleteFile File; | |
1142 { | |
1143 OutputRedirector Stdout(fileno(stdout)); | |
1144 if (!Stdout.Valid) | |
1145 return ""; | |
1146 File.FilePath = Stdout.FilePath; | |
1147 | |
1148 StackOption<OptionValue> TestOption(Opt, cl::desc(HelpText), | |
1149 OptionAttributes...); | |
1150 printOptionInfo(TestOption, 26); | |
1151 outs().flush(); | |
1152 } | |
1153 auto Buffer = MemoryBuffer::getFile(File.FilePath); | |
1154 if (!Buffer) | |
1155 return ""; | |
1156 return Buffer->get()->getBuffer().str(); | |
1157 } | |
1158 | |
1159 enum class OptionValue { Val }; | |
1160 const StringRef Opt = "some-option"; | |
1161 const StringRef HelpText = "some help"; | |
1162 | |
1163 private: | |
1164 // This is a workaround for cl::Option sub-classes having their | |
1165 // printOptionInfo functions private. | |
1166 void printOptionInfo(const cl::Option &O, size_t Width) { | |
1167 O.printOptionInfo(Width); | |
1168 } | |
1169 }; | |
1170 | |
1171 TEST_F(PrintOptionInfoTest, PrintOptionInfoValueOptionalWithoutSentinel) { | |
1172 std::string Output = | |
1173 runTest(cl::ValueOptional, | |
1174 cl::values(clEnumValN(OptionValue::Val, "v1", "desc1"))); | |
1175 | |
1176 // clang-format off | |
1177 EXPECT_EQ(Output, (" --" + Opt + "=<value> - " + HelpText + "\n" | |
1178 " =v1 - desc1\n") | |
1179 .str()); | |
1180 // clang-format on | |
1181 } | |
1182 | |
1183 TEST_F(PrintOptionInfoTest, PrintOptionInfoValueOptionalWithSentinel) { | |
1184 std::string Output = runTest( | |
1185 cl::ValueOptional, cl::values(clEnumValN(OptionValue::Val, "v1", "desc1"), | |
1186 clEnumValN(OptionValue::Val, "", ""))); | |
1187 | |
1188 // clang-format off | |
1189 EXPECT_EQ(Output, | |
1190 (" --" + Opt + " - " + HelpText + "\n" | |
1191 " --" + Opt + "=<value> - " + HelpText + "\n" | |
1192 " =v1 - desc1\n") | |
1193 .str()); | |
1194 // clang-format on | |
1195 } | |
1196 | |
1197 TEST_F(PrintOptionInfoTest, PrintOptionInfoValueOptionalWithSentinelWithHelp) { | |
1198 std::string Output = runTest( | |
1199 cl::ValueOptional, cl::values(clEnumValN(OptionValue::Val, "v1", "desc1"), | |
1200 clEnumValN(OptionValue::Val, "", "desc2"))); | |
1201 | |
1202 // clang-format off | |
1203 EXPECT_EQ(Output, (" --" + Opt + " - " + HelpText + "\n" | |
1204 " --" + Opt + "=<value> - " + HelpText + "\n" | |
1205 " =v1 - desc1\n" | |
1206 " =<empty> - desc2\n") | |
1207 .str()); | |
1208 // clang-format on | |
1209 } | |
1210 | |
1211 TEST_F(PrintOptionInfoTest, PrintOptionInfoValueRequiredWithEmptyValueName) { | |
1212 std::string Output = runTest( | |
1213 cl::ValueRequired, cl::values(clEnumValN(OptionValue::Val, "v1", "desc1"), | |
1214 clEnumValN(OptionValue::Val, "", ""))); | |
1215 | |
1216 // clang-format off | |
1217 EXPECT_EQ(Output, (" --" + Opt + "=<value> - " + HelpText + "\n" | |
1218 " =v1 - desc1\n" | |
1219 " =<empty>\n") | |
1220 .str()); | |
1221 // clang-format on | |
1222 } | |
1223 | |
1224 TEST_F(PrintOptionInfoTest, PrintOptionInfoEmptyValueDescription) { | |
1225 std::string Output = runTest( | |
1226 cl::ValueRequired, cl::values(clEnumValN(OptionValue::Val, "v1", ""))); | |
1227 | |
1228 // clang-format off | |
1229 EXPECT_EQ(Output, | |
1230 (" --" + Opt + "=<value> - " + HelpText + "\n" | |
1231 " =v1\n").str()); | |
1232 // clang-format on | |
1233 } | |
1234 | |
1235 class GetOptionWidthTest : public ::testing::Test { | |
1236 public: | |
1237 enum class OptionValue { Val }; | |
1238 | |
1239 template <typename... Ts> | |
1240 size_t runTest(StringRef ArgName, Ts... OptionAttributes) { | |
1241 StackOption<OptionValue> TestOption(ArgName, cl::desc("some help"), | |
1242 OptionAttributes...); | |
1243 return getOptionWidth(TestOption); | |
1244 } | |
1245 | |
1246 private: | |
1247 // This is a workaround for cl::Option sub-classes having their | |
1248 // printOptionInfo | |
1249 // functions private. | |
1250 size_t getOptionWidth(const cl::Option &O) { return O.getOptionWidth(); } | |
1251 }; | |
1252 | |
1253 TEST_F(GetOptionWidthTest, GetOptionWidthArgNameLonger) { | |
1254 StringRef ArgName("a-long-argument-name"); | |
1255 size_t ExpectedStrSize = (" --" + ArgName + "=<value> - ").str().size(); | |
1256 EXPECT_EQ( | |
1257 runTest(ArgName, cl::values(clEnumValN(OptionValue::Val, "v", "help"))), | |
1258 ExpectedStrSize); | |
1259 } | |
1260 | |
1261 TEST_F(GetOptionWidthTest, GetOptionWidthFirstOptionNameLonger) { | |
1262 StringRef OptName("a-long-option-name"); | |
1263 size_t ExpectedStrSize = (" =" + OptName + " - ").str().size(); | |
1264 EXPECT_EQ( | |
1265 runTest("a", cl::values(clEnumValN(OptionValue::Val, OptName, "help"), | |
1266 clEnumValN(OptionValue::Val, "b", "help"))), | |
1267 ExpectedStrSize); | |
1268 } | |
1269 | |
1270 TEST_F(GetOptionWidthTest, GetOptionWidthSecondOptionNameLonger) { | |
1271 StringRef OptName("a-long-option-name"); | |
1272 size_t ExpectedStrSize = (" =" + OptName + " - ").str().size(); | |
1273 EXPECT_EQ( | |
1274 runTest("a", cl::values(clEnumValN(OptionValue::Val, "b", "help"), | |
1275 clEnumValN(OptionValue::Val, OptName, "help"))), | |
1276 ExpectedStrSize); | |
1277 } | |
1278 | |
1279 TEST_F(GetOptionWidthTest, GetOptionWidthEmptyOptionNameLonger) { | |
1280 size_t ExpectedStrSize = StringRef(" =<empty> - ").size(); | |
1281 // The length of a=<value> (including indentation) is actually the same as the | |
1282 // =<empty> string, so it is impossible to distinguish via testing the case | |
1283 // where the empty string is picked from where the option name is picked. | |
1284 EXPECT_EQ(runTest("a", cl::values(clEnumValN(OptionValue::Val, "b", "help"), | |
1285 clEnumValN(OptionValue::Val, "", "help"))), | |
1286 ExpectedStrSize); | |
1287 } | |
1288 | |
1289 TEST_F(GetOptionWidthTest, | |
1290 GetOptionWidthValueOptionalEmptyOptionWithNoDescription) { | |
1291 StringRef ArgName("a"); | |
1292 // The length of a=<value> (including indentation) is actually the same as the | |
1293 // =<empty> string, so it is impossible to distinguish via testing the case | |
1294 // where the empty string is ignored from where it is not ignored. | |
1295 // The dash will not actually be printed, but the space it would take up is | |
1296 // included to ensure a consistent column width. | |
1297 size_t ExpectedStrSize = (" -" + ArgName + "=<value> - ").str().size(); | |
1298 EXPECT_EQ(runTest(ArgName, cl::ValueOptional, | |
1299 cl::values(clEnumValN(OptionValue::Val, "value", "help"), | |
1300 clEnumValN(OptionValue::Val, "", ""))), | |
1301 ExpectedStrSize); | |
1302 } | |
1303 | |
1304 TEST_F(GetOptionWidthTest, | |
1305 GetOptionWidthValueRequiredEmptyOptionWithNoDescription) { | |
1306 // The length of a=<value> (including indentation) is actually the same as the | |
1307 // =<empty> string, so it is impossible to distinguish via testing the case | |
1308 // where the empty string is picked from where the option name is picked | |
1309 size_t ExpectedStrSize = StringRef(" =<empty> - ").size(); | |
1310 EXPECT_EQ(runTest("a", cl::ValueRequired, | |
1311 cl::values(clEnumValN(OptionValue::Val, "value", "help"), | |
1312 clEnumValN(OptionValue::Val, "", ""))), | |
1313 ExpectedStrSize); | |
1314 } | |
1315 | |
1316 TEST(CommandLineTest, PrefixOptions) { | |
1317 cl::ResetCommandLineParser(); | |
1318 | |
1319 StackOption<std::string, cl::list<std::string>> IncludeDirs( | |
1320 "I", cl::Prefix, cl::desc("Declare an include directory")); | |
1321 | |
1322 // Test non-prefixed variant works with cl::Prefix options. | |
1323 EXPECT_TRUE(IncludeDirs.empty()); | |
1324 const char *args[] = {"prog", "-I=/usr/include"}; | |
1325 EXPECT_TRUE( | |
1326 cl::ParseCommandLineOptions(2, args, StringRef(), &llvm::nulls())); | |
1327 EXPECT_TRUE(IncludeDirs.size() == 1); | |
1328 EXPECT_TRUE(IncludeDirs.front().compare("/usr/include") == 0); | |
1329 | |
1330 IncludeDirs.erase(IncludeDirs.begin()); | |
1331 cl::ResetAllOptionOccurrences(); | |
1332 | |
1333 // Test non-prefixed variant works with cl::Prefix options when value is | |
1334 // passed in following argument. | |
1335 EXPECT_TRUE(IncludeDirs.empty()); | |
1336 const char *args2[] = {"prog", "-I", "/usr/include"}; | |
1337 EXPECT_TRUE( | |
1338 cl::ParseCommandLineOptions(3, args2, StringRef(), &llvm::nulls())); | |
1339 EXPECT_TRUE(IncludeDirs.size() == 1); | |
1340 EXPECT_TRUE(IncludeDirs.front().compare("/usr/include") == 0); | |
1341 | |
1342 IncludeDirs.erase(IncludeDirs.begin()); | |
1343 cl::ResetAllOptionOccurrences(); | |
1344 | |
1345 // Test prefixed variant works with cl::Prefix options. | |
1346 EXPECT_TRUE(IncludeDirs.empty()); | |
1347 const char *args3[] = {"prog", "-I/usr/include"}; | |
1348 EXPECT_TRUE( | |
1349 cl::ParseCommandLineOptions(2, args3, StringRef(), &llvm::nulls())); | |
1350 EXPECT_TRUE(IncludeDirs.size() == 1); | |
1351 EXPECT_TRUE(IncludeDirs.front().compare("/usr/include") == 0); | |
1352 | |
1353 StackOption<std::string, cl::list<std::string>> MacroDefs( | |
1354 "D", cl::AlwaysPrefix, cl::desc("Define a macro"), | |
1355 cl::value_desc("MACRO[=VALUE]")); | |
1356 | |
1357 cl::ResetAllOptionOccurrences(); | |
1358 | |
1359 // Test non-prefixed variant does not work with cl::AlwaysPrefix options: | |
1360 // equal sign is part of the value. | |
1361 EXPECT_TRUE(MacroDefs.empty()); | |
1362 const char *args4[] = {"prog", "-D=HAVE_FOO"}; | |
1363 EXPECT_TRUE( | |
1364 cl::ParseCommandLineOptions(2, args4, StringRef(), &llvm::nulls())); | |
1365 EXPECT_TRUE(MacroDefs.size() == 1); | |
1366 EXPECT_TRUE(MacroDefs.front().compare("=HAVE_FOO") == 0); | |
1367 | |
1368 MacroDefs.erase(MacroDefs.begin()); | |
1369 cl::ResetAllOptionOccurrences(); | |
1370 | |
1371 // Test non-prefixed variant does not allow value to be passed in following | |
1372 // argument with cl::AlwaysPrefix options. | |
1373 EXPECT_TRUE(MacroDefs.empty()); | |
1374 const char *args5[] = {"prog", "-D", "HAVE_FOO"}; | |
1375 EXPECT_FALSE( | |
1376 cl::ParseCommandLineOptions(3, args5, StringRef(), &llvm::nulls())); | |
1377 EXPECT_TRUE(MacroDefs.empty()); | |
1378 | |
1379 cl::ResetAllOptionOccurrences(); | |
1380 | |
1381 // Test prefixed variant works with cl::AlwaysPrefix options. | |
1382 EXPECT_TRUE(MacroDefs.empty()); | |
1383 const char *args6[] = {"prog", "-DHAVE_FOO"}; | |
1384 EXPECT_TRUE( | |
1385 cl::ParseCommandLineOptions(2, args6, StringRef(), &llvm::nulls())); | |
1386 EXPECT_TRUE(MacroDefs.size() == 1); | |
1387 EXPECT_TRUE(MacroDefs.front().compare("HAVE_FOO") == 0); | |
1388 } | |
1389 | |
1390 TEST(CommandLineTest, GroupingWithValue) { | |
1391 cl::ResetCommandLineParser(); | |
1392 | |
1393 StackOption<bool> OptF("f", cl::Grouping, cl::desc("Some flag")); | |
1394 StackOption<bool> OptB("b", cl::Grouping, cl::desc("Another flag")); | |
1395 StackOption<bool> OptD("d", cl::Grouping, cl::ValueDisallowed, | |
1396 cl::desc("ValueDisallowed option")); | |
1397 StackOption<std::string> OptV("v", cl::Grouping, | |
1398 cl::desc("ValueRequired option")); | |
1399 StackOption<std::string> OptO("o", cl::Grouping, cl::ValueOptional, | |
1400 cl::desc("ValueOptional option")); | |
1401 | |
1402 // Should be possible to use an option which requires a value | |
1403 // at the end of a group. | |
1404 const char *args1[] = {"prog", "-fv", "val1"}; | |
1405 EXPECT_TRUE( | |
1406 cl::ParseCommandLineOptions(3, args1, StringRef(), &llvm::nulls())); | |
1407 EXPECT_TRUE(OptF); | |
1408 EXPECT_STREQ("val1", OptV.c_str()); | |
1409 OptV.clear(); | |
1410 cl::ResetAllOptionOccurrences(); | |
1411 | |
1412 // Should not crash if it is accidentally used elsewhere in the group. | |
1413 const char *args2[] = {"prog", "-vf", "val2"}; | |
1414 EXPECT_FALSE( | |
1415 cl::ParseCommandLineOptions(3, args2, StringRef(), &llvm::nulls())); | |
1416 OptV.clear(); | |
1417 cl::ResetAllOptionOccurrences(); | |
1418 | |
1419 // Should allow the "opt=value" form at the end of the group | |
1420 const char *args3[] = {"prog", "-fv=val3"}; | |
1421 EXPECT_TRUE( | |
1422 cl::ParseCommandLineOptions(2, args3, StringRef(), &llvm::nulls())); | |
1423 EXPECT_TRUE(OptF); | |
1424 EXPECT_STREQ("val3", OptV.c_str()); | |
1425 OptV.clear(); | |
1426 cl::ResetAllOptionOccurrences(); | |
1427 | |
1428 // Should allow assigning a value for a ValueOptional option | |
1429 // at the end of the group | |
1430 const char *args4[] = {"prog", "-fo=val4"}; | |
1431 EXPECT_TRUE( | |
1432 cl::ParseCommandLineOptions(2, args4, StringRef(), &llvm::nulls())); | |
1433 EXPECT_TRUE(OptF); | |
1434 EXPECT_STREQ("val4", OptO.c_str()); | |
1435 OptO.clear(); | |
1436 cl::ResetAllOptionOccurrences(); | |
1437 | |
1438 // Should assign an empty value if a ValueOptional option is used elsewhere | |
1439 // in the group. | |
1440 const char *args5[] = {"prog", "-fob"}; | |
1441 EXPECT_TRUE( | |
1442 cl::ParseCommandLineOptions(2, args5, StringRef(), &llvm::nulls())); | |
1443 EXPECT_TRUE(OptF); | |
1444 EXPECT_EQ(1, OptO.getNumOccurrences()); | |
1445 EXPECT_EQ(1, OptB.getNumOccurrences()); | |
1446 EXPECT_TRUE(OptO.empty()); | |
1447 cl::ResetAllOptionOccurrences(); | |
1448 | |
1449 // Should not allow an assignment for a ValueDisallowed option. | |
1450 const char *args6[] = {"prog", "-fd=false"}; | |
1451 EXPECT_FALSE( | |
1452 cl::ParseCommandLineOptions(2, args6, StringRef(), &llvm::nulls())); | |
1453 } | |
1454 | |
1455 TEST(CommandLineTest, GroupingAndPrefix) { | |
1456 cl::ResetCommandLineParser(); | |
1457 | |
1458 StackOption<bool> OptF("f", cl::Grouping, cl::desc("Some flag")); | |
1459 StackOption<bool> OptB("b", cl::Grouping, cl::desc("Another flag")); | |
1460 StackOption<std::string> OptP("p", cl::Prefix, cl::Grouping, | |
1461 cl::desc("Prefix and Grouping")); | |
1462 StackOption<std::string> OptA("a", cl::AlwaysPrefix, cl::Grouping, | |
1463 cl::desc("AlwaysPrefix and Grouping")); | |
1464 | |
1465 // Should be possible to use a cl::Prefix option without grouping. | |
1466 const char *args1[] = {"prog", "-pval1"}; | |
1467 EXPECT_TRUE( | |
1468 cl::ParseCommandLineOptions(2, args1, StringRef(), &llvm::nulls())); | |
1469 EXPECT_STREQ("val1", OptP.c_str()); | |
1470 OptP.clear(); | |
1471 cl::ResetAllOptionOccurrences(); | |
1472 | |
1473 // Should be possible to pass a value in a separate argument. | |
1474 const char *args2[] = {"prog", "-p", "val2"}; | |
1475 EXPECT_TRUE( | |
1476 cl::ParseCommandLineOptions(3, args2, StringRef(), &llvm::nulls())); | |
1477 EXPECT_STREQ("val2", OptP.c_str()); | |
1478 OptP.clear(); | |
1479 cl::ResetAllOptionOccurrences(); | |
1480 | |
1481 // The "-opt=value" form should work, too. | |
1482 const char *args3[] = {"prog", "-p=val3"}; | |
1483 EXPECT_TRUE( | |
1484 cl::ParseCommandLineOptions(2, args3, StringRef(), &llvm::nulls())); | |
1485 EXPECT_STREQ("val3", OptP.c_str()); | |
1486 OptP.clear(); | |
1487 cl::ResetAllOptionOccurrences(); | |
1488 | |
1489 // All three previous cases should work the same way if an option with both | |
1490 // cl::Prefix and cl::Grouping modifiers is used at the end of a group. | |
1491 const char *args4[] = {"prog", "-fpval4"}; | |
1492 EXPECT_TRUE( | |
1493 cl::ParseCommandLineOptions(2, args4, StringRef(), &llvm::nulls())); | |
1494 EXPECT_TRUE(OptF); | |
1495 EXPECT_STREQ("val4", OptP.c_str()); | |
1496 OptP.clear(); | |
1497 cl::ResetAllOptionOccurrences(); | |
1498 | |
1499 const char *args5[] = {"prog", "-fp", "val5"}; | |
1500 EXPECT_TRUE( | |
1501 cl::ParseCommandLineOptions(3, args5, StringRef(), &llvm::nulls())); | |
1502 EXPECT_TRUE(OptF); | |
1503 EXPECT_STREQ("val5", OptP.c_str()); | |
1504 OptP.clear(); | |
1505 cl::ResetAllOptionOccurrences(); | |
1506 | |
1507 const char *args6[] = {"prog", "-fp=val6"}; | |
1508 EXPECT_TRUE( | |
1509 cl::ParseCommandLineOptions(2, args6, StringRef(), &llvm::nulls())); | |
1510 EXPECT_TRUE(OptF); | |
1511 EXPECT_STREQ("val6", OptP.c_str()); | |
1512 OptP.clear(); | |
1513 cl::ResetAllOptionOccurrences(); | |
1514 | |
1515 // Should assign a value even if the part after a cl::Prefix option is equal | |
1516 // to the name of another option. | |
1517 const char *args7[] = {"prog", "-fpb"}; | |
1518 EXPECT_TRUE( | |
1519 cl::ParseCommandLineOptions(2, args7, StringRef(), &llvm::nulls())); | |
1520 EXPECT_TRUE(OptF); | |
1521 EXPECT_STREQ("b", OptP.c_str()); | |
1522 EXPECT_FALSE(OptB); | |
1523 OptP.clear(); | |
1524 cl::ResetAllOptionOccurrences(); | |
1525 | |
1526 // Should be possible to use a cl::AlwaysPrefix option without grouping. | |
1527 const char *args8[] = {"prog", "-aval8"}; | |
1528 EXPECT_TRUE( | |
1529 cl::ParseCommandLineOptions(2, args8, StringRef(), &llvm::nulls())); | |
1530 EXPECT_STREQ("val8", OptA.c_str()); | |
1531 OptA.clear(); | |
1532 cl::ResetAllOptionOccurrences(); | |
1533 | |
1534 // Should not be possible to pass a value in a separate argument. | |
1535 const char *args9[] = {"prog", "-a", "val9"}; | |
1536 EXPECT_FALSE( | |
1537 cl::ParseCommandLineOptions(3, args9, StringRef(), &llvm::nulls())); | |
1538 cl::ResetAllOptionOccurrences(); | |
1539 | |
1540 // With the "-opt=value" form, the "=" symbol should be preserved. | |
1541 const char *args10[] = {"prog", "-a=val10"}; | |
1542 EXPECT_TRUE( | |
1543 cl::ParseCommandLineOptions(2, args10, StringRef(), &llvm::nulls())); | |
1544 EXPECT_STREQ("=val10", OptA.c_str()); | |
1545 OptA.clear(); | |
1546 cl::ResetAllOptionOccurrences(); | |
1547 | |
1548 // All three previous cases should work the same way if an option with both | |
1549 // cl::AlwaysPrefix and cl::Grouping modifiers is used at the end of a group. | |
1550 const char *args11[] = {"prog", "-faval11"}; | |
1551 EXPECT_TRUE( | |
1552 cl::ParseCommandLineOptions(2, args11, StringRef(), &llvm::nulls())); | |
1553 EXPECT_TRUE(OptF); | |
1554 EXPECT_STREQ("val11", OptA.c_str()); | |
1555 OptA.clear(); | |
1556 cl::ResetAllOptionOccurrences(); | |
1557 | |
1558 const char *args12[] = {"prog", "-fa", "val12"}; | |
1559 EXPECT_FALSE( | |
1560 cl::ParseCommandLineOptions(3, args12, StringRef(), &llvm::nulls())); | |
1561 cl::ResetAllOptionOccurrences(); | |
1562 | |
1563 const char *args13[] = {"prog", "-fa=val13"}; | |
1564 EXPECT_TRUE( | |
1565 cl::ParseCommandLineOptions(2, args13, StringRef(), &llvm::nulls())); | |
1566 EXPECT_TRUE(OptF); | |
1567 EXPECT_STREQ("=val13", OptA.c_str()); | |
1568 OptA.clear(); | |
1569 cl::ResetAllOptionOccurrences(); | |
1570 | |
1571 // Should assign a value even if the part after a cl::AlwaysPrefix option | |
1572 // is equal to the name of another option. | |
1573 const char *args14[] = {"prog", "-fab"}; | |
1574 EXPECT_TRUE( | |
1575 cl::ParseCommandLineOptions(2, args14, StringRef(), &llvm::nulls())); | |
1576 EXPECT_TRUE(OptF); | |
1577 EXPECT_STREQ("b", OptA.c_str()); | |
1578 EXPECT_FALSE(OptB); | |
1579 OptA.clear(); | |
1580 cl::ResetAllOptionOccurrences(); | |
1581 } | |
1582 | |
1583 TEST(CommandLineTest, LongOptions) { | |
1584 cl::ResetCommandLineParser(); | |
1585 | |
1586 StackOption<bool> OptA("a", cl::desc("Some flag")); | |
1587 StackOption<bool> OptBLong("long-flag", cl::desc("Some long flag")); | |
1588 StackOption<bool, cl::alias> OptB("b", cl::desc("Alias to --long-flag"), | |
1589 cl::aliasopt(OptBLong)); | |
1590 StackOption<std::string> OptAB("ab", cl::desc("Another long option")); | |
1591 | |
1592 std::string Errs; | |
1593 raw_string_ostream OS(Errs); | |
1594 | |
1595 const char *args1[] = {"prog", "-a", "-ab", "val1"}; | |
1596 const char *args2[] = {"prog", "-a", "--ab", "val1"}; | |
1597 const char *args3[] = {"prog", "-ab", "--ab", "val1"}; | |
1598 | |
1599 // | |
1600 // The following tests treat `-` and `--` the same, and always match the | |
1601 // longest string. | |
1602 // | |
1603 | |
1604 EXPECT_TRUE( | |
1605 cl::ParseCommandLineOptions(4, args1, StringRef(), &OS)); OS.flush(); | |
1606 EXPECT_TRUE(OptA); | |
1607 EXPECT_FALSE(OptBLong); | |
1608 EXPECT_STREQ("val1", OptAB.c_str()); | |
1609 EXPECT_TRUE(Errs.empty()); Errs.clear(); | |
1610 cl::ResetAllOptionOccurrences(); | |
1611 | |
1612 EXPECT_TRUE( | |
1613 cl::ParseCommandLineOptions(4, args2, StringRef(), &OS)); OS.flush(); | |
1614 EXPECT_TRUE(OptA); | |
1615 EXPECT_FALSE(OptBLong); | |
1616 EXPECT_STREQ("val1", OptAB.c_str()); | |
1617 EXPECT_TRUE(Errs.empty()); Errs.clear(); | |
1618 cl::ResetAllOptionOccurrences(); | |
1619 | |
1620 // Fails because `-ab` and `--ab` are treated the same and appear more than | |
1621 // once. Also, `val1` is unexpected. | |
1622 EXPECT_FALSE( | |
1623 cl::ParseCommandLineOptions(4, args3, StringRef(), &OS)); OS.flush(); | |
1624 outs()<< Errs << "\n"; | |
1625 EXPECT_FALSE(Errs.empty()); Errs.clear(); | |
1626 cl::ResetAllOptionOccurrences(); | |
1627 | |
1628 // | |
1629 // The following tests treat `-` and `--` differently, with `-` for short, and | |
1630 // `--` for long options. | |
1631 // | |
1632 | |
1633 // Fails because `-ab` is treated as `-a -b`, so `-a` is seen twice, and | |
1634 // `val1` is unexpected. | |
1635 EXPECT_FALSE(cl::ParseCommandLineOptions(4, args1, StringRef(), | |
1636 &OS, nullptr, true)); OS.flush(); | |
1637 EXPECT_FALSE(Errs.empty()); Errs.clear(); | |
1638 cl::ResetAllOptionOccurrences(); | |
1639 | |
1640 // Works because `-a` is treated differently than `--ab`. | |
1641 EXPECT_TRUE(cl::ParseCommandLineOptions(4, args2, StringRef(), | |
1642 &OS, nullptr, true)); OS.flush(); | |
1643 EXPECT_TRUE(Errs.empty()); Errs.clear(); | |
1644 cl::ResetAllOptionOccurrences(); | |
1645 | |
1646 // Works because `-ab` is treated as `-a -b`, and `--ab` is a long option. | |
1647 EXPECT_TRUE(cl::ParseCommandLineOptions(4, args3, StringRef(), | |
1648 &OS, nullptr, true)); | |
1649 EXPECT_TRUE(OptA); | |
1650 EXPECT_TRUE(OptBLong); | |
1651 EXPECT_STREQ("val1", OptAB.c_str()); | |
1652 OS.flush(); | |
1653 EXPECT_TRUE(Errs.empty()); Errs.clear(); | |
1654 cl::ResetAllOptionOccurrences(); | |
1655 } | |
784 } // anonymous namespace | 1656 } // anonymous namespace |