blob: 135e1f31cbf7cdd8d54872e778b86ee12cdcd169 [file] [edit]
//===- CommandLineTest.cpp ------------------------------------------------===//
//
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//
#include "orc-rt-utils/CommandLine.h"
#include "orc-rt/Error.h"
#include "llvm/Testing/Support/Error.h"
#include "gtest/gtest.h"
using namespace orc_rt;
class CommandLineParserTest : public ::testing::Test {
protected:
std::string Host;
int Port = 0;
bool Verbose = false;
bool Help = false;
CommandLineParser Parser;
void SetUp() override {
Parser.addValue("host", "Hostname", std::string("localhost"), Host,
CommandLineParser::OptionKind::Value, 'h');
Parser.addFlag("help", "Display this help message", false, Help, '?');
Parser.addValue("port", "Port number", 8080, Port,
CommandLineParser::OptionKind::Value, 'p');
Parser.addFlag("verbose", "Enable verbose logging", false, Verbose, 'v');
}
};
TEST_F(CommandLineParserTest, NoopTest) {
CommandLineParser Parser;
const char *Argv[] = {"appname"};
auto Err = Parser.parse(1, const_cast<char **>(Argv));
EXPECT_FALSE(!!Err);
}
TEST_F(CommandLineParserTest, ValueRequired) {
const char *Argv[] = {"appname", "--host"};
auto Err = Parser.parse(std::begin(Argv), std::end(Argv));
if (!Err) {
ADD_FAILURE() << "--host requires a value, shouldn't succeed.";
} else {
orc_rt::consumeError(std::move(Err));
}
}
TEST_F(CommandLineParserTest, UnknownOption) {
const char *Argv[] = {"appname", "--unknown=foo"};
auto Err = Parser.parse(std::begin(Argv), std::end(Argv));
if (!Err) {
ADD_FAILURE() << "unknown option, shouldn't succeed.";
} else {
orc_rt::consumeError(std::move(Err));
}
}
TEST_F(CommandLineParserTest, InvalidInteger) {
const char *Argv[] = {"appname", "--port=not_a_number"};
auto Err = Parser.parse(std::begin(Argv), std::end(Argv));
if (!Err) {
ADD_FAILURE() << "Invalid integer, shouldn't succeed.";
} else {
orc_rt::consumeError(std::move(Err));
}
}
TEST_F(CommandLineParserTest, ParseFullConfiguration) {
const char *Argv[] = {"appname", "--host=example.com", "--port=8080",
"--verbose=true"};
cantFail(Parser.parse(std::begin(Argv), std::end(Argv)));
EXPECT_EQ(Host, "example.com");
EXPECT_EQ(Port, 8080);
EXPECT_EQ(Verbose, true);
}
TEST_F(CommandLineParserTest, ShortFlagClustering) {
const char *Argv[] = {"appname", "-v?"};
cantFail(Parser.parse(std::begin(Argv), std::end(Argv)));
EXPECT_TRUE(Verbose);
EXPECT_TRUE(Help);
}
TEST_F(CommandLineParserTest, ShortFlagWithValue) {
const char *Argv[] = {"appname", "-p", "1234", "-hlocalhost"};
cantFail(Parser.parse(std::begin(Argv), std::end(Argv)));
EXPECT_EQ(Port, 1234);
EXPECT_EQ(Host, "localhost");
}
TEST_F(CommandLineParserTest, ClusterWithValueAtEnd) {
const char *Argv[] = {"appname", "-vp9999"};
cantFail(Parser.parse(std::begin(Argv), std::end(Argv)));
EXPECT_TRUE(Verbose);
EXPECT_EQ(Port, 9999);
}
TEST_F(CommandLineParserTest, DoubleDashTerminatesOptionParsing) {
const char *Argv[] = {"appname", "-v", "--", "-p", "1234"};
cantFail(Parser.parse(static_cast<int>(std::size(Argv)),
const_cast<char **>(Argv)));
EXPECT_TRUE(Verbose);
EXPECT_EQ(Port, 8080); // Should remain default
ASSERT_EQ(Parser.positionals().size(), 2u);
EXPECT_EQ(Parser.positionals()[0], "-p");
EXPECT_EQ(Parser.positionals()[1], "1234");
}
TEST_F(CommandLineParserTest, PrintHelpAlignmentWithShortFlags) {
std::string LogFile;
Parser.addValue("log-file", "Path to log", std::string("out.log"), LogFile);
std::stringstream SS;
Parser.printHelp(SS, "appname");
std::string Result = SS.str();
auto GetColumn = [&](std::string_view SearchTerm) -> size_t {
size_t Pos = Result.find(SearchTerm);
if (Pos == std::string::npos)
return 0;
size_t LineStart = Result.rfind('\n', Pos);
return (LineStart == std::string::npos) ? Pos : (Pos - LineStart - 1);
};
size_t PortDescCol = GetColumn("Port number");
size_t LogDescCol = GetColumn("Path to log");
size_t VerbDescCol = GetColumn("Enable verbose");
ASSERT_NE(PortDescCol, 0u);
EXPECT_EQ(PortDescCol, LogDescCol)
<< "Descriptions should align even if short flag is missing";
EXPECT_EQ(LogDescCol, VerbDescCol);
size_t LogFlagPos = Result.find("--log-file");
size_t PortFlagPos = Result.find("--port");
size_t LogFlagCol = (LogFlagPos - Result.rfind('\n', LogFlagPos) - 1);
size_t PortFlagCol = (PortFlagPos - Result.rfind('\n', PortFlagPos) - 1);
EXPECT_EQ(LogFlagCol, PortFlagCol);
}