2024-05-29 16:29:08 +10:00
|
|
|
#include <cruft/util/cmdopt.hpp>
|
2015-06-30 22:09:35 +10:00
|
|
|
|
2024-05-29 16:29:08 +10:00
|
|
|
#include <cruft/util/tap.hpp>
|
|
|
|
#include <cruft/util/types.hpp>
|
|
|
|
#include <cruft/util/maths.hpp>
|
2015-06-30 22:09:35 +10:00
|
|
|
|
2016-05-12 17:31:33 +10:00
|
|
|
#include <array>
|
|
|
|
|
2015-06-30 22:09:35 +10:00
|
|
|
|
2016-03-15 13:55:49 +11:00
|
|
|
///////////////////////////////////////////////////////////////////////////////
|
2015-06-30 22:09:35 +10:00
|
|
|
// Check that null options don't strhrow anything
|
2016-03-15 13:55:49 +11:00
|
|
|
static
|
2015-06-30 22:09:35 +10:00
|
|
|
void
|
2018-08-05 14:42:02 +10:00
|
|
|
test_null (cruft::TAP::logger &tap)
|
2015-07-02 17:03:56 +10:00
|
|
|
{
|
2018-08-05 14:42:02 +10:00
|
|
|
cruft::cmdopt::parser p;
|
|
|
|
p.add<cruft::cmdopt::option::null> ('n', "null", "testing null option");
|
2015-06-30 22:09:35 +10:00
|
|
|
|
|
|
|
static const char *argv1[] = { "./foo", "-n", "foo" };
|
2015-07-02 17:03:56 +10:00
|
|
|
tap.expect_nothrow ([&] () {
|
2016-11-17 18:06:39 +11:00
|
|
|
p.scan (std::size (argv1), argv1);
|
2015-07-21 03:17:20 +10:00
|
|
|
}, "nothrow null short form");
|
2015-06-30 22:09:35 +10:00
|
|
|
|
|
|
|
static const char *argv2[] = { "./foo", "--null", "foo" };
|
2015-07-02 17:03:56 +10:00
|
|
|
tap.expect_nothrow ([&] () {
|
2016-11-17 18:06:39 +11:00
|
|
|
p.scan (std::size (argv2), argv2);
|
2015-07-21 03:17:20 +10:00
|
|
|
}, "nothrow null long form");
|
2015-06-30 22:09:35 +10:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2016-03-15 13:55:49 +11:00
|
|
|
///////////////////////////////////////////////////////////////////////////////
|
2015-06-30 22:09:35 +10:00
|
|
|
// Check if presence options can be used successfully
|
2016-03-15 13:55:49 +11:00
|
|
|
static
|
2015-06-30 22:09:35 +10:00
|
|
|
void
|
2018-08-05 14:42:02 +10:00
|
|
|
test_present (cruft::TAP::logger &tap)
|
2015-07-02 17:03:56 +10:00
|
|
|
{
|
2018-08-05 14:42:02 +10:00
|
|
|
cruft::cmdopt::parser p;
|
2015-06-30 22:09:35 +10:00
|
|
|
bool is_present;
|
2015-07-02 17:03:56 +10:00
|
|
|
|
2018-08-05 14:42:02 +10:00
|
|
|
p.add<cruft::cmdopt::option::present> ('p', "present", "option is present", is_present);
|
2015-06-30 22:09:35 +10:00
|
|
|
|
|
|
|
// Short option form
|
2015-07-02 17:03:56 +10:00
|
|
|
{
|
|
|
|
static const char *argv1[] = { "./foo", "-p" };
|
|
|
|
is_present = false;
|
2016-11-17 18:06:39 +11:00
|
|
|
p.scan (std::size (argv1), argv1);
|
2015-07-02 17:03:56 +10:00
|
|
|
tap.expect (is_present, "presence short form");
|
|
|
|
}
|
2015-06-30 22:09:35 +10:00
|
|
|
|
|
|
|
// Long option form
|
2015-07-02 17:03:56 +10:00
|
|
|
{
|
|
|
|
static const char *argv2[] = { "./foo", "--present" };
|
|
|
|
is_present = false;
|
2016-11-17 18:06:39 +11:00
|
|
|
p.scan (std::size (argv2), argv2);
|
2015-07-02 17:03:56 +10:00
|
|
|
tap.expect (is_present, "presence long form");
|
|
|
|
}
|
2015-06-30 22:09:35 +10:00
|
|
|
|
|
|
|
// Check that value is reset from true if not present
|
2015-07-02 17:03:56 +10:00
|
|
|
{
|
|
|
|
static const char *argv3[] = { "./foo" };
|
|
|
|
is_present = true;
|
2016-11-17 18:06:39 +11:00
|
|
|
p.scan (std::size (argv3), argv3);
|
2015-07-02 17:03:56 +10:00
|
|
|
tap.expect (!is_present, "presence null");
|
|
|
|
}
|
2015-06-30 22:09:35 +10:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2016-03-15 13:55:49 +11:00
|
|
|
///////////////////////////////////////////////////////////////////////////////
|
2015-06-30 22:09:35 +10:00
|
|
|
// Check all forms of boolean inputs
|
2016-03-15 13:55:49 +11:00
|
|
|
static
|
2015-06-30 22:09:35 +10:00
|
|
|
void
|
2018-08-05 14:42:02 +10:00
|
|
|
test_bool (cruft::TAP::logger &tap)
|
2015-07-02 17:03:56 +10:00
|
|
|
{
|
2018-08-05 14:42:02 +10:00
|
|
|
cruft::cmdopt::parser p;
|
2015-06-30 22:09:35 +10:00
|
|
|
bool value = false;
|
|
|
|
|
2018-08-05 14:42:02 +10:00
|
|
|
p.add<cruft::cmdopt::option::value<bool>> ('b', "bool", "testing boolean actions", value);
|
2015-06-30 22:09:35 +10:00
|
|
|
|
|
|
|
// List all legal forms of positive or negative boolean values
|
|
|
|
std::array<const char*, 3> argv { "./foo", "-b", NULL };
|
|
|
|
static const char *positive[] = { "1", "true", "yes" };
|
|
|
|
static const char *negative[] = { "0", "false", "no" };
|
|
|
|
|
|
|
|
// For each boolean value, ensure that it returns as expected
|
|
|
|
for (auto i: positive) {
|
|
|
|
argv[2] = i;
|
|
|
|
p.scan (argv.size (), argv.data ());
|
2021-04-13 16:05:08 +10:00
|
|
|
tap.expect_eq (value, true, "read bool, {:s}", i);
|
2015-06-30 22:09:35 +10:00
|
|
|
}
|
|
|
|
|
|
|
|
for (auto i: negative) {
|
|
|
|
argv[2] = i;
|
|
|
|
p.scan (argv.size (), argv.data ());
|
2021-04-13 16:05:08 +10:00
|
|
|
tap.expect_eq (value, false, "read bool, {:s}", i);
|
2015-06-30 22:09:35 +10:00
|
|
|
}
|
|
|
|
|
|
|
|
// Check that invalid forms of boolean all throw exceptions
|
|
|
|
const char* invalid[] = { "foo", "null" };
|
|
|
|
|
|
|
|
for (auto i: invalid) {
|
|
|
|
argv[2] = i;
|
2018-08-05 14:42:02 +10:00
|
|
|
tap.expect_throw<cruft::cmdopt::invalid_value> ([&] () {
|
2015-07-02 17:03:56 +10:00
|
|
|
p.scan (argv.size (), argv.data ());
|
2021-04-13 16:05:08 +10:00
|
|
|
}, "invalid bool, {:s}", i);
|
2015-06-30 22:09:35 +10:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2016-03-15 13:55:49 +11:00
|
|
|
///////////////////////////////////////////////////////////////////////////////
|
2015-06-30 22:09:35 +10:00
|
|
|
template<typename T>
|
2016-03-15 13:55:49 +11:00
|
|
|
static
|
2015-06-30 22:09:35 +10:00
|
|
|
void
|
2018-08-05 14:42:02 +10:00
|
|
|
test_numeric (cruft::TAP::logger &tap)
|
2015-07-02 17:03:56 +10:00
|
|
|
{
|
2018-08-05 14:42:02 +10:00
|
|
|
cruft::cmdopt::parser p;
|
2015-06-30 22:09:35 +10:00
|
|
|
|
|
|
|
T value;
|
2018-08-05 14:42:02 +10:00
|
|
|
p.add<cruft::cmdopt::option::value<T>> ('t', "type", "testing type option", value);
|
2015-06-30 22:09:35 +10:00
|
|
|
|
|
|
|
T values[] = {
|
|
|
|
// TODO: Enable minimum value testing. Currently disabled as
|
|
|
|
// a negative numerical value looks just like a proceeding
|
|
|
|
// option.
|
|
|
|
//std::numeric_limits<T>::min(),
|
|
|
|
|
|
|
|
std::numeric_limits<T>::max (),
|
|
|
|
0
|
|
|
|
};
|
|
|
|
|
|
|
|
const char *argv_short[] = { "./foo", "-t", NULL };
|
|
|
|
const char * argv_long[] = { "./foo", NULL };
|
|
|
|
|
2016-11-17 18:06:39 +11:00
|
|
|
for(size_t i = 0; i < std::size (values); ++i) {
|
2015-06-30 22:09:35 +10:00
|
|
|
std::ostringstream out_short, out_long;
|
|
|
|
std::string str_short, str_long;
|
|
|
|
|
2015-07-02 17:03:56 +10:00
|
|
|
// construct short form arguments
|
2015-06-30 22:09:35 +10:00
|
|
|
out_short << values[i];
|
|
|
|
str_short = out_short.str ();
|
|
|
|
argv_short[2] = str_short.c_str ();
|
|
|
|
|
2015-07-02 17:03:56 +10:00
|
|
|
// check short form reading
|
2015-06-30 22:09:35 +10:00
|
|
|
value = 2;
|
2016-11-17 18:06:39 +11:00
|
|
|
p.scan (std::size (argv_short), argv_short);
|
2015-07-21 03:17:20 +10:00
|
|
|
tap.expect_eq (value, values[i], "equality, short form");
|
2015-06-30 22:09:35 +10:00
|
|
|
|
2015-07-02 17:03:56 +10:00
|
|
|
// construct long form arguments
|
2015-06-30 22:09:35 +10:00
|
|
|
out_long << "--type=" << values[i];
|
|
|
|
str_long = out_long.str ();
|
|
|
|
argv_long[1] = str_long.c_str ();
|
|
|
|
|
2015-07-02 17:03:56 +10:00
|
|
|
// check long form reading
|
2015-06-30 22:09:35 +10:00
|
|
|
value = 2;
|
2016-11-17 18:06:39 +11:00
|
|
|
p.scan (std::size (argv_long), argv_long);
|
2015-07-21 03:17:20 +10:00
|
|
|
tap.expect_eq (value, values[i], "equality, long form");
|
2015-06-30 22:09:35 +10:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2016-03-15 13:55:49 +11:00
|
|
|
///////////////////////////////////////////////////////////////////////////////
|
|
|
|
static
|
2015-06-30 22:09:35 +10:00
|
|
|
void
|
2018-08-05 14:42:02 +10:00
|
|
|
test_bytes (cruft::TAP::logger &tap)
|
2015-07-02 17:03:56 +10:00
|
|
|
{
|
2018-08-05 14:42:02 +10:00
|
|
|
cruft::cmdopt::parser p;
|
2015-06-30 22:09:35 +10:00
|
|
|
size_t size;
|
|
|
|
|
2018-08-05 14:42:02 +10:00
|
|
|
p.add<cruft::cmdopt::option::bytes> ('b', "bytes", "testing bytes", size);
|
2015-06-30 22:09:35 +10:00
|
|
|
|
|
|
|
static const struct {
|
|
|
|
const char *str;
|
|
|
|
size_t val;
|
|
|
|
} commands[] = {
|
|
|
|
{ "1", 1 },
|
2018-08-05 14:42:02 +10:00
|
|
|
{ "1k", cruft::pow (1024u, 1u) },
|
|
|
|
{ "1M", cruft::pow (1024u, 2u) },
|
|
|
|
{ "1G", cruft::pow (1024u, 3u) }
|
2015-06-30 22:09:35 +10:00
|
|
|
};
|
|
|
|
|
|
|
|
const char *argv[] = {
|
|
|
|
"./foo",
|
|
|
|
"-b",
|
|
|
|
NULL
|
|
|
|
};
|
|
|
|
|
|
|
|
for (auto &i: commands) {
|
|
|
|
argv[2] = i.str;
|
2016-11-17 18:06:39 +11:00
|
|
|
p.scan (std::size (argv), argv);
|
2015-06-30 22:09:35 +10:00
|
|
|
|
2021-04-13 16:05:08 +10:00
|
|
|
tap.expect_eq (i.val, size, "bytes, {:s}", i.str);
|
2015-06-30 22:09:35 +10:00
|
|
|
};
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2016-03-15 13:55:49 +11:00
|
|
|
///////////////////////////////////////////////////////////////////////////////
|
|
|
|
static
|
2015-06-30 22:09:35 +10:00
|
|
|
void
|
2018-08-05 14:42:02 +10:00
|
|
|
test_required (cruft::TAP::logger &tap)
|
2015-07-02 17:03:56 +10:00
|
|
|
{
|
2018-08-05 14:42:02 +10:00
|
|
|
cruft::cmdopt::parser p;
|
|
|
|
p.add<cruft::cmdopt::option::null> (
|
2015-06-30 22:09:35 +10:00
|
|
|
'n',
|
|
|
|
"null",
|
|
|
|
"null testing"
|
|
|
|
).required (true);
|
|
|
|
|
|
|
|
static const char *argv[] = {
|
|
|
|
"./cpptest",
|
|
|
|
"-n",
|
|
|
|
"value"
|
|
|
|
};
|
|
|
|
|
2015-07-02 17:03:56 +10:00
|
|
|
tap.expect_nothrow ([&] () {
|
2016-11-17 18:06:39 +11:00
|
|
|
p.scan (std::size (argv), argv);
|
2015-07-21 03:17:20 +10:00
|
|
|
}, "required option, success");
|
2015-07-02 17:03:56 +10:00
|
|
|
|
2018-08-05 14:42:02 +10:00
|
|
|
tap.expect_throw<cruft::cmdopt::invalid_required> ([&] () {
|
2015-07-02 17:03:56 +10:00
|
|
|
p.scan (1, argv);
|
2015-07-21 03:17:20 +10:00
|
|
|
}, "required option, failure");
|
2015-06-30 22:09:35 +10:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2020-01-17 07:58:23 +11:00
|
|
|
///////////////////////////////////////////////////////////////////////////////
|
|
|
|
static
|
|
|
|
void
|
|
|
|
test_fulfilled (cruft::TAP::logger &tap)
|
|
|
|
{
|
|
|
|
// Test that a value option that has no requirements/seen constraints and no provided value is fullfilled.
|
|
|
|
{
|
|
|
|
cruft::cmdopt::parser p;
|
|
|
|
bool b_val;
|
|
|
|
auto &b_opt = p.add<cruft::cmdopt::option::value<bool>> ('b', "bool", "boolean value", b_val);
|
|
|
|
static constexpr char const* argv[] = { "./cpptest", };
|
|
|
|
tap.expect_nothrow ([&] () {
|
|
|
|
p.scan (std::size (argv), argv);
|
|
|
|
}, "fullfilled, empty, scan");
|
|
|
|
tap.expect (b_opt.fulfilled (), "fulfilled, empty, value");
|
|
|
|
}
|
|
|
|
|
|
|
|
// Test that an unseen dependent option means the option is unfulfilled.
|
|
|
|
{
|
|
|
|
cruft::cmdopt::parser p;
|
|
|
|
int a_val = 0, b_val = 0;
|
|
|
|
auto &a_opt = p.add<cruft::cmdopt::option::value<int>> ('a', "ay", "int value", a_val);
|
|
|
|
auto &b_opt = p.add<cruft::cmdopt::option::value<int>> ('b', "be", "int value", b_val);
|
|
|
|
|
|
|
|
b_opt.required(a_opt.is (1));
|
|
|
|
|
|
|
|
static constexpr char const* argv[] = { "./cpptest", "-a", "1"};
|
|
|
|
tap.expect_throw<cruft::cmdopt::invalid_required> ([&] () {
|
|
|
|
p.scan (std::size (argv), argv);
|
|
|
|
}, "fullfilled, unseen dependent, scan");
|
|
|
|
}
|
|
|
|
|
|
|
|
// Test that a seen dependent opion means the option is fulfilled.
|
|
|
|
{
|
|
|
|
cruft::cmdopt::parser p;
|
|
|
|
int a_val = 0, b_val = 0;
|
|
|
|
auto &a_opt = p.add<cruft::cmdopt::option::value<int>> ('a', "ay", "int value", a_val);
|
|
|
|
auto &b_opt = p.add<cruft::cmdopt::option::value<int>> ('b', "be", "int value", b_val);
|
|
|
|
|
|
|
|
b_opt.required(a_opt.is (1));
|
|
|
|
|
|
|
|
static constexpr char const* argv[] = { "./cpptest", "-a", "1", "-b", "10"};
|
|
|
|
tap.expect_nothrow ([&] () {
|
|
|
|
p.scan (std::size (argv), argv);
|
|
|
|
}, "fullfilled, unseen dependent, scan");
|
|
|
|
|
|
|
|
tap.expect_eq (a_val, 1, "fulfilled, dependent value");
|
|
|
|
tap.expect_eq (b_val, 10, "fulfilled, dependent value");
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2016-03-15 13:55:49 +11:00
|
|
|
///////////////////////////////////////////////////////////////////////////////
|
|
|
|
static
|
|
|
|
void
|
2018-08-05 14:42:02 +10:00
|
|
|
test_positional (cruft::TAP::logger &tap)
|
2016-03-15 13:55:49 +11:00
|
|
|
{
|
|
|
|
unsigned value = 0xdead;
|
|
|
|
constexpr unsigned expected = 0xbeef;
|
|
|
|
|
2018-08-05 14:42:02 +10:00
|
|
|
cruft::cmdopt::parser p;
|
|
|
|
p.append<cruft::cmdopt::option::value<unsigned>> ("unsigned test", value);
|
2016-03-15 13:55:49 +11:00
|
|
|
|
|
|
|
static const char *argv[] = {
|
|
|
|
"./cpptest",
|
|
|
|
"--",
|
|
|
|
"48879",
|
|
|
|
};
|
|
|
|
|
|
|
|
tap.expect_nothrow ([&] {
|
2016-11-17 18:06:39 +11:00
|
|
|
p.scan (std::size (argv), argv);
|
2016-03-15 13:55:49 +11:00
|
|
|
}, "positional, nothrow");
|
|
|
|
|
|
|
|
tap.expect_eq (value, expected, "positiona, value success");
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
///////////////////////////////////////////////////////////////////////////////
|
2015-06-30 22:09:35 +10:00
|
|
|
int
|
|
|
|
main (int, char **) {
|
2019-01-03 15:48:34 +11:00
|
|
|
return cruft::TAP::logger::run ([] (auto &tap) {
|
|
|
|
test_null (tap);
|
|
|
|
test_present (tap);
|
|
|
|
test_bool (tap);
|
|
|
|
test_numeric< int16_t> (tap);
|
|
|
|
test_numeric< int32_t> (tap);
|
|
|
|
test_numeric< int64_t> (tap);
|
|
|
|
test_numeric<uint16_t> (tap);
|
|
|
|
test_numeric<uint32_t> (tap);
|
|
|
|
test_numeric<uint64_t> (tap);
|
|
|
|
test_bytes (tap);
|
|
|
|
test_required (tap);
|
2020-01-17 07:58:23 +11:00
|
|
|
test_fulfilled (tap);
|
2019-01-03 15:48:34 +11:00
|
|
|
test_positional (tap);
|
|
|
|
});
|
2015-06-30 22:09:35 +10:00
|
|
|
}
|