/* 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;
}