//===----------------------------------------------------------------------===//
#include "llvm/ADT/STLExtras.h"
-#include "llvm/Support/CommandLine.h"
#include "llvm/Config/config.h"
+#include "llvm/Support/CommandLine.h"
+#include "llvm/Support/StringSaver.h"
#include "gtest/gtest.h"
#include <stdlib.h>
#include <string>
TempEnvVar(const char *name, const char *value)
: name(name) {
const char *old_value = getenv(name);
- EXPECT_EQ(NULL, old_value) << old_value;
+ EXPECT_EQ(nullptr, old_value) << old_value;
#if HAVE_SETENV
setenv(name, value, true);
#else
#if HAVE_SETENV
// Assume setenv and unsetenv come together.
unsetenv(name);
+#else
+ (void)name; // Suppress -Wunused-private-field.
#endif
}
const char *const name;
};
+template <typename T>
+class StackOption : public cl::opt<T> {
+ typedef cl::opt<T> Base;
+public:
+ // One option...
+ template<class M0t>
+ explicit StackOption(const M0t &M0) : Base(M0) {}
+
+ // Two options...
+ template<class M0t, class M1t>
+ StackOption(const M0t &M0, const M1t &M1) : Base(M0, M1) {}
+
+ // Three options...
+ template<class M0t, class M1t, class M2t>
+ StackOption(const M0t &M0, const M1t &M1, const M2t &M2) : Base(M0, M1, M2) {}
+
+ // Four options...
+ template<class M0t, class M1t, class M2t, class M3t>
+ StackOption(const M0t &M0, const M1t &M1, const M2t &M2, const M3t &M3)
+ : Base(M0, M1, M2, M3) {}
+
+ ~StackOption() override { this->removeArgument(); }
+};
+
+
cl::OptionCategory TestCategory("Test Options", "Description");
-cl::opt<int> TestOption("test-option", cl::desc("old description"));
TEST(CommandLineTest, ModifyExisitingOption) {
+ StackOption<int> TestOption("test-option", cl::desc("old description"));
+
const char Description[] = "New description";
const char ArgString[] = "new-test-option";
const char ValueString[] = "Integer";
- StringMap<cl::Option*> Map;
- cl::getRegisteredOptions(Map);
+ StringMap<cl::Option *> &Map = cl::getRegisteredOptions();
ASSERT_TRUE(Map.count("test-option") == 1) <<
"Could not find option in map.";
// command line system will still hold a pointer to a deallocated cl::Option.
TEST(CommandLineTest, ParseEnvironmentToLocalVar) {
// Put cl::opt on stack to check for proper initialization of fields.
- cl::opt<std::string> EnvironmentTestOptionLocal("env-test-opt-local");
+ StackOption<std::string> EnvironmentTestOptionLocal("env-test-opt-local");
TempEnvVar TEV(test_env_var, "-env-test-opt-local=hello-local");
EXPECT_EQ("", EnvironmentTestOptionLocal);
cl::ParseEnvironmentOptions("CommandLineTest", test_env_var);
#endif // SKIP_ENVIRONMENT_TESTS
TEST(CommandLineTest, UseOptionCategory) {
- cl::opt<int> TestOption2("test-option", cl::cat(TestCategory));
+ StackOption<int> TestOption2("test-option", cl::cat(TestCategory));
ASSERT_EQ(&TestCategory,TestOption2.Category) << "Failed to assign Option "
"Category.";
}
-class StrDupSaver : public cl::StringSaver {
- const char *SaveString(const char *Str) LLVM_OVERRIDE {
- return strdup(Str);
+typedef void ParserFunction(StringRef Source, StringSaver &Saver,
+ SmallVectorImpl<const char *> &NewArgv,
+ bool MarkEOLs);
+
+void testCommandLineTokenizer(ParserFunction *parse, const char *Input,
+ const char *const Output[], size_t OutputSize) {
+ SmallVector<const char *, 0> Actual;
+ BumpPtrAllocator A;
+ StringSaver Saver(A);
+ parse(Input, Saver, Actual, /*MarkEOLs=*/false);
+ EXPECT_EQ(OutputSize, Actual.size());
+ for (unsigned I = 0, E = Actual.size(); I != E; ++I) {
+ if (I < OutputSize)
+ EXPECT_STREQ(Output[I], Actual[I]);
}
-};
+}
TEST(CommandLineTest, TokenizeGNUCommandLine) {
const char *Input = "foo\\ bar \"foo bar\" \'foo bar\' 'foo\\\\bar' "
const char *const Output[] = { "foo bar", "foo bar", "foo bar", "foo\\bar",
"foobarbaz", "C:\\src\\foo.cpp",
"C:\\src\\foo.cpp" };
- SmallVector<const char *, 0> Actual;
- StrDupSaver Saver;
- cl::TokenizeGNUCommandLine(Input, Saver, Actual);
- EXPECT_EQ(array_lengthof(Output), Actual.size());
- for (unsigned I = 0, E = Actual.size(); I != E; ++I) {
- if (I < array_lengthof(Output))
- EXPECT_STREQ(Output[I], Actual[I]);
- free(const_cast<char *>(Actual[I]));
+ testCommandLineTokenizer(cl::TokenizeGNUCommandLine, Input, Output,
+ array_lengthof(Output));
+}
+
+TEST(CommandLineTest, TokenizeWindowsCommandLine) {
+ const char *Input = "a\\b c\\\\d e\\\\\"f g\" h\\\"i j\\\\\\\"k \"lmn\" o pqr "
+ "\"st \\\"u\" \\v";
+ const char *const Output[] = { "a\\b", "c\\\\d", "e\\f g", "h\"i", "j\\\"k",
+ "lmn", "o", "pqr", "st \"u", "\\v" };
+ testCommandLineTokenizer(cl::TokenizeWindowsCommandLine, Input, Output,
+ array_lengthof(Output));
+}
+
+TEST(CommandLineTest, AliasesWithArguments) {
+ static const size_t ARGC = 3;
+ const char *const Inputs[][ARGC] = {
+ { "-tool", "-actual=x", "-extra" },
+ { "-tool", "-actual", "x" },
+ { "-tool", "-alias=x", "-extra" },
+ { "-tool", "-alias", "x" }
+ };
+
+ for (size_t i = 0, e = array_lengthof(Inputs); i < e; ++i) {
+ StackOption<std::string> Actual("actual");
+ StackOption<bool> Extra("extra");
+ StackOption<std::string> Input(cl::Positional);
+
+ cl::alias Alias("alias", llvm::cl::aliasopt(Actual));
+
+ cl::ParseCommandLineOptions(ARGC, Inputs[i]);
+ EXPECT_EQ("x", Actual);
+ EXPECT_EQ(0, Input.getNumOccurrences());
+
+ Alias.removeArgument();
}
}
+void testAliasRequired(int argc, const char *const *argv) {
+ StackOption<std::string> Option("option", cl::Required);
+ cl::alias Alias("o", llvm::cl::aliasopt(Option));
+
+ cl::ParseCommandLineOptions(argc, argv);
+ EXPECT_EQ("x", Option);
+ EXPECT_EQ(1, Option.getNumOccurrences());
+
+ Alias.removeArgument();
+}
+
+TEST(CommandLineTest, AliasRequired) {
+ const char *opts1[] = { "-tool", "-option=x" };
+ const char *opts2[] = { "-tool", "-o", "x" };
+ testAliasRequired(array_lengthof(opts1), opts1);
+ testAliasRequired(array_lengthof(opts2), opts2);
+}
+
+TEST(CommandLineTest, HideUnrelatedOptions) {
+ StackOption<int> TestOption1("hide-option-1");
+ StackOption<int> TestOption2("hide-option-2", cl::cat(TestCategory));
+
+ cl::HideUnrelatedOptions(TestCategory);
+
+ ASSERT_EQ(cl::ReallyHidden, TestOption1.getOptionHiddenFlag())
+ << "Failed to hide extra option.";
+ ASSERT_EQ(cl::NotHidden, TestOption2.getOptionHiddenFlag())
+ << "Hid extra option that should be visable.";
+
+ StringMap<cl::Option *> &Map = cl::getRegisteredOptions();
+ ASSERT_EQ(cl::NotHidden, Map["help"]->getOptionHiddenFlag())
+ << "Hid default option that should be visable.";
+}
+
+cl::OptionCategory TestCategory2("Test Options set 2", "Description");
+
+TEST(CommandLineTest, HideUnrelatedOptionsMulti) {
+ StackOption<int> TestOption1("multi-hide-option-1");
+ StackOption<int> TestOption2("multi-hide-option-2", cl::cat(TestCategory));
+ StackOption<int> TestOption3("multi-hide-option-3", cl::cat(TestCategory2));
+
+ const cl::OptionCategory *VisibleCategories[] = {&TestCategory,
+ &TestCategory2};
+
+ cl::HideUnrelatedOptions(makeArrayRef(VisibleCategories));
+
+ ASSERT_EQ(cl::ReallyHidden, TestOption1.getOptionHiddenFlag())
+ << "Failed to hide extra option.";
+ ASSERT_EQ(cl::NotHidden, TestOption2.getOptionHiddenFlag())
+ << "Hid extra option that should be visable.";
+ ASSERT_EQ(cl::NotHidden, TestOption3.getOptionHiddenFlag())
+ << "Hid extra option that should be visable.";
+
+ StringMap<cl::Option *> &Map = cl::getRegisteredOptions();
+ ASSERT_EQ(cl::NotHidden, Map["help"]->getOptionHiddenFlag())
+ << "Hid default option that should be visable.";
+}
+
} // anonymous namespace