2022-03-16 14:20:26 +11:00
|
|
|
#include <cruft/util/tap.hpp>
|
|
|
|
#include <cruft/util/cmdopt2/parser.hpp>
|
2022-03-18 13:26:10 +11:00
|
|
|
#include <cruft/util/cmdopt2/args.hpp>
|
2022-03-16 14:20:26 +11:00
|
|
|
|
2024-10-16 12:19:35 +11:00
|
|
|
#include <fmt/ranges.h>
|
2022-03-16 14:20:26 +11:00
|
|
|
|
|
|
|
|
|
|
|
///////////////////////////////////////////////////////////////////////////////
|
|
|
|
static void
|
|
|
|
test_combinations (cruft::TAP::logger &tap)
|
|
|
|
{
|
|
|
|
static const struct {
|
|
|
|
std::vector<char const*> args;
|
|
|
|
int foo;
|
|
|
|
std::optional<float> bar;
|
|
|
|
std::string qux;
|
|
|
|
bool verbose;
|
|
|
|
} TESTS[] = {
|
|
|
|
{
|
|
|
|
.args = { "cmd", "-f", "1", "--bar", "2", "val" },
|
|
|
|
.foo = 1,
|
|
|
|
.bar = 2,
|
|
|
|
.qux = "val",
|
|
|
|
.verbose = false,
|
|
|
|
},
|
|
|
|
{
|
|
|
|
.args = { "cmd", "--bar", "2", "-f", "1", "val" },
|
|
|
|
.foo = 1,
|
|
|
|
.bar = 2,
|
|
|
|
.qux = "val",
|
|
|
|
.verbose = false,
|
|
|
|
},
|
|
|
|
{
|
|
|
|
.args = { "cmd", "--bar", "2", "val", "-f", "1", },
|
|
|
|
.foo = 1,
|
|
|
|
.bar = 2,
|
|
|
|
.qux = "val",
|
|
|
|
.verbose = false,
|
|
|
|
},
|
|
|
|
{
|
|
|
|
.args = { "cmd", "-v", "--bar", "2", "val", "-f", "1", },
|
|
|
|
.foo = 1,
|
|
|
|
.bar = 2,
|
|
|
|
.qux = "val",
|
|
|
|
.verbose = true,
|
|
|
|
},
|
|
|
|
{
|
|
|
|
.args = { "cmd", "--bar", "2", "val", "-f", "1", },
|
|
|
|
.foo = 1,
|
|
|
|
.bar = 2,
|
|
|
|
.qux = "val",
|
|
|
|
.verbose = false,
|
|
|
|
},
|
|
|
|
{
|
|
|
|
.args = { "cmd", "val", "--bar", "2", "-f", "1", },
|
|
|
|
.foo = 1,
|
|
|
|
.bar = 2,
|
|
|
|
.qux = "val",
|
|
|
|
.verbose = false,
|
|
|
|
},
|
|
|
|
{
|
|
|
|
.args = { "cmd", "val", "-v", "-f", "1", },
|
|
|
|
.foo = 1,
|
|
|
|
.bar = {},
|
|
|
|
.qux = "val",
|
|
|
|
.verbose = true,
|
|
|
|
},
|
|
|
|
{
|
|
|
|
.args = { "cmd", "val", "-f", "1", },
|
|
|
|
.foo = 1,
|
|
|
|
.bar = {},
|
|
|
|
.qux = "val",
|
|
|
|
.verbose = true,
|
|
|
|
},
|
|
|
|
};
|
|
|
|
|
|
|
|
int foo;
|
|
|
|
std::optional<float> bar;
|
|
|
|
std::string qux;
|
|
|
|
bool verbose;
|
|
|
|
|
|
|
|
using namespace cruft::cmdopt2;
|
2022-03-21 11:50:39 +11:00
|
|
|
parser p ("test suite");
|
2022-03-16 14:20:26 +11:00
|
|
|
|
2022-03-18 16:23:17 +11:00
|
|
|
p.add (keyword ("foo").flag ().flag ('f').bind (foo));
|
|
|
|
p.add (keyword ("bar").bind (bar));
|
|
|
|
p.add (positional ("qux").bind (qux));
|
|
|
|
p.add (keyword ("verbose").flag ().flag ('v').present (verbose));
|
2022-03-16 14:20:26 +11:00
|
|
|
|
|
|
|
for (auto const &t: TESTS) {
|
|
|
|
foo = decltype(foo) {};
|
|
|
|
bar = decltype(bar) {};
|
|
|
|
qux = decltype(qux) {};
|
|
|
|
verbose = false;
|
|
|
|
|
2022-03-18 16:04:45 +11:00
|
|
|
auto const consumed = p.parse (int (t.args.size ()), t.args.data ());
|
2022-03-16 14:20:26 +11:00
|
|
|
|
|
|
|
tap.expect (
|
2022-03-18 16:04:45 +11:00
|
|
|
consumed == int (t.args.size ())
|
|
|
|
and foo == t.foo
|
|
|
|
and bar == t.bar
|
|
|
|
and qux == t.qux,
|
2022-03-16 14:20:26 +11:00
|
|
|
"{}", fmt::join (t.args.begin (), t.args.end (), " ")
|
|
|
|
);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
///////////////////////////////////////////////////////////////////////////////
|
|
|
|
static void test_presence (cruft::TAP::logger &tap)
|
|
|
|
{
|
|
|
|
static const struct {
|
|
|
|
std::vector<char const*> args;
|
|
|
|
int count;
|
|
|
|
bool present;
|
|
|
|
} TESTS[] = {
|
|
|
|
{
|
|
|
|
.args = { "cmd", "-v", },
|
|
|
|
.count = 1,
|
|
|
|
.present = false,
|
|
|
|
},
|
|
|
|
{
|
|
|
|
.args = { "cmd", "-vvv", },
|
|
|
|
.count = 3,
|
|
|
|
.present = false,
|
|
|
|
},
|
|
|
|
{
|
|
|
|
.args = { "cmd", "-v", "-vv"},
|
|
|
|
.count = 3,
|
|
|
|
.present = false,
|
|
|
|
},
|
|
|
|
{
|
|
|
|
.args = { "cmd", },
|
|
|
|
.count = 0,
|
|
|
|
.present = false,
|
|
|
|
},
|
|
|
|
{
|
|
|
|
.args = { "cmd", "-p"},
|
|
|
|
.count = 0,
|
|
|
|
.present = true,
|
|
|
|
},
|
|
|
|
{
|
|
|
|
.args = { "cmd", "-ppp"},
|
|
|
|
.count = 0,
|
|
|
|
.present = true,
|
|
|
|
},
|
|
|
|
{
|
|
|
|
.args = { "cmd", "-p", "-p"},
|
|
|
|
.count = 0,
|
|
|
|
.present = true,
|
|
|
|
},
|
|
|
|
{
|
|
|
|
.args = { "cmd", "-p", "-v", "-p"},
|
|
|
|
.count = 1,
|
|
|
|
.present = true,
|
|
|
|
},
|
|
|
|
{
|
|
|
|
.args = { "cmd", "-p", "-v", "-p", "-v"},
|
|
|
|
.count = 2,
|
|
|
|
.present = true,
|
|
|
|
},
|
|
|
|
};
|
|
|
|
|
|
|
|
int count;
|
|
|
|
bool present;
|
|
|
|
|
|
|
|
using namespace cruft::cmdopt2;
|
|
|
|
|
2022-03-21 11:50:39 +11:00
|
|
|
parser p ("test suite");
|
2022-03-18 16:23:17 +11:00
|
|
|
p.add (keyword ("verbose").flag ().flag ('v').count (count));
|
|
|
|
p.add (keyword ("present").flag ().flag ('p').present (present));
|
2022-03-16 14:20:26 +11:00
|
|
|
|
|
|
|
for (auto const &t: TESTS) {
|
|
|
|
count = 0;
|
|
|
|
present = false;
|
|
|
|
|
2022-03-18 16:04:45 +11:00
|
|
|
auto const consumed = p.parse (int (t.args.size ()), t.args.data ());
|
2022-03-16 14:20:26 +11:00
|
|
|
|
|
|
|
tap.expect (
|
2022-03-18 16:04:45 +11:00
|
|
|
consumed == int (t.args.size ())
|
|
|
|
and count == t.count
|
|
|
|
and present == t.present,
|
2022-03-16 14:20:26 +11:00
|
|
|
"{}", fmt::join (t.args.begin (), t.args.end (), " ")
|
|
|
|
);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2022-03-18 16:04:45 +11:00
|
|
|
///////////////////////////////////////////////////////////////////////////////
|
|
|
|
static void
|
|
|
|
test_required (cruft::TAP::logger &tap)
|
|
|
|
{
|
|
|
|
static const struct {
|
|
|
|
std::vector<char const*> args;
|
|
|
|
bool success;
|
|
|
|
} TESTS[] = {
|
|
|
|
{ .args = { "cmd", }, .success = false },
|
|
|
|
{ .args = { "cmd", "-y" }, .success = true },
|
|
|
|
{ .args = { "cmd", "-n" }, .success = false },
|
|
|
|
};
|
|
|
|
|
|
|
|
using namespace cruft::cmdopt2;
|
|
|
|
|
2022-03-21 11:50:39 +11:00
|
|
|
parser p ("test suite");
|
2022-03-18 16:23:17 +11:00
|
|
|
p.add (keyword ("y").flag ('y').required (true ).ignore ());
|
|
|
|
p.add (keyword ("n").flag ('n').required (false).ignore ());
|
2022-03-18 16:04:45 +11:00
|
|
|
|
|
|
|
for (auto const &t: TESTS) {
|
|
|
|
bool success;
|
|
|
|
try {
|
|
|
|
auto const consumed = p.parse (int (t.args.size ()), t.args.data ());
|
|
|
|
bool const completed = consumed == int (t.args.size ());
|
|
|
|
success = completed == t.success;
|
|
|
|
} catch (...) {
|
|
|
|
success = not t.success;
|
|
|
|
}
|
|
|
|
tap.expect (
|
|
|
|
success,
|
|
|
|
"{}",
|
|
|
|
fmt::join (t.args.begin (), t.args.end (), " ")
|
|
|
|
);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2022-03-21 11:48:24 +11:00
|
|
|
///////////////////////////////////////////////////////////////////////////////
|
|
|
|
static void
|
|
|
|
test_repeated (cruft::TAP::logger &tap)
|
|
|
|
{
|
|
|
|
static const struct {
|
|
|
|
std::vector<char const*> args;
|
|
|
|
std::vector<int> values;
|
|
|
|
} TESTS[] = {
|
|
|
|
{ .args = { "cmd" }, .values = { } },
|
|
|
|
{ .args = { "cmd", "1", }, .values = { 1, } },
|
|
|
|
{ .args = { "cmd", "1", "1", }, .values = { 1, 1, } },
|
|
|
|
{ .args = { "cmd", "-v", "1", }, .values = { 1, } },
|
|
|
|
{ .args = { "cmd", "-v", "1", "-v", "1"}, .values = { 1, 1 } },
|
|
|
|
{ .args = { "cmd", "--foo", "1", }, .values = { 1, } },
|
|
|
|
{ .args = { "cmd", "--foo", "1", "--foo", "1"}, .values = { 1, 1, } },
|
|
|
|
};
|
|
|
|
|
|
|
|
std::vector<int> values;
|
|
|
|
|
|
|
|
using namespace cruft::cmdopt2;
|
|
|
|
parser p ("test suite");
|
|
|
|
p.add (keyword ("value").flag ('v').repeat (true).bind (values));
|
|
|
|
p.add (keyword ("foo").repeat (true).bind (values));
|
|
|
|
p.add (positional ("var").repeat (true).bind (values));
|
|
|
|
|
|
|
|
for (auto const &t: TESTS) {
|
|
|
|
values.clear ();
|
|
|
|
|
|
|
|
auto const consumed = p.parse (int (t.args.size ()), t.args.data ());
|
|
|
|
tap.expect (
|
|
|
|
consumed == int (t.args.size ())
|
|
|
|
and values == t.values,
|
|
|
|
"{}",
|
|
|
|
fmt::join (t.args.begin (), t.args.end (), " ")
|
|
|
|
);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2022-05-24 15:09:49 +10:00
|
|
|
///////////////////////////////////////////////////////////////////////////////
|
|
|
|
static void
|
|
|
|
test_bind (cruft::TAP::logger &tap)
|
|
|
|
{
|
|
|
|
static constexpr
|
|
|
|
char const* VALUES[] = {
|
|
|
|
"one",
|
|
|
|
"two",
|
|
|
|
"three"
|
|
|
|
};
|
|
|
|
|
|
|
|
std::vector<char const*> values;
|
|
|
|
|
|
|
|
using namespace cruft::cmdopt2;
|
|
|
|
parser p ("test suite");
|
|
|
|
p.add (
|
|
|
|
keyword ("value")
|
|
|
|
.flag ('v')
|
|
|
|
.repeat (true)
|
|
|
|
.bind ([&] (char const *str) { values.push_back (str); })
|
|
|
|
);
|
|
|
|
|
|
|
|
char const *argv[] = { "./cmd", "--value", VALUES[0], "--value", VALUES[1], "--value", VALUES[2] };
|
|
|
|
auto const consumed = p.parse (std::ssize (argv), argv);
|
|
|
|
|
|
|
|
tap.expect_eq (consumed, std::ssize (argv), "bound function: consumed");
|
|
|
|
|
|
|
|
tap.expect (
|
|
|
|
std::equal (
|
|
|
|
std::begin (values),
|
|
|
|
std::end (values),
|
|
|
|
std::begin (VALUES),
|
|
|
|
std::end (VALUES)
|
|
|
|
),
|
|
|
|
"bound function: values"
|
|
|
|
);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2022-03-16 14:20:26 +11:00
|
|
|
///////////////////////////////////////////////////////////////////////////////
|
|
|
|
int main ()
|
|
|
|
{
|
|
|
|
cruft::TAP::logger tap;
|
|
|
|
test_combinations (tap);
|
|
|
|
test_presence (tap);
|
2022-03-18 16:04:45 +11:00
|
|
|
test_required (tap);
|
2022-03-21 11:48:24 +11:00
|
|
|
test_repeated (tap);
|
2022-05-24 15:09:49 +10:00
|
|
|
test_bind (tap);
|
2022-03-16 14:20:26 +11:00
|
|
|
return tap.status ();
|
|
|
|
}
|