You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
149 lines
4.7 KiB
149 lines
4.7 KiB
5 years ago
|
/* Distributed under the OSI-approved BSD 3-Clause License. See accompanying
|
||
|
file Copyright.txt or https://cmake.org/licensing for details. */
|
||
|
|
||
|
#include "cmArgumentParser.h"
|
||
|
|
||
|
#include "cm_static_string_view.hxx"
|
||
|
#include "cm_string_view.hxx"
|
||
|
|
||
|
#include <initializer_list>
|
||
|
#include <iostream>
|
||
|
#include <string>
|
||
|
#include <vector>
|
||
|
|
||
|
namespace {
|
||
|
|
||
|
struct Result
|
||
|
{
|
||
|
bool Option1 = false;
|
||
|
bool Option2 = false;
|
||
|
|
||
|
std::string String1;
|
||
|
std::string String2;
|
||
|
|
||
|
std::vector<std::string> List1;
|
||
|
std::vector<std::string> List2;
|
||
|
std::vector<std::string> List3;
|
||
|
|
||
|
std::vector<std::vector<std::string>> Multi1;
|
||
|
std::vector<std::vector<std::string>> Multi2;
|
||
|
std::vector<std::vector<std::string>> Multi3;
|
||
|
};
|
||
|
|
||
|
std::initializer_list<cm::string_view> const args = {
|
||
|
/* clang-format off */
|
||
|
"OPTION_1", // option
|
||
|
"STRING_1", // string arg missing value
|
||
|
"STRING_2", "foo", "bar", // string arg + unparsed value
|
||
|
"LIST_1", // list arg missing values
|
||
|
"LIST_2", "foo", "bar", // list arg with 2 elems
|
||
|
"LIST_3", "bar", // list arg ...
|
||
|
"LIST_3", "foo", // ... with continuation
|
||
|
"MULTI_2", // multi list with 0 lists
|
||
|
"MULTI_3", "foo", "bar", // multi list with first list with two elems
|
||
|
"MULTI_3", "bar", "foo", // multi list with second list with two elems
|
||
|
/* clang-format on */
|
||
|
};
|
||
|
|
||
|
bool verifyResult(Result const& result,
|
||
|
std::vector<std::string> const& unparsedArguments,
|
||
|
std::vector<std::string> const& keywordsMissingValue)
|
||
|
{
|
||
|
static std::vector<std::string> const foobar = { "foo", "bar" };
|
||
|
static std::vector<std::string> const barfoo = { "bar", "foo" };
|
||
|
static std::vector<std::string> const missing = { "STRING_1", "LIST_1" };
|
||
|
|
||
|
#define ASSERT_TRUE(x) \
|
||
|
do { \
|
||
|
if (!(x)) { \
|
||
|
std::cout << "ASSERT_TRUE(" #x ") failed on line " << __LINE__ << "\n"; \
|
||
|
return false; \
|
||
|
} \
|
||
|
} while (false)
|
||
|
|
||
|
ASSERT_TRUE(result.Option1);
|
||
|
ASSERT_TRUE(!result.Option2);
|
||
|
|
||
|
ASSERT_TRUE(result.String1.empty());
|
||
|
ASSERT_TRUE(result.String2 == "foo");
|
||
|
|
||
|
ASSERT_TRUE(result.List1.empty());
|
||
|
ASSERT_TRUE(result.List2 == foobar);
|
||
|
ASSERT_TRUE(result.List3 == barfoo);
|
||
|
|
||
|
ASSERT_TRUE(result.Multi1.empty());
|
||
|
ASSERT_TRUE(result.Multi2.size() == 1);
|
||
|
ASSERT_TRUE(result.Multi2[0].empty());
|
||
|
ASSERT_TRUE(result.Multi3.size() == 2);
|
||
|
ASSERT_TRUE(result.Multi3[0] == foobar);
|
||
|
ASSERT_TRUE(result.Multi3[1] == barfoo);
|
||
|
|
||
|
ASSERT_TRUE(unparsedArguments.size() == 1);
|
||
|
ASSERT_TRUE(unparsedArguments[0] == "bar");
|
||
|
ASSERT_TRUE(keywordsMissingValue == missing);
|
||
|
|
||
|
return true;
|
||
|
}
|
||
|
|
||
|
bool testArgumentParserDynamic()
|
||
|
{
|
||
|
Result result;
|
||
|
std::vector<std::string> unparsedArguments;
|
||
|
std::vector<std::string> keywordsMissingValue;
|
||
|
|
||
|
cmArgumentParser<void>{}
|
||
|
.Bind("OPTION_1"_s, result.Option1)
|
||
|
.Bind("OPTION_2"_s, result.Option2)
|
||
|
.Bind("STRING_1"_s, result.String1)
|
||
|
.Bind("STRING_2"_s, result.String2)
|
||
|
.Bind("LIST_1"_s, result.List1)
|
||
|
.Bind("LIST_2"_s, result.List2)
|
||
|
.Bind("LIST_3"_s, result.List3)
|
||
|
.Bind("MULTI_1"_s, result.Multi1)
|
||
|
.Bind("MULTI_2"_s, result.Multi2)
|
||
|
.Bind("MULTI_3"_s, result.Multi3)
|
||
|
.Parse(args, &unparsedArguments, &keywordsMissingValue);
|
||
|
|
||
|
return verifyResult(result, unparsedArguments, keywordsMissingValue);
|
||
|
}
|
||
|
|
||
|
bool testArgumentParserStatic()
|
||
|
{
|
||
|
static auto const parser = //
|
||
|
cmArgumentParser<Result>{}
|
||
|
.Bind("OPTION_1"_s, &Result::Option1)
|
||
|
.Bind("OPTION_2"_s, &Result::Option2)
|
||
|
.Bind("STRING_1"_s, &Result::String1)
|
||
|
.Bind("STRING_2"_s, &Result::String2)
|
||
|
.Bind("LIST_1"_s, &Result::List1)
|
||
|
.Bind("LIST_2"_s, &Result::List2)
|
||
|
.Bind("LIST_3"_s, &Result::List3)
|
||
|
.Bind("MULTI_1"_s, &Result::Multi1)
|
||
|
.Bind("MULTI_2"_s, &Result::Multi2)
|
||
|
.Bind("MULTI_3"_s, &Result::Multi3);
|
||
|
|
||
|
std::vector<std::string> unparsedArguments;
|
||
|
std::vector<std::string> keywordsMissingValue;
|
||
|
Result const result =
|
||
|
parser.Parse(args, &unparsedArguments, &keywordsMissingValue);
|
||
|
|
||
|
return verifyResult(result, unparsedArguments, keywordsMissingValue);
|
||
|
}
|
||
|
|
||
|
} // namespace
|
||
|
|
||
|
int testArgumentParser(int /*unused*/, char* /*unused*/ [])
|
||
|
{
|
||
|
if (!testArgumentParserDynamic()) {
|
||
|
std::cout << "While executing testArgumentParserDynamic().\n";
|
||
|
return -1;
|
||
|
}
|
||
|
|
||
|
if (!testArgumentParserStatic()) {
|
||
|
std::cout << "While executing testArgumentParserStatic().\n";
|
||
|
return -1;
|
||
|
}
|
||
|
|
||
|
return 0;
|
||
|
}
|