#define CATCH_CONFIG_MAIN
#include <catch2/catch_test_macros.hpp>
#include <charconv>
#include <filesystem>
#include <ranges>
namespace {
constexpr const char *const MYARGS[] = {"FOO", "X", "Y", "Z", "AAA"};
}
TEST_CASE("Null parse", "[Z]")
{
static constinit const char *const ARGV[]{"foo"};
}
TEST_CASE("Null help", "[Z]")
{
static constinit const char *const ARGV[]{"foo", "-h"};
REQUIRE(!ret);
CHECK(ret.message() ==
"USAGE: foo [-h]\n"
"\n"
"VALID FLAGS:\n"
" -h, --help\n"
"\tDisplay this help and exit\n");
}
TEST_CASE("Scenario: position_args() with one argument", "[S][I]")
{
REQUIRE(!ezargs.
parse(1, MYARGS));
REQUIRE(!ezargs.
parse(2, MYARGS));
REQUIRE(!ezargs.
parse(3, MYARGS));
REQUIRE(ezargs.
parse(4, MYARGS));
REQUIRE(!ezargs.
parse(5, MYARGS));
}
TEST_CASE("Scenario: position_args() with two argument", "[S][I]")
{
ezargs.
position_args(std::array{
"a",
"b",
"c"}, std::array{1,2});
REQUIRE(!ezargs.
parse(1, MYARGS));
REQUIRE(ezargs.
parse(2, MYARGS));
REQUIRE(ezargs.
parse(3, MYARGS));
REQUIRE(ezargs.
parse(4, MYARGS));
REQUIRE(!ezargs.
parse(5, MYARGS));
}
TEST_CASE("Scenario: add_flag() with trigger only", "[S][I]")
{
ezargs.
add_flag(
"foo",
'f',
"123456abcdef", []{});
}
TEST_CASE("Scenario: argv[0] with -E -h", "[S]")
{
.position_args(std::array{"eeny"});
.position_args(std::array{"meeny"});
ezargs.
add_flag(
"eureka",
'E',
"123456abcdef", []{});
const std::string arg0 = std::filesystem::current_path() / "test1.exe";
const char *const argv[]{arg0.c_str(), "-h"};
auto ret = ezargs.
parse(2, argv);
REQUIRE(!ret);
CHECK(ret.message() ==
"USAGE: test1.exe (foo|bar) ... [-E] [-h]\n"
"VALID ACTIONS:\n"
" foo\n"
" bar\n");
}
TEST_CASE("Scenario: Subcommand help", "[S]")
{
.position_args(std::array{"eeny"});
.position_args(std::array{"meeny"});
const std::string arg0 = std::filesystem::current_path() / "test1.exe";
const char *const argv[]{arg0.c_str(), "foo", "-h"};
auto ret = ezargs.
parse(3, argv);
REQUIRE(!ret);
std::istringstream in{ret.message()};
std::string line;
REQUIRE(std::getline(in, line));
CHECK(line == "USAGE: test1.exe foo <eeny> [-h]");
}
TEST_CASE("Scenario: Parse negative number as flag value", "[S]")
{
double x{};
ezargs.
add_flag(
'x',
"foobar", [&](
auto v){
std::from_chars(v.data(), v.data()+v.size(), x);
});
const std::string arg0 = std::filesystem::current_path() / "test1.exe";
const char *argv[]{arg0.c_str(), "-x", "-.5"};
REQUIRE(ezargs.
parse(3, argv));
CHECK(x == -.5);
ezargs.
add_flag(
'.',
"contrived", []{});
x = 0;
REQUIRE(ezargs.
parse(3, argv));
CHECK(x == -.5);
ezargs.
add_flag(
'5',
"contrived", []{});
CHECK(!ezargs.
parse(3, argv));
std::string s6;
ezargs.
add_flag(
'6',
"contrived", [&](
auto v){ s6 = v; });
argv[2] = "-.6";
x = 0;
REQUIRE(ezargs.
parse(3, argv));
CHECK(x == -.6);
}
C_EZArgs & add_subcommand(const std::string &name, std::invocable<> auto onParsed, const std::string &description={})
auto parsed_position_argc() const
C_ErrorOrIndex parse(std::integral auto argc, const char *const argv[]) const
C_EZArgs & add_flag(std::string_view name, char short_name, std::string_view description, std::invocable<> auto &&trigger, std::invocable< std::string_view > auto &&parse)
C_EZArgs & position_args(const std::ranges::forward_range auto &arg_names, const std::ranges::forward_range auto &count_optionals, bool unlimited=false)