cc74cbfda7
All checks were successful
rpcrypto-build / build (Debug, hisiv510.toolchain.cmake) (push) Successful in 1m4s
rpcrypto-build / build (Debug, himix200.toolchain.cmake) (push) Successful in 1m17s
rpcrypto-build / build (Release, hisiv510.toolchain.cmake) (push) Successful in 1m17s
rpcrypto-build / build (Release, himix200.toolchain.cmake) (push) Successful in 1m24s
linux-hisiv500-gcc / linux-gcc-hisiv500 (push) Successful in 1m25s
linux-mips64-gcc / linux-gcc-mips64el (push) Successful in 1m34s
linux-x64-gcc / linux-gcc (push) Successful in 1m36s
987 lines
35 KiB
C++
987 lines
35 KiB
C++
#include "../include/argagg/argagg.hpp"
|
|
|
|
#define DOCTEST_CONFIG_IMPLEMENT_WITH_MAIN
|
|
#include "doctest.h"
|
|
|
|
#include <cstring>
|
|
#include <iostream>
|
|
#include <vector>
|
|
|
|
|
|
TEST_CASE("cmd_line_arg_is_option_flag")
|
|
{
|
|
CHECK(argagg::cmd_line_arg_is_option_flag("") == false);
|
|
CHECK(argagg::cmd_line_arg_is_option_flag("a") == false);
|
|
CHECK(argagg::cmd_line_arg_is_option_flag("abc") == false);
|
|
CHECK(argagg::cmd_line_arg_is_option_flag("-") == false);
|
|
CHECK(argagg::cmd_line_arg_is_option_flag("-a") == true);
|
|
CHECK(argagg::cmd_line_arg_is_option_flag("-abc") == true);
|
|
CHECK(argagg::cmd_line_arg_is_option_flag("-I/usr/local/include") == true);
|
|
CHECK(argagg::cmd_line_arg_is_option_flag("--") == false);
|
|
CHECK(argagg::cmd_line_arg_is_option_flag("---a") == false);
|
|
CHECK(argagg::cmd_line_arg_is_option_flag("--a") == true);
|
|
CHECK(argagg::cmd_line_arg_is_option_flag("--abc") == true);
|
|
CHECK(argagg::cmd_line_arg_is_option_flag("---abc") == false);
|
|
CHECK(argagg::cmd_line_arg_is_option_flag("--a@b") == false);
|
|
CHECK(argagg::cmd_line_arg_is_option_flag("--a+b") == false);
|
|
CHECK(argagg::cmd_line_arg_is_option_flag("--foo-bar") == true);
|
|
CHECK(argagg::cmd_line_arg_is_option_flag("--output=~/out.txt") == true);
|
|
}
|
|
|
|
|
|
TEST_CASE("is_valid_flag_definition")
|
|
{
|
|
CHECK(argagg::is_valid_flag_definition("") == false);
|
|
CHECK(argagg::is_valid_flag_definition("a") == false);
|
|
CHECK(argagg::is_valid_flag_definition("abc") == false);
|
|
CHECK(argagg::is_valid_flag_definition("-") == false);
|
|
CHECK(argagg::is_valid_flag_definition("-a") == true);
|
|
CHECK(argagg::is_valid_flag_definition("-abc") == false);
|
|
CHECK(argagg::is_valid_flag_definition("-I/usr/local/include") == false);
|
|
CHECK(argagg::is_valid_flag_definition("--") == false);
|
|
CHECK(argagg::is_valid_flag_definition("---a") == false);
|
|
CHECK(argagg::is_valid_flag_definition("--a") == true);
|
|
CHECK(argagg::is_valid_flag_definition("--abc") == true);
|
|
CHECK(argagg::is_valid_flag_definition("---abc") == false);
|
|
CHECK(argagg::is_valid_flag_definition("--a@b") == false);
|
|
CHECK(argagg::is_valid_flag_definition("--a+b") == false);
|
|
CHECK(argagg::is_valid_flag_definition("--foo-bar") == true);
|
|
CHECK(argagg::is_valid_flag_definition("--output=~/out.txt") == false);
|
|
}
|
|
|
|
|
|
TEST_CASE("flag_is_short")
|
|
{
|
|
CHECK(argagg::flag_is_short("-a") == true);
|
|
CHECK(argagg::flag_is_short("-abc") == true);
|
|
CHECK(argagg::flag_is_short("--a") == false);
|
|
CHECK(argagg::flag_is_short("--abc") == false);
|
|
CHECK(argagg::flag_is_short("--a-b") == false);
|
|
}
|
|
|
|
|
|
TEST_CASE("intro example")
|
|
{
|
|
argagg::parser argparser {{
|
|
{ "help", {"-h", "--help"},
|
|
"shows this help message", 0},
|
|
{ "delim", {"-d", "--delim"},
|
|
"delimiter (default: ,)", 1},
|
|
{ "num", {"-n", "--num"},
|
|
"number", 1},
|
|
}};
|
|
std::vector<const char*> argv {
|
|
"test", "3.141", "foo", "-h", "bar", "300", "-n", "100", "-d", "-", "-",
|
|
"--", "-b", "--blah"};
|
|
argagg::parser_results args;
|
|
try {
|
|
args = argparser.parse(argv.size(), &(argv.front()));
|
|
} catch (const std::exception& e) {
|
|
std::cerr << e.what() << std::endl;
|
|
}
|
|
CHECK(args.has_option("help") == true);
|
|
CHECK(static_cast<bool>(args["help"]) == true);
|
|
CHECK(args.has_option("delim") == true);
|
|
CHECK(static_cast<bool>(args["delim"]) == true);
|
|
auto delim = args["delim"].as<std::string>(",");
|
|
CHECK(delim == "-");
|
|
CHECK(args.has_option("num") == true);
|
|
CHECK(static_cast<bool>(args["num"]) == true);
|
|
int x = 0;
|
|
if (args["num"]) {
|
|
x = args["num"];
|
|
}
|
|
CHECK(x == 100);
|
|
auto y = 0.0;
|
|
if (args.pos.size() > 0) {
|
|
y = args.as<double>(0);
|
|
}
|
|
CHECK(y == doctest::Approx(3.141));
|
|
CHECK(args.as<std::string>(1) == "foo");
|
|
CHECK(args.as<std::string>(2) == "bar");
|
|
CHECK(args.as<int>(3) == 300);
|
|
CHECK(args.as<std::string>(4) == "-");
|
|
CHECK(args.as<std::string>(5) == "-b");
|
|
CHECK(args.as<std::string>(6) == "--blah");
|
|
}
|
|
|
|
|
|
TEST_CASE("no definitions")
|
|
{
|
|
argagg::parser parser {{
|
|
}};
|
|
SUBCASE("no arguments") {
|
|
std::vector<const char*> argv {
|
|
"test"};
|
|
argagg::parser_results args = parser.parse(argv.size(), &(argv.front()));
|
|
CHECK(args.has_option("help") == false);
|
|
CHECK(args.has_option("verbose") == false);
|
|
CHECK(args.has_option("output") == false);
|
|
CHECK(args.count() == 0);
|
|
}
|
|
SUBCASE("with arguments") {
|
|
std::vector<const char*> argv {
|
|
"test", "foo", "bar", "baz"};
|
|
argagg::parser_results args = parser.parse(argv.size(), &(argv.front()));
|
|
CHECK(args.has_option("help") == false);
|
|
CHECK(args.has_option("verbose") == false);
|
|
CHECK(args.has_option("output") == false);
|
|
CHECK(args.count() == 3);
|
|
CHECK(::std::string(args.pos[0]) == "foo");
|
|
CHECK(::std::string(args.pos[1]) == "bar");
|
|
CHECK(::std::string(args.pos[2]) == "baz");
|
|
}
|
|
SUBCASE("with flags") {
|
|
std::vector<const char*> argv {
|
|
"test", "--verbose", "-o", "baz"};
|
|
CHECK_THROWS_AS({
|
|
argagg::parser_results args = parser.parse(argv.size(), &(argv.front()));
|
|
}, argagg::unexpected_option_error);
|
|
}
|
|
}
|
|
|
|
|
|
TEST_CASE("invalid definitions")
|
|
{
|
|
std::vector<const char*> argv {
|
|
"test"};
|
|
SUBCASE("no flags") {
|
|
argagg::parser parser {{
|
|
{"bad", {}, "bad", 0},
|
|
}};
|
|
CHECK_THROWS_AS({
|
|
argagg::parser_results args = parser.parse(argv.size(), &(argv.front()));
|
|
}, argagg::invalid_flag);
|
|
}
|
|
SUBCASE("too short") {
|
|
argagg::parser parser {{
|
|
{"bad", {"-"}, "bad", 0},
|
|
}};
|
|
CHECK_THROWS_AS({
|
|
argagg::parser_results args = parser.parse(argv.size(), &(argv.front()));
|
|
}, argagg::invalid_flag);
|
|
}
|
|
SUBCASE("too short 2") {
|
|
argagg::parser parser {{
|
|
{"bad", {"a"}, "bad", 0},
|
|
}};
|
|
CHECK_THROWS_AS({
|
|
argagg::parser_results args = parser.parse(argv.size(), &(argv.front()));
|
|
}, argagg::invalid_flag);
|
|
}
|
|
SUBCASE("no hyphen") {
|
|
argagg::parser parser {{
|
|
{"bad", {"bad"}, "bad", 0},
|
|
}};
|
|
CHECK_THROWS_AS({
|
|
argagg::parser_results args = parser.parse(argv.size(), &(argv.front()));
|
|
}, argagg::invalid_flag);
|
|
}
|
|
SUBCASE("short flag group") {
|
|
argagg::parser parser {{
|
|
{"bad", {"-bad"}, "bad", 0},
|
|
}};
|
|
CHECK_THROWS_AS({
|
|
argagg::parser_results args = parser.parse(argv.size(), &(argv.front()));
|
|
}, argagg::invalid_flag);
|
|
}
|
|
SUBCASE("invalid character") {
|
|
argagg::parser parser {{
|
|
{"bad", {"-b ad"}, "bad", 0},
|
|
}};
|
|
CHECK_THROWS_AS({
|
|
argagg::parser_results args = parser.parse(argv.size(), &(argv.front()));
|
|
}, argagg::invalid_flag);
|
|
}
|
|
SUBCASE("too many hyphens") {
|
|
argagg::parser parser {{
|
|
{"bad", {"---bad"}, "bad", 0},
|
|
}};
|
|
CHECK_THROWS_AS({
|
|
argagg::parser_results args = parser.parse(argv.size(), &(argv.front()));
|
|
}, argagg::invalid_flag);
|
|
}
|
|
SUBCASE("long flag equal assignment") {
|
|
argagg::parser parser {{
|
|
{"bad", {"--bad=still-bad"}, "bad", 0},
|
|
}};
|
|
CHECK_THROWS_AS({
|
|
argagg::parser_results args = parser.parse(argv.size(), &(argv.front()));
|
|
}, argagg::invalid_flag);
|
|
}
|
|
SUBCASE("duplicate short flags") {
|
|
argagg::parser parser {{
|
|
{"bad", {"-b"}, "bad", 0},
|
|
{"bad2", {"-b"}, "bad2", 0},
|
|
}};
|
|
CHECK_THROWS_AS({
|
|
argagg::parser_results args = parser.parse(argv.size(), &(argv.front()));
|
|
}, argagg::invalid_flag);
|
|
}
|
|
SUBCASE("duplicate long flags") {
|
|
argagg::parser parser {{
|
|
{"bad", {"--bad"}, "bad", 0},
|
|
{"bad2", {"--bad"}, "bad2", 0},
|
|
}};
|
|
CHECK_THROWS_AS({
|
|
argagg::parser_results args = parser.parse(argv.size(), &(argv.front()));
|
|
}, argagg::invalid_flag);
|
|
}
|
|
}
|
|
|
|
|
|
TEST_CASE("simple")
|
|
{
|
|
argagg::parser parser {{
|
|
{"verbose", {"-v", "--verbose"}, "be verbose", 0},
|
|
{"output", {"-o", "--output"}, "output filename", 1},
|
|
}};
|
|
SUBCASE("no arguments") {
|
|
std::vector<const char*> argv {
|
|
"test"};
|
|
argagg::parser_results args = parser.parse(argv.size(), &(argv.front()));
|
|
CHECK(args.has_option("help") == false);
|
|
CHECK(args.has_option("verbose") == false);
|
|
CHECK(args.has_option("output") == false);
|
|
CHECK(args.count() == 0);
|
|
}
|
|
SUBCASE("no flags") {
|
|
std::vector<const char*> argv {
|
|
"test", "foo", "bar", "baz"};
|
|
argagg::parser_results args = parser.parse(argv.size(), &(argv.front()));
|
|
CHECK(args.has_option("help") == false);
|
|
CHECK(args.has_option("verbose") == false);
|
|
CHECK_THROWS_AS({
|
|
args["verbose"].as<int>();
|
|
}, std::out_of_range);
|
|
CHECK(args["verbose"].as<int>(999) == 999);
|
|
CHECK(args.has_option("output") == false);
|
|
CHECK(args.count() == 3);
|
|
CHECK(args.as<std::string>(0) == "foo");
|
|
CHECK(args.as<std::string>(1) == "bar");
|
|
CHECK(args.as<std::string>(2) == "baz");
|
|
}
|
|
SUBCASE("only flags") {
|
|
std::vector<const char*> argv {
|
|
"test", "--verbose", "--output", "foo", "-v", "-o", "bar"};
|
|
argagg::parser_results args = parser.parse(argv.size(), &(argv.front()));
|
|
CHECK(args.has_option("help") == false);
|
|
CHECK(args.has_option("verbose") == true);
|
|
CHECK(args["verbose"].count() == 2);
|
|
CHECK(args["verbose"][0].arg == nullptr);
|
|
CHECK(args["verbose"][1].arg == nullptr);
|
|
CHECK_THROWS_AS({
|
|
args["verbose"][0].as<std::string>();
|
|
}, argagg::option_lacks_argument_error);
|
|
CHECK_THROWS_AS({
|
|
args["verbose"][0].as<int>();
|
|
}, argagg::option_lacks_argument_error);
|
|
CHECK(args.has_option("output") == true);
|
|
CHECK(args["output"].count() == 2);
|
|
CHECK(args["output"][0].as<std::string>() == "foo");
|
|
CHECK(args["output"][1].as<std::string>() == "bar");
|
|
CHECK(args.count() == 0);
|
|
}
|
|
SUBCASE("simple mixed") {
|
|
std::vector<const char*> argv {
|
|
"test", "-v", "--output", "foo", "bar"};
|
|
argagg::parser_results args = parser.parse(argv.size(), &(argv.front()));
|
|
CHECK(args.has_option("help") == false);
|
|
CHECK(args.has_option("verbose") == true);
|
|
CHECK(args["verbose"].count() == 1);
|
|
CHECK(args["verbose"][0].arg == nullptr);
|
|
CHECK(args.has_option("output") == true);
|
|
CHECK(args["output"].count() == 1);
|
|
CHECK(args["output"].as<std::string>() == "foo");
|
|
CHECK(args.count() == 1);
|
|
CHECK(args.as<std::string>(0) == "bar");
|
|
}
|
|
SUBCASE("trailing flags") {
|
|
std::vector<const char*> argv {
|
|
"test", "foo", "bar", "-v", "--output", "baz"};
|
|
argagg::parser_results args = parser.parse(argv.size(), &(argv.front()));
|
|
CHECK(args.has_option("help") == false);
|
|
CHECK(args.has_option("verbose") == true);
|
|
CHECK(args["verbose"].count() == 1);
|
|
CHECK(args["verbose"][0].arg == nullptr);
|
|
CHECK(args.has_option("output") == true);
|
|
CHECK(args["output"].count() == 1);
|
|
CHECK(args["output"].as<std::string>() == "baz");
|
|
CHECK(args.count() == 2);
|
|
CHECK(args.as<std::string>(0) == "foo");
|
|
CHECK(args.as<std::string>(1) == "bar");
|
|
}
|
|
SUBCASE("interleaved positional arguments") {
|
|
std::vector<const char*> argv {
|
|
"test", "foo", "-v", "bar", "--verbose", "baz", "--output", "dog", "cat"};
|
|
argagg::parser_results args = parser.parse(argv.size(), &(argv.front()));
|
|
CHECK(args.has_option("help") == false);
|
|
CHECK(args.has_option("verbose") == true);
|
|
CHECK(args["verbose"].count() == 2);
|
|
CHECK(args["verbose"][0].arg == nullptr);
|
|
CHECK(args.has_option("output") == true);
|
|
CHECK(args["output"].count() == 1);
|
|
CHECK(args["output"].as<std::string>() == "dog");
|
|
CHECK(args.count() == 4);
|
|
CHECK(args.as<std::string>(0) == "foo");
|
|
CHECK(args.as<std::string>(1) == "bar");
|
|
CHECK(args.as<std::string>(2) == "baz");
|
|
CHECK(args.as<std::string>(3) == "cat");
|
|
}
|
|
SUBCASE("unused short flag") {
|
|
std::vector<const char*> argv {
|
|
"test", "--output", "foo", "-h", "bar", "-v"};
|
|
CHECK_THROWS_AS({
|
|
argagg::parser_results args = parser.parse(argv.size(), &(argv.front()));
|
|
}, argagg::unexpected_option_error);
|
|
}
|
|
SUBCASE("unused long flag") {
|
|
std::vector<const char*> argv {
|
|
"test", "--output", "foo", "--help", "bar", "-v"};
|
|
CHECK_THROWS_AS({
|
|
argagg::parser_results args = parser.parse(argv.size(), &(argv.front()));
|
|
}, argagg::unexpected_option_error);
|
|
}
|
|
}
|
|
|
|
|
|
TEST_CASE("long flag equal format for arguments")
|
|
{
|
|
argagg::parser parser {{
|
|
{"verbose", {"-v", "--verbose"}, "be verbose", 0},
|
|
{"delim", {"-d", "--delim"}, "delimiter", 1},
|
|
{"output", {"-o", "--output"}, "output", 1},
|
|
}};
|
|
SUBCASE("basic") {
|
|
std::vector<const char*> argv {
|
|
"test", "-v", "--output=foo", "--delim=bar", "baz"};
|
|
argagg::parser_results args = parser.parse(argv.size(), &(argv.front()));
|
|
CHECK(args.has_option("verbose") == true);
|
|
CHECK(args.has_option("output") == true);
|
|
CHECK(args["output"].as<std::string>() == "foo");
|
|
CHECK(args.has_option("delim") == true);
|
|
CHECK(args["delim"].as<std::string>() == "bar");
|
|
CHECK(args.count() == 1);
|
|
CHECK(args.as<std::string>(0) == "baz");
|
|
}
|
|
SUBCASE("empty") {
|
|
std::vector<const char*> argv {
|
|
"test", "-v", "--output=", "--delim=", "baz"};
|
|
argagg::parser_results args = parser.parse(argv.size(), &(argv.front()));
|
|
CHECK(args.has_option("verbose") == true);
|
|
CHECK(args.has_option("output") == true);
|
|
CHECK(args["output"].as<std::string>() == "");
|
|
CHECK(args.has_option("delim") == true);
|
|
CHECK(args["delim"].as<std::string>() == "");
|
|
CHECK(args.count() == 1);
|
|
CHECK(args.as<std::string>(0) == "baz");
|
|
}
|
|
SUBCASE("symbols") {
|
|
std::vector<const char*> argv {
|
|
"test", "-v", "--output=--foo!!", "--delim=,", "baz"};
|
|
argagg::parser_results args = parser.parse(argv.size(), &(argv.front()));
|
|
CHECK(args.has_option("verbose") == true);
|
|
CHECK(args.has_option("output") == true);
|
|
CHECK(args["output"].as<std::string>() == "--foo!!");
|
|
CHECK(args.has_option("delim") == true);
|
|
CHECK(args["delim"].as<std::string>() == ",");
|
|
CHECK(args.count() == 1);
|
|
CHECK(args.as<std::string>(0) == "baz");
|
|
}
|
|
SUBCASE("unnecessary argument") {
|
|
std::vector<const char*> argv {
|
|
"test", "--verbose=bad"};
|
|
CHECK_THROWS_AS({
|
|
argagg::parser_results args = parser.parse(argv.size(), &(argv.front()));
|
|
}, argagg::unexpected_argument_error);
|
|
}
|
|
}
|
|
|
|
|
|
TEST_CASE("short flag groups")
|
|
{
|
|
argagg::parser parser {{
|
|
{"verbose", {"-v", "--verbose"}, "be verbose", 0},
|
|
{"help", {"-h", "--help"}, "help", 0},
|
|
{"foo", {"-f", "--foo"}, "foo", 0},
|
|
{"output", {"-o", "--output"}, "output", 1},
|
|
}};
|
|
SUBCASE("basic") {
|
|
std::vector<const char*> argv {
|
|
"test", "-vhf", "bar"};
|
|
argagg::parser_results args = parser.parse(argv.size(), &(argv.front()));
|
|
CHECK(args.has_option("verbose") == true);
|
|
CHECK(args.has_option("help") == true);
|
|
CHECK(args.has_option("foo") == true);
|
|
CHECK(args.has_option("output") == false);
|
|
CHECK(args.count() == 1);
|
|
CHECK(args.as<std::string>(0) == "bar");
|
|
}
|
|
SUBCASE("basic 2") {
|
|
std::vector<const char*> argv {
|
|
"test", "-fvh", "bar"};
|
|
argagg::parser_results args = parser.parse(argv.size(), &(argv.front()));
|
|
CHECK(args.has_option("verbose") == true);
|
|
CHECK(args.has_option("help") == true);
|
|
CHECK(args.has_option("foo") == true);
|
|
CHECK(args.has_option("output") == false);
|
|
CHECK(args.count() == 1);
|
|
CHECK(args.as<std::string>(0) == "bar");
|
|
}
|
|
SUBCASE("basic 3") {
|
|
std::vector<const char*> argv {
|
|
"test", "-fh", "-v", "bar"};
|
|
argagg::parser_results args = parser.parse(argv.size(), &(argv.front()));
|
|
CHECK(args.has_option("verbose") == true);
|
|
CHECK(args.has_option("help") == true);
|
|
CHECK(args.has_option("foo") == true);
|
|
CHECK(args.has_option("output") == false);
|
|
CHECK(args.count() == 1);
|
|
CHECK(args.as<std::string>(0) == "bar");
|
|
}
|
|
SUBCASE("basic 4") {
|
|
std::vector<const char*> argv {
|
|
"test", "--vfh", "bar"};
|
|
CHECK_THROWS_AS({
|
|
argagg::parser_results args = parser.parse(argv.size(), &(argv.front()));
|
|
}, argagg::unexpected_option_error);
|
|
}
|
|
SUBCASE("unexpected symbol") {
|
|
std::vector<const char*> argv {
|
|
"test", "-v-fh", "bar"};
|
|
CHECK_THROWS_AS({
|
|
argagg::parser_results args = parser.parse(argv.size(), &(argv.front()));
|
|
}, std::domain_error);
|
|
}
|
|
SUBCASE("trailing flag with argument") {
|
|
std::vector<const char*> argv {
|
|
"test", "-vhfo", "bar"};
|
|
argagg::parser_results args = parser.parse(argv.size(), &(argv.front()));
|
|
CHECK(args.has_option("verbose") == true);
|
|
CHECK(args.has_option("help") == true);
|
|
CHECK(args.has_option("foo") == true);
|
|
CHECK(args.has_option("output") == true);
|
|
CHECK(args["output"].as<std::string>() == "bar");
|
|
CHECK(args.count() == 0);
|
|
}
|
|
SUBCASE("leading flag with argument") {
|
|
std::vector<const char*> argv {
|
|
"test", "-ohfv", "bar"};
|
|
argagg::parser_results args = parser.parse(argv.size(), &(argv.front()));
|
|
CHECK(args.has_option("verbose") == false);
|
|
CHECK(args.has_option("help") == false);
|
|
CHECK(args.has_option("foo") == false);
|
|
CHECK(args.has_option("output") == true);
|
|
CHECK(args["output"].as<std::string>() == "hfv");
|
|
CHECK(args.count() == 1);
|
|
CHECK(args.as<std::string>(0) == "bar");
|
|
}
|
|
SUBCASE("middling flag with argument") {
|
|
std::vector<const char*> argv {
|
|
"test", "-vfoh", "bar"};
|
|
argagg::parser_results args = parser.parse(argv.size(), &(argv.front()));
|
|
CHECK(args.has_option("verbose") == true);
|
|
CHECK(args.has_option("help") == false);
|
|
CHECK(args.has_option("foo") == true);
|
|
CHECK(args.has_option("output") == true);
|
|
CHECK(args["output"].as<std::string>() == "h");
|
|
CHECK(args.count() == 1);
|
|
CHECK(args.as<std::string>(0) == "bar");
|
|
}
|
|
}
|
|
|
|
|
|
TEST_CASE("flag stop")
|
|
{
|
|
argagg::parser parser {{
|
|
{"verbose", {"-v", "--verbose"}, "be verbose", 0},
|
|
{"delim", {"-d", "--delim"}, "delimiter", 1},
|
|
}};
|
|
SUBCASE("ignore flags after stop") {
|
|
std::vector<const char*> argv {
|
|
"test", "-v", "--", "bar", "--verbose", "baz",
|
|
"--delim", "dog", "-d", "cat"};
|
|
argagg::parser_results args = parser.parse(argv.size(), &(argv.front()));
|
|
CHECK(args.has_option("help") == false);
|
|
CHECK(args.has_option("verbose") == true);
|
|
CHECK(args["verbose"].count() == 1);
|
|
CHECK(args["verbose"][0].arg == nullptr);
|
|
CHECK(args.has_option("output") == false);
|
|
CHECK(args.count() == 7);
|
|
CHECK(args.as<std::string>(0) == "bar");
|
|
CHECK(args.as<std::string>(1) == "--verbose");
|
|
CHECK(args.as<std::string>(2) == "baz");
|
|
CHECK(args.as<std::string>(3) == "--delim");
|
|
CHECK(args.as<std::string>(4) == "dog");
|
|
CHECK(args.as<std::string>(5) == "-d");
|
|
CHECK(args.as<std::string>(6) == "cat");
|
|
}
|
|
SUBCASE("flag stop consumed as argument for option") {
|
|
std::vector<const char*> argv {
|
|
"test", "-d", "--", "--", "-", "boo"};
|
|
argagg::parser_results args = parser.parse(argv.size(), &(argv.front()));
|
|
CHECK(args.has_option("help") == false);
|
|
CHECK(args.has_option("verbose") == false);
|
|
CHECK(args.has_option("delim") == true);
|
|
CHECK(args["delim"].as<std::string>() == "--");
|
|
CHECK(args.count() == 2);
|
|
CHECK(args.as<std::string>(0) == "-");
|
|
CHECK(args.as<std::string>(1) == "boo");
|
|
}
|
|
}
|
|
|
|
|
|
TEST_CASE("option requires argument")
|
|
{
|
|
argagg::parser parser {{
|
|
{"verbose", {"-v", "--verbose"}, "be verbose", 0},
|
|
{"number", {"-n", "--number"}, "number", 1},
|
|
}};
|
|
SUBCASE("arguments provided") {
|
|
std::vector<const char*> argv {
|
|
"test", "-n", "1", "2", "-n", "4"};
|
|
argagg::parser_results args = parser.parse(argv.size(), &(argv.front()));
|
|
CHECK(args.has_option("verbose") == false);
|
|
CHECK(args.has_option("number") == true);
|
|
CHECK(args["number"].count() == 2);
|
|
CHECK(args["number"][0].as<int>() == 1);
|
|
CHECK(args["number"][1].as<int>() == 4);
|
|
CHECK(args.count() == 1);
|
|
CHECK(args.as<int>(0) == 2);
|
|
}
|
|
SUBCASE("negative numbers") {
|
|
std::vector<const char*> argv {
|
|
"test", "-n", "-1", "-n", "-4444", "--", "-22"};
|
|
argagg::parser_results args = parser.parse(argv.size(), &(argv.front()));
|
|
CHECK(args.has_option("verbose") == false);
|
|
CHECK(args.has_option("number") == true);
|
|
CHECK(args["number"].count() == 2);
|
|
CHECK(args["number"][0].as<int>() == -1);
|
|
CHECK(args["number"][1].as<int>() == -4444);
|
|
CHECK(args.count() == 1);
|
|
CHECK(args.as<int>(0) == -22);
|
|
}
|
|
SUBCASE("use flag as argument even though it is a valid flag")
|
|
{
|
|
std::vector<const char*> argv {
|
|
"test", "-n", "-v"};
|
|
argagg::parser_results args = parser.parse(argv.size(), &(argv.front()));
|
|
CHECK(args.has_option("number") == true);
|
|
CHECK(args["number"].count() == 1);
|
|
CHECK(args["number"][0].as<std::string>() == "-v");
|
|
}
|
|
SUBCASE("interrupted by unused flag")
|
|
{
|
|
std::vector<const char*> argv {
|
|
"test", "-n", "1", "2", "-c"};
|
|
CHECK_THROWS_AS({
|
|
argagg::parser_results args = parser.parse(argv.size(), &(argv.front()));
|
|
}, argagg::unexpected_option_error);
|
|
}
|
|
SUBCASE("given zero, end of args") {
|
|
std::vector<const char*> argv {
|
|
"test", "-n"};
|
|
CHECK_THROWS_AS({
|
|
argagg::parser_results args = parser.parse(argv.size(), &(argv.front()));
|
|
}, argagg::option_lacks_argument_error);
|
|
}
|
|
}
|
|
|
|
|
|
TEST_CASE("greedy processing")
|
|
{
|
|
argagg::parser parser {{
|
|
{"a", {"-a"}, "a", 0},
|
|
{"b", {"-b", "--bar"}, "b", 0},
|
|
{"c", {"-c"}, "c", 0},
|
|
{"output", {"-o", "--output"}, "output", 1},
|
|
}};
|
|
SUBCASE("short group example 1") {
|
|
std::vector<const char*> argv {
|
|
"test", "-abco", "foo"};
|
|
argagg::parser_results args = parser.parse(argv.size(), &(argv.front()));
|
|
CHECK(args.has_option("a") == true);
|
|
CHECK(args.has_option("b") == true);
|
|
CHECK(args.has_option("c") == true);
|
|
CHECK(args.has_option("output") == true);
|
|
CHECK(args["output"].as<std::string>() == "foo");
|
|
CHECK(args.count() == 0);
|
|
}
|
|
SUBCASE("short group example 2") {
|
|
std::vector<const char*> argv {
|
|
"test", "-aboc", "foo"};
|
|
argagg::parser_results args = parser.parse(argv.size(), &(argv.front()));
|
|
CHECK(args.has_option("a") == true);
|
|
CHECK(args.has_option("b") == true);
|
|
CHECK(args.has_option("c") == false);
|
|
CHECK(args.has_option("output") == true);
|
|
CHECK(args["output"].as<std::string>() == "c");
|
|
CHECK(args.count() == 1);
|
|
CHECK(args.as<std::string>(0) == "foo");
|
|
}
|
|
SUBCASE("short group example 3") {
|
|
std::vector<const char*> argv {
|
|
"test", "-aobc", "foo"};
|
|
argagg::parser_results args = parser.parse(argv.size(), &(argv.front()));
|
|
CHECK(args.has_option("a") == true);
|
|
CHECK(args.has_option("b") == false);
|
|
CHECK(args.has_option("c") == false);
|
|
CHECK(args.has_option("output") == true);
|
|
CHECK(args["output"].as<std::string>() == "bc");
|
|
CHECK(args.count() == 1);
|
|
CHECK(args.as<std::string>(0) == "foo");
|
|
}
|
|
SUBCASE("short group example 4") {
|
|
std::vector<const char*> argv {
|
|
"test", "-oabc", "foo"};
|
|
argagg::parser_results args = parser.parse(argv.size(), &(argv.front()));
|
|
CHECK(args.has_option("a") == false);
|
|
CHECK(args.has_option("b") == false);
|
|
CHECK(args.has_option("c") == false);
|
|
CHECK(args.has_option("output") == true);
|
|
CHECK(args["output"].as<std::string>() == "abc");
|
|
CHECK(args.count() == 1);
|
|
CHECK(args.as<std::string>(0) == "foo");
|
|
}
|
|
SUBCASE("long example 1") {
|
|
std::vector<const char*> argv {
|
|
"test", "--output=foo", "--", "--bar"};
|
|
argagg::parser_results args = parser.parse(argv.size(), &(argv.front()));
|
|
CHECK(args.has_option("a") == false);
|
|
CHECK(args.has_option("b") == false);
|
|
CHECK(args.has_option("c") == false);
|
|
CHECK(args.has_option("output") == true);
|
|
CHECK(args["output"].as<std::string>() == "foo");
|
|
CHECK(args.count() == 1);
|
|
CHECK(args.as<std::string>(0) == "--bar");
|
|
}
|
|
SUBCASE("long example 2") {
|
|
std::vector<const char*> argv {
|
|
"test", "--output", "--", "--bar"};
|
|
argagg::parser_results args = parser.parse(argv.size(), &(argv.front()));
|
|
CHECK(args.has_option("a") == false);
|
|
CHECK(args.has_option("b") == true);
|
|
CHECK(args.has_option("c") == false);
|
|
CHECK(args.has_option("output") == true);
|
|
CHECK(args["output"].as<std::string>() == "--");
|
|
CHECK(args.count() == 0);
|
|
}
|
|
SUBCASE("long example 3") {
|
|
std::vector<const char*> argv {
|
|
"test", "--output", "--bar"};
|
|
argagg::parser_results args = parser.parse(argv.size(), &(argv.front()));
|
|
CHECK(args.has_option("a") == false);
|
|
CHECK(args.has_option("b") == false);
|
|
CHECK(args.has_option("c") == false);
|
|
CHECK(args.has_option("output") == true);
|
|
CHECK(args["output"].as<std::string>() == "--bar");
|
|
CHECK(args.count() == 0);
|
|
}
|
|
}
|
|
|
|
|
|
TEST_CASE("gcc example")
|
|
{
|
|
argagg::parser parser {{
|
|
{"verbose", {"-v", "--verbose"}, "be verbose", 0},
|
|
{"version", {"--version"}, "print version", 0},
|
|
{"include path", {"-I"}, "include path", 1},
|
|
{"library path", {"-L"}, "library path", 1},
|
|
{"library", {"-l"}, "library", 1},
|
|
{"output", {"-o"}, "output", 1},
|
|
}};
|
|
SUBCASE("version") {
|
|
std::vector<const char*> argv {
|
|
"gcc", "--version"};
|
|
argagg::parser_results args = parser.parse(argv.size(), &(argv.front()));
|
|
CHECK(args.has_option("verbose") == false);
|
|
CHECK(args.has_option("version") == true);
|
|
CHECK(args.has_option("include path") == false);
|
|
CHECK(args.has_option("library path") == false);
|
|
CHECK(args.has_option("library") == false);
|
|
CHECK(args.has_option("output") == false);
|
|
CHECK(args.count() == 0);
|
|
}
|
|
SUBCASE("simple") {
|
|
std::vector<const char*> argv {
|
|
"gcc", "test.c"};
|
|
argagg::parser_results args = parser.parse(argv.size(), &(argv.front()));
|
|
CHECK(args.has_option("verbose") == false);
|
|
CHECK(args.has_option("version") == false);
|
|
CHECK(args.has_option("include path") == false);
|
|
CHECK(args.has_option("library path") == false);
|
|
CHECK(args.has_option("library") == false);
|
|
CHECK(args.has_option("output") == false);
|
|
CHECK(args.count() == 1);
|
|
CHECK(args.as<std::string>(0) == "test.c");
|
|
}
|
|
SUBCASE("simple 2") {
|
|
std::vector<const char*> argv {
|
|
"gcc", "-I/usr/local/include", "test.c", "-otest"};
|
|
argagg::parser_results args = parser.parse(argv.size(), &(argv.front()));
|
|
CHECK(args.has_option("verbose") == false);
|
|
CHECK(args.has_option("version") == false);
|
|
CHECK(args.has_option("include path") == true);
|
|
CHECK(args["include path"].count() == 1);
|
|
CHECK(args["include path"].as<std::string>() == "/usr/local/include");
|
|
CHECK(args.has_option("library path") == false);
|
|
CHECK(args.has_option("library") == false);
|
|
CHECK(args.has_option("output") == true);
|
|
CHECK(args["output"].count() == 1);
|
|
CHECK(args["output"].as<std::string>() == "test");
|
|
CHECK(args.count() == 1);
|
|
CHECK(args.as<std::string>(0) == "test.c");
|
|
}
|
|
SUBCASE("simple 3") {
|
|
std::vector<const char*> argv {
|
|
"gcc", "-I/usr/local/include", "-I.", "-L/usr/local/lib", "-lz", "-lm",
|
|
"test.c", "-otest"};
|
|
argagg::parser_results args = parser.parse(argv.size(), &(argv.front()));
|
|
CHECK(args.has_option("verbose") == false);
|
|
CHECK(args.has_option("version") == false);
|
|
CHECK(args.has_option("include path") == true);
|
|
CHECK(args["include path"].count() == 2);
|
|
CHECK(args["include path"][0].as<std::string>() == "/usr/local/include");
|
|
CHECK(args["include path"][1].as<std::string>() == ".");
|
|
CHECK(args.has_option("library path") == true);
|
|
CHECK(args["library path"].count() == 1);
|
|
CHECK(args["library path"][0].as<std::string>() == "/usr/local/lib");
|
|
CHECK(args.has_option("library") == true);
|
|
CHECK(args["library"].count() == 2);
|
|
CHECK(args["library"][0].as<std::string>() == "z");
|
|
CHECK(args["library"][1].as<std::string>() == "m");
|
|
CHECK(args.has_option("output") == true);
|
|
CHECK(args["output"].count() == 1);
|
|
CHECK(args["output"].as<std::string>() == "test");
|
|
CHECK(args.count() == 1);
|
|
CHECK(args.as<std::string>(0) == "test.c");
|
|
}
|
|
}
|
|
|
|
|
|
TEST_CASE("argument conversions")
|
|
{
|
|
argagg::parser parser {{
|
|
{"number", {"-n", "--num", "--number"}, "number", 1},
|
|
}};
|
|
SUBCASE("positional integer") {
|
|
std::vector<const char*> argv {
|
|
"test", "1", "2"};
|
|
argagg::parser_results args = parser.parse(argv.size(), &(argv.front()));
|
|
CHECK(args.pos.size() == 2);
|
|
CHECK(args.as<char>() == 1);
|
|
CHECK(args.as<unsigned char>() == 1);
|
|
CHECK(args.as<signed char>() == 1);
|
|
CHECK(args.as<short>() == 1);
|
|
CHECK(args.as<unsigned short>() == 1);
|
|
CHECK(args.as<signed short>() == 1);
|
|
CHECK(args.as<int>() == 1);
|
|
CHECK(args.as<unsigned int>() == 1);
|
|
CHECK(args.as<signed int>() == 1);
|
|
CHECK(args.as<long>() == 1);
|
|
CHECK(args.as<unsigned long>() == 1);
|
|
CHECK(args.as<signed long>() == 1);
|
|
CHECK(args.as<long long>() == 1);
|
|
CHECK(args.as<unsigned long long>() == 1);
|
|
CHECK(args.as<signed long long>() == 1);
|
|
CHECK(std::strcmp(args.as<const char*>(), "1") == 0);
|
|
CHECK(args.as<char>(1) == 2);
|
|
CHECK(args.as<unsigned char>(1) == 2);
|
|
CHECK(args.as<signed char>(1) == 2);
|
|
CHECK(args.as<short>(1) == 2);
|
|
CHECK(args.as<unsigned short>(1) == 2);
|
|
CHECK(args.as<signed short>(1) == 2);
|
|
CHECK(args.as<int>(1) == 2);
|
|
CHECK(args.as<unsigned int>(1) == 2);
|
|
CHECK(args.as<signed int>(1) == 2);
|
|
CHECK(args.as<long>(1) == 2);
|
|
CHECK(args.as<unsigned long>(1) == 2);
|
|
CHECK(args.as<signed long>(1) == 2);
|
|
CHECK(args.as<long long>(1) == 2);
|
|
CHECK(args.as<unsigned long long>(1) == 2);
|
|
CHECK(args.as<signed long long>(1) == 2);
|
|
CHECK(args.as<std::string>(1) == "2");
|
|
CHECK(std::strcmp(args.as<const char*>(1), "2") == 0);
|
|
}
|
|
SUBCASE("positional floating point") {
|
|
std::vector<const char*> argv {
|
|
"test", "3.141592653", "2.71828182846"};
|
|
argagg::parser_results args = parser.parse(argv.size(), &(argv.front()));
|
|
CHECK(args.pos.size() == 2);
|
|
CHECK(args.as<float>() == doctest::Approx(3.141592653f));
|
|
CHECK(args.as<double>() == doctest::Approx(3.141592653));
|
|
CHECK(args.as<std::string>() == "3.141592653");
|
|
CHECK(args.as<float>(1) == doctest::Approx(2.71828182846f));
|
|
CHECK(args.as<double>(1) == doctest::Approx(2.71828182846));
|
|
CHECK(args.as<std::string>(1) == "2.71828182846");
|
|
}
|
|
SUBCASE("positional vector") {
|
|
std::vector<const char*> argv {
|
|
"test", "0", "1", "2"};
|
|
argagg::parser_results args = parser.parse(argv.size(), &(argv.front()));
|
|
CHECK(args.pos.size() == 3);
|
|
auto v = args.all_as<int>();
|
|
CHECK(v[0] == 0);
|
|
CHECK(v[1] == 1);
|
|
CHECK(v[2] == 2);
|
|
}
|
|
SUBCASE("option integer") {
|
|
std::vector<const char*> argv {
|
|
"test", "-n", "1"};
|
|
argagg::parser_results args = parser.parse(argv.size(), &(argv.front()));
|
|
CHECK(args.has_option("number") == true);
|
|
CHECK(args["number"].count() == 1);
|
|
CHECK(args["number"].as<char>() == 1);
|
|
CHECK(args["number"].as<unsigned char>() == 1);
|
|
CHECK(args["number"].as<signed char>() == 1);
|
|
CHECK(args["number"].as<short>() == 1);
|
|
CHECK(args["number"].as<unsigned short>() == 1);
|
|
CHECK(args["number"].as<signed short>() == 1);
|
|
CHECK(args["number"].as<int>() == 1);
|
|
CHECK(args["number"].as<unsigned int>() == 1);
|
|
CHECK(args["number"].as<signed int>() == 1);
|
|
CHECK(args["number"].as<long>() == 1);
|
|
CHECK(args["number"].as<unsigned long>() == 1);
|
|
CHECK(args["number"].as<signed long>() == 1);
|
|
CHECK(args["number"].as<long long>() == 1);
|
|
CHECK(args["number"].as<unsigned long long>() == 1);
|
|
CHECK(args["number"].as<signed long long>() == 1);
|
|
CHECK(args["number"].as<std::string>() == "1");
|
|
}
|
|
SUBCASE("option floating point") {
|
|
std::vector<const char*> argv {
|
|
"test", "-n", "3.141592653"};
|
|
argagg::parser_results args = parser.parse(argv.size(), &(argv.front()));
|
|
CHECK(args.has_option("number") == true);
|
|
CHECK(args["number"].count() == 1);
|
|
CHECK(args["number"].as<float>() == doctest::Approx(3.141592653f));
|
|
CHECK(args["number"].as<double>() == doctest::Approx(3.141592653));
|
|
CHECK(args["number"].as<std::string>() == "3.141592653");
|
|
}
|
|
SUBCASE("option implicit conversions") {
|
|
std::vector<const char*> argv {
|
|
"test", "-n", "3.141592653", "-n", "2"};
|
|
argagg::parser_results args = parser.parse(argv.size(), &(argv.front()));
|
|
CHECK(args.has_option("number") == true);
|
|
CHECK(args["number"].count() == 2);
|
|
float x = args["number"][0];
|
|
int y = args["number"][1];
|
|
CHECK(x == doctest::Approx(3.141592653f));
|
|
CHECK(y == 2);
|
|
}
|
|
SUBCASE("exception on bad conversion") {
|
|
std::vector<const char*> argv {
|
|
"test", "-n", "not-an-number"};
|
|
argagg::parser_results args = parser.parse(argv.size(), &(argv.front()));
|
|
CHECK(args.has_option("number") == true);
|
|
CHECK(args["number"].count() == 1);
|
|
CHECK_THROWS_AS({
|
|
args["number"].as<int>();
|
|
}, std::invalid_argument);
|
|
CHECK_THROWS_AS({
|
|
args["number"].as<double>();
|
|
}, std::invalid_argument);
|
|
CHECK(args["number"].as<int>(-1) == -1);
|
|
CHECK(args["number"].as<double>(3.141) == doctest::Approx(3.141));
|
|
}
|
|
}
|
|
|
|
|
|
// Define a custom conversion function for the test that follows
|
|
namespace argagg {
|
|
namespace convert {
|
|
template <>
|
|
std::vector<std::string> arg(const char* s)
|
|
{
|
|
std::vector<std::string> ret {};
|
|
if (std::strlen(s) == 0) {
|
|
return ret;
|
|
}
|
|
while (true) {
|
|
const char* token = std::strchr(s, ',');
|
|
if (token == nullptr) {
|
|
ret.emplace_back(s, std::strlen(s));
|
|
break;
|
|
}
|
|
std::size_t len = token - s;
|
|
ret.emplace_back(s, len);
|
|
s += len + 1;
|
|
}
|
|
return ret;
|
|
}
|
|
} // namespace convert
|
|
} // namespace argagg
|
|
|
|
|
|
TEST_CASE("custom conversion function")
|
|
{
|
|
argagg::parser parser {{
|
|
{"words", {"-w", "--words"}, "words", 1},
|
|
}};
|
|
std::vector<const char*> argv {
|
|
"test", "-w", "hello,world,foo,bar,baz"};
|
|
argagg::parser_results args = parser.parse(argv.size(), &(argv.front()));
|
|
CHECK(args.has_option("words") == true);
|
|
auto v = args["words"].as<std::vector<std::string>>();
|
|
CHECK(v.size() == 5);
|
|
CHECK(v[0] == "hello");
|
|
CHECK(v[1] == "world");
|
|
CHECK(v[2] == "foo");
|
|
CHECK(v[3] == "bar");
|
|
CHECK(v[4] == "baz");
|
|
}
|
|
|
|
|
|
TEST_CASE("write options help")
|
|
{
|
|
argagg::parser parser {{
|
|
{"help", {"-h", "--help"}, "print help", 0},
|
|
{"verbose", {"-v", "--verbose"}, "be verbose", 0},
|
|
{"output", {"-o", "--output"}, "output filename", 1},
|
|
}};
|
|
// Just checking for no exceptions for now.
|
|
std::cout << parser;
|
|
}
|
|
|
|
|
|
static const std::string ipsum =
|
|
"Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod "
|
|
"tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam"
|
|
", quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo "
|
|
"consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse "
|
|
"cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat "
|
|
"non proident, sunt in culpa qui officia deserunt mollit anim id est "
|
|
"laborum.";
|
|
|
|
|
|
#ifdef __unix__
|
|
static const std::string fmt_ipsum =
|
|
"Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod\n"
|
|
"tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim\n"
|
|
"veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea\n"
|
|
"commodo consequat. Duis aute irure dolor in reprehenderit in voluptate\n"
|
|
"velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat\n"
|
|
"cupidatat non proident, sunt in culpa qui officia deserunt mollit anim\n"
|
|
"id est laborum.\n";
|
|
#else // #ifdef __unix__
|
|
static const std::string fmt_ipsum(ipsum);
|
|
#endif // #ifdef __unix__
|
|
|
|
|
|
TEST_CASE("fmt_ostream")
|
|
{
|
|
std::ostringstream os;
|
|
{
|
|
argagg::fmt_ostream test(os);
|
|
test << ipsum;
|
|
}
|
|
CHECK(os.str() == fmt_ipsum);
|
|
}
|
|
|
|
|
|
TEST_CASE("fmt_string")
|
|
{
|
|
std::string test_formatted = argagg::fmt_string(ipsum);
|
|
CHECK(test_formatted == fmt_ipsum);
|
|
}
|