diff options
Diffstat (limited to 'llvm/unittests/Support/CommandLineTest.cpp')
-rw-r--r-- | llvm/unittests/Support/CommandLineTest.cpp | 134 |
1 files changed, 134 insertions, 0 deletions
diff --git a/llvm/unittests/Support/CommandLineTest.cpp b/llvm/unittests/Support/CommandLineTest.cpp index 416e0ee..8f8e1ba 100644 --- a/llvm/unittests/Support/CommandLineTest.cpp +++ b/llvm/unittests/Support/CommandLineTest.cpp @@ -13,6 +13,7 @@ #include "llvm/Config/config.h" #include "llvm/Support/FileSystem.h" #include "llvm/Support/InitLLVM.h" +#include "llvm/Support/MemoryBuffer.h" #include "llvm/Support/Path.h" #include "llvm/Support/Program.h" #include "llvm/Support/StringSaver.h" @@ -839,4 +840,137 @@ TEST(CommandLineTest, GetCommandLineArguments) { } #endif +class OutputRedirector { +public: + OutputRedirector(int RedirectFD) + : RedirectFD(RedirectFD), OldFD(dup(RedirectFD)) { + if (OldFD == -1 || + sys::fs::createTemporaryFile("unittest-redirect", "", NewFD, + FilePath) || + dup2(NewFD, RedirectFD) == -1) + Valid = false; + } + + ~OutputRedirector() { + dup2(OldFD, RedirectFD); + close(OldFD); + close(NewFD); + } + + SmallVector<char, 128> FilePath; + bool Valid = true; + +private: + int RedirectFD; + int OldFD; + int NewFD; +}; + +struct AutoDeleteFile { + SmallVector<char, 128> FilePath; + ~AutoDeleteFile() { + if (!FilePath.empty()) + sys::fs::remove(std::string(FilePath.data(), FilePath.size())); + } +}; + +class PrintOptionInfoTest : public ::testing::Test { +public: + // Return std::string because the output of a failing EXPECT check is + // unreadable for StringRef. It also avoids any lifetime issues. + template <typename... Ts> std::string runTest(Ts... OptionAttributes) { + AutoDeleteFile File; + { + OutputRedirector Stdout(fileno(stdout)); + if (!Stdout.Valid) + return ""; + File.FilePath = Stdout.FilePath; + + StackOption<OptionValue> TestOption(Opt, cl::desc(HelpText), + OptionAttributes...); + printOptionInfo(TestOption, 25); + outs().flush(); + } + auto Buffer = MemoryBuffer::getFile(File.FilePath); + if (!Buffer) + return ""; + return Buffer->get()->getBuffer().str(); + } + + enum class OptionValue { Val }; + const StringRef Opt = "some-option"; + const StringRef HelpText = "some help"; + +private: + // This is a workaround for cl::Option sub-classes having their + // printOptionInfo functions private. + void printOptionInfo(const cl::Option &O, size_t Width) { + O.printOptionInfo(Width); + } +}; + +TEST_F(PrintOptionInfoTest, PrintOptionInfoValueOptionalWithoutSentinel) { + std::string Output = + runTest(cl::ValueOptional, + cl::values(clEnumValN(OptionValue::Val, "v1", "desc1"))); + + // clang-format off + EXPECT_EQ(Output, (" -" + Opt + "=<value> - " + HelpText + "\n" + " =v1 - desc1\n") + .str()); + // clang-format on +} + +TEST_F(PrintOptionInfoTest, PrintOptionInfoValueOptionalWithSentinel) { + std::string Output = runTest( + cl::ValueOptional, cl::values(clEnumValN(OptionValue::Val, "v1", "desc1"), + clEnumValN(OptionValue::Val, "", ""))); + + // clang-format off + EXPECT_EQ(Output, + (" -" + Opt + " - " + HelpText + "\n" + " -" + Opt + "=<value> - " + HelpText + "\n" + " =v1 - desc1\n") + .str()); + // clang-format on +} + +TEST_F(PrintOptionInfoTest, PrintOptionInfoValueOptionalWithSentinelWithHelp) { + std::string Output = runTest( + cl::ValueOptional, cl::values(clEnumValN(OptionValue::Val, "v1", "desc1"), + clEnumValN(OptionValue::Val, "", "desc2"))); + + // clang-format off + EXPECT_EQ(Output, (" -" + Opt + " - " + HelpText + "\n" + " -" + Opt + "=<value> - " + HelpText + "\n" + " =v1 - desc1\n" + " =<empty> - desc2\n") + .str()); + // clang-format on +} + +TEST_F(PrintOptionInfoTest, PrintOptionInfoValueRequiredWithEmptyValueName) { + std::string Output = runTest( + cl::ValueRequired, cl::values(clEnumValN(OptionValue::Val, "v1", "desc1"), + clEnumValN(OptionValue::Val, "", ""))); + + // clang-format off + EXPECT_EQ(Output, (" -" + Opt + "=<value> - " + HelpText + "\n" + " =v1 - desc1\n" + " =<empty>\n") + .str()); + // clang-format on +} + +TEST_F(PrintOptionInfoTest, PrintOptionInfoEmptyValueDescription) { + std::string Output = runTest( + cl::ValueRequired, cl::values(clEnumValN(OptionValue::Val, "v1", ""))); + + // clang-format off + EXPECT_EQ(Output, + (" -" + Opt + "=<value> - " + HelpText + "\n" + " =v1\n").str()); + // clang-format on +} + } // anonymous namespace |