#include #include #include std::ostream& operator<<(std::ostream& ostr, const arg::error& err) { switch(err) { case arg::error::invalid_arg: ostr << "arg::error::invalid_arg"; break; case arg::error::invalid_opt: ostr << "arg::error::invalid_opt"; break; case arg::error::missing_arg: ostr << "arg::error::missing_arg"; break; } return ostr; } #include class ArgParserTest : public uUnit { public: ArgParserTest() { uTEST(ArgParserTest::test_zero); uTEST(ArgParserTest::test_one); uTEST(ArgParserTest::test_many); uTEST(ArgParserTest::test_exceptional); uTEST(ArgParserTest::test_err_callback); uTEST(ArgParserTest::test_pos_callback); uTEST(ArgParserTest::test_grouped); uTEST(ArgParserTest::test_nullprogram); } void test_zero() { const char* const argv[] = { "app-name" }; int argc = sizeof(argv)/sizeof(*argv); arg::Parser args(argc, argv); auto res = args.parse(); uASSERT_EQUAL(0, res); } void test_one() { const char* argv[] = { "app-name", "-x", "42" }; int argc = sizeof(argv)/sizeof(*argv); arg::Parser args(argc, argv); int x{}; args.add('x', "--long-x", std::function([&](int i){ x = i; return 0;}), "Help x"); auto res = args.parse(); uASSERT_EQUAL(0, res); uASSERT_EQUAL(42, x); } void test_many() { const char* argv[] = { "app-name", "-x", "42", "-y17", "-z", "--long-X=12", "--long-Y", "18" }; int argc = sizeof(argv)/sizeof(*argv); arg::Parser args(argc, argv); int x{}; int y{}; bool z{false}; int X{}; int Y{}; args.add('x', "--long-x", std::function([&](int i){ x = i; return 0;}), "Help x"); args.add('y', "--long-y", std::function([&](int i){ y = i; return 0;}), "Help y"); args.add('z', "--long-z", std::function([&](){ z = true; return 0;}), "Help z"); args.add('X', "--long-X", std::function([&](int i){ X = i; return 0;}), "Help X"); args.add('Y', "--long-Y", std::function([&](int i){ Y = i; return 0;}), "Help Y"); auto res = args.parse(); uASSERT_EQUAL(0, res); uASSERT_EQUAL(42, x); uASSERT_EQUAL(17, y); uASSERT_EQUAL(true, z); uASSERT_EQUAL(12, X); uASSERT_EQUAL(18, Y); } void test_exceptional() { { // Missing arg at trailing opt const char* argv[] = { "app-name", "-x" }; int argc = sizeof(argv)/sizeof(*argv); arg::Parser args(argc, argv); int x{}; int y{}; args.add('x', "--long-x", std::function([&](int i){ x = i; return 0;}), "Help x"); args.add('y', "--long-y", std::function([&](int i){ y = i; return 0;}), "Help y"); auto res = args.parse(); uASSERT_EQUAL(1, res); } { // Missing arg before other opt const char* argv[] = { "app-name", "-x", "-y" }; int argc = sizeof(argv)/sizeof(*argv); arg::Parser args(argc, argv); int x{}; int y{}; args.add('x', "--long-x", std::function([&](int i){ x = i; return 0;}), "Help x"); args.add('y', "--long-y", std::function([&](int i){ y = i; return 0;}), "Help y"); auto res = args.parse(); uASSERT_EQUAL(1, res); } { // Unknown arg const char* argv[] = { "app-name", "-T" }; int argc = sizeof(argv)/sizeof(*argv); arg::Parser args(argc, argv); int x{}; int y{}; args.add('x', "--long-x", std::function([&](int i){ x = i; return 0;}), "Help x"); args.add('y', "--long-y", std::function([&](int i){ y = i; return 0;}), "Help y"); auto res = args.parse(); uASSERT_EQUAL(1, res); } } void test_err_callback() { using namespace std::string_literals; { // Missing arg at trailing opt const char* argv[] = { "app-name", "-x" }; int argc = sizeof(argv)/sizeof(*argv); arg::Parser args(argc, argv); int x{}; args.add('x', "--long-x", std::function([&](int i){ x = i; return 0;}), "Help x"); bool called{false}; args.set_err_cb( [&](arg::error err, std::string_view opt) { called = true; uASSERT_EQUAL(arg::error::missing_arg, err); uASSERT_EQUAL("-x"s, opt); }); auto res = args.parse(); uASSERT_EQUAL(1, res); uASSERT(called); } { // Invalid arg format const char* argv[] = { "app-name", "-x", "abc" }; int argc = sizeof(argv)/sizeof(*argv); arg::Parser args(argc, argv); int x{}; args.add('x', "--long-x", std::function([&](int i){ x = i; return 0;}), "Help x"); bool called{false}; args.set_err_cb( [&](arg::error err, std::string_view opt) { called = true; uASSERT_EQUAL(arg::error::invalid_arg, err); uASSERT_EQUAL("abc"s, opt); }); auto res = args.parse(); uASSERT_EQUAL(1, res); uASSERT(called); } { // Invalid opt const char* argv[] = { "app-name", "-y" }; int argc = sizeof(argv)/sizeof(*argv); arg::Parser args(argc, argv); int x{}; args.add('x', "--long-x", std::function([&](int i){ x = i; return 0;}), "Help x"); bool called{false}; args.set_err_cb( [&](arg::error err, std::string_view opt) { called = true; uASSERT_EQUAL(arg::error::invalid_opt, err); uASSERT_EQUAL("-y"s, opt); }); auto res = args.parse(); uASSERT_EQUAL(1, res); uASSERT(called); } } void test_pos_callback() { using namespace std::string_literals; const char* argv[] = { "app-name", "foo", "-x", "42", "bar", "-X43", "-Y", "42" }; int argc = sizeof(argv)/sizeof(*argv); arg::Parser> args(argc, argv); int x{}; int X{}; int Y{}; args.add('x', "--long-x", std::function([&](int i){ x = i; return 0;}), "Help x"); args.add('X', "--opt-x", std::function([&](std::optional i) { uASSERT(i.has_value()); X = *i; return 0; }), "Help X"); args.add('Y', "--opt-y", std::function([&](std::optional i) { uASSERT(!i.has_value()); Y = 1; return 0; }), "Help X"); std::vector pos; args.set_pos_cb( [&](std::string_view sv) { pos.push_back(std::string(sv)); return 0; }); auto res = args.parse(); uASSERT_EQUAL(0, res); uASSERT_EQUAL(3u, pos.size()); uASSERT_EQUAL("foo"s, pos[0]); uASSERT_EQUAL("bar"s, pos[1]); uASSERT_EQUAL("42"s, pos[2]); uASSERT_EQUAL(42, x); uASSERT_EQUAL(43, X); uASSERT_EQUAL(1, Y); } void test_grouped() { { const char* argv[] = { "app-name", "-xyz", "42" }; int argc = sizeof(argv)/sizeof(*argv); arg::Parser args(argc, argv); bool x{false}; bool y{false}; int z{}; args.add('x', "--long-x", std::function([&](){ x = true; return 0;}), "Help x"); args.add('y', "--long-y", std::function([&](){ y = true; return 0;}), "Help y"); args.add('z', "--long-z", std::function([&](int i){ z = i; return 0;}), "Help z"); auto res = args.parse(); uASSERT_EQUAL(0, res); uASSERT(x); uASSERT(y); uASSERT_EQUAL(42, z); } { const char* argv[] = { "app-name", "-xyz42" }; int argc = sizeof(argv)/sizeof(*argv); arg::Parser args(argc, argv); bool x{false}; bool y{false}; int z{}; args.add('x', "--long-x", std::function([&](){ x = true; return 0;}), "Help x"); args.add('y', "--long-y", std::function([&](){ y = true; return 0;}), "Help y"); args.add('z', "--long-z", std::function([&](int i){ z = i; return 0;}), "Help z"); auto res = args.parse(); uASSERT_EQUAL(0, res); uASSERT(x); uASSERT(y); uASSERT_EQUAL(42, z); } { const char* argv[] = { "app-name", "-xyz42" }; int argc = sizeof(argv)/sizeof(*argv); arg::Parser> args(argc, argv); bool x{false}; bool y{false}; int z{}; args.add('x', "--long-x", std::function([&](){ x = true; return 0;}), "Help x"); args.add('y', "--long-y", std::function([&](){ y = true; return 0;}), "Help y"); args.add('z', "--long-z", std::function([&](std::optional i) { uASSERT(i.has_value()); z = *i; return 0; }), "Help z"); auto res = args.parse(); uASSERT_EQUAL(0, res); uASSERT(x); uASSERT(y); uASSERT_EQUAL(42, z); } { const char* argv[] = { "app-name", "-xyz" }; int argc = sizeof(argv)/sizeof(*argv); arg::Parser> args(argc, argv); bool x{false}; bool y{false}; int z{}; args.add('x', "--long-x", std::function([&](){ x = true; return 0;}), "Help x"); args.add('y', "--long-y", std::function([&](){ y = true; return 0;}), "Help y"); args.add('z', "--long-z", std::function([&](std::optional i) { uASSERT(!i.has_value()); z = 1; return 0; }), "Help z"); auto res = args.parse(); uASSERT_EQUAL(0, res); uASSERT(x); uASSERT(y); uASSERT_EQUAL(1, z); } { const char* argv[] = { "app-name", "-xyz", "42" }; int argc = sizeof(argv)/sizeof(*argv); arg::Parser> args(argc, argv); bool x{false}; bool y{false}; int z{}; args.add('x', "--long-x", std::function([&](){ x = true; return 0;}), "Help x"); args.add('y', "--long-y", std::function([&](){ y = true; return 0;}), "Help y"); args.add('z', "--long-z", std::function([&](std::optional i) { uASSERT(!i.has_value()); z = 1; return 0; }), "Help z"); auto res = args.parse(); uASSERT_EQUAL(0, res); uASSERT(x); uASSERT(y); uASSERT_EQUAL(1, z); } } void test_nullprogram() { using namespace std::string_literals; // Inspired by https://nullprogram.com/blog/2020/08/01/ // // Short options // { const char* argv[] = { "program", "-a", "-b", "-c" }; int argc = sizeof(argv)/sizeof(*argv); arg::Parser<> args(argc, argv); std::vector r; args.add('a', {}, std::function([&](){ r.push_back('a'); return 0;}), {}); args.add('b', {}, std::function([&](){ r.push_back('b'); return 0;}), {}); args.add('c', {}, std::function([&](){ r.push_back('c'); return 0;}), {}); auto res = args.parse(); uASSERT_EQUAL(0, res); uASSERT_EQUAL(3u, r.size()); uASSERT_EQUAL('a', r[0]); uASSERT_EQUAL('b', r[1]); uASSERT_EQUAL('c', r[2]); } { const char* argv[] = { "program", "-abc" }; int argc = sizeof(argv)/sizeof(*argv); arg::Parser<> args(argc, argv); std::vector r; args.add('a', {}, std::function([&](){ r.push_back('a'); return 0;}), {}); args.add('b', {}, std::function([&](){ r.push_back('b'); return 0;}), {}); args.add('c', {}, std::function([&](){ r.push_back('c'); return 0;}), {}); auto res = args.parse(); uASSERT_EQUAL(0, res); uASSERT_EQUAL(3u, r.size()); uASSERT_EQUAL('a', r[0]); uASSERT_EQUAL('b', r[1]); uASSERT_EQUAL('c', r[2]); } { const char* argv[] = { "program", "-acb" }; int argc = sizeof(argv)/sizeof(*argv); arg::Parser<> args(argc, argv); std::vector r; args.add('a', {}, std::function([&](){ r.push_back('a'); return 0;}), {}); args.add('b', {}, std::function([&](){ r.push_back('b'); return 0;}), {}); args.add('c', {}, std::function([&](){ r.push_back('c'); return 0;}), {}); auto res = args.parse(); uASSERT_EQUAL(0, res); uASSERT_EQUAL(3u, r.size()); uASSERT_EQUAL('a', r[0]); uASSERT_EQUAL('c', r[1]); uASSERT_EQUAL('b', r[2]); } { const char* argv[] = { "program", "-i", "input.txt", "-o", "output.txt" }; int argc = sizeof(argv)/sizeof(*argv); arg::Parser args(argc, argv); std::vector r; args.add('i', {}, std::function([&](std::string input) { r.push_back(input); return 0; }), {}); args.add('o', {}, std::function([&](std::string input) { r.push_back(input); return 0; }), {}); auto res = args.parse(); uASSERT_EQUAL(0, res); uASSERT_EQUAL(2u, r.size()); uASSERT_EQUAL("input.txt"s, r[0]); uASSERT_EQUAL("output.txt"s, r[1]); } { const char* argv[] = { "program", "-iinput.txt", "-ooutput.txt" }; int argc = sizeof(argv)/sizeof(*argv); arg::Parser args(argc, argv); std::vector r; args.add('i', {}, std::function([&](std::string input) { r.push_back(input); return 0; }), {}); args.add('o', {}, std::function([&](std::string input) { r.push_back(input); return 0; }), {}); auto res = args.parse(); uASSERT_EQUAL(0, res); uASSERT_EQUAL(2u, r.size()); uASSERT_EQUAL("input.txt"s, r[0]); uASSERT_EQUAL("output.txt"s, r[1]); } { const char* argv[] = { "program", "-abco", "output.txt" }; int argc = sizeof(argv)/sizeof(*argv); arg::Parser args(argc, argv); std::vector r; args.add('a', {}, std::function([&](){ r.push_back("a"); return 0;}), {}); args.add('b', {}, std::function([&](){ r.push_back("b"); return 0;}), {}); args.add('c', {}, std::function([&](){ r.push_back("c"); return 0;}), {}); args.add('o', {}, std::function([&](std::string input) { r.push_back(input); return 0; }), {}); auto res = args.parse(); uASSERT_EQUAL(0, res); uASSERT_EQUAL(4u, r.size()); uASSERT_EQUAL("a"s, r[0]); uASSERT_EQUAL("b"s, r[1]); uASSERT_EQUAL("c"s, r[2]); uASSERT_EQUAL("output.txt"s, r[3]); } { const char* argv[] = { "program", "-abcooutput.txt" }; int argc = sizeof(argv)/sizeof(*argv); arg::Parser args(argc, argv); std::vector r; args.add('a', {}, std::function([&](){ r.push_back("a"); return 0;}), {}); args.add('b', {}, std::function([&](){ r.push_back("b"); return 0;}), {}); args.add('c', {}, std::function([&](){ r.push_back("c"); return 0;}), {}); args.add('o', {}, std::function([&](std::string input) { r.push_back(input); return 0; }), {}); auto res = args.parse(); uASSERT_EQUAL(0, res); uASSERT_EQUAL(4u, r.size()); uASSERT_EQUAL("a"s, r[0]); uASSERT_EQUAL("b"s, r[1]); uASSERT_EQUAL("c"s, r[2]); uASSERT_EQUAL("output.txt"s, r[3]); } { // Optional omitted const char* argv[] = { "program", "-c" }; int argc = sizeof(argv)/sizeof(*argv); arg::Parser> args(argc, argv); std::vector r; args.add('c', {}, std::function([&](std::optional c) { uASSERT(!c.has_value()); r.push_back("c"); return 0; }), {}); auto res = args.parse(); uASSERT_EQUAL(0, res); uASSERT_EQUAL(1u, r.size()); uASSERT_EQUAL("c"s, r[0]); } { // Optional provided const char* argv[] = { "program", "-cblue" }; int argc = sizeof(argv)/sizeof(*argv); arg::Parser> args(argc, argv); std::vector r; args.add('c', {}, std::function([&](std::optional c) { uASSERT(c.has_value()); r.push_back(*c); return 0; }), {}); auto res = args.parse(); uASSERT_EQUAL(0, res); uASSERT_EQUAL(1u, r.size()); uASSERT_EQUAL("blue"s, r[0]); } { // Optional omitted (blue is a new argument) const char* argv[] = { "program", "-c", "blue" }; int argc = sizeof(argv)/sizeof(*argv); arg::Parser> args(argc, argv); std::vector r; args.add('c', {}, std::function([&](std::optional c) { uASSERT(!c.has_value()); r.push_back("c"); return 0; }), {}); args.set_pos_cb(std::function([&](std::string_view pos) { r.push_back(std::string(pos)); return 0; })); auto res = args.parse(); uASSERT_EQUAL(0, res); uASSERT_EQUAL(2u, r.size()); uASSERT_EQUAL("c"s, r[0]); uASSERT_EQUAL("blue"s, r[1]); } { // Two seperate flags const char* argv[] = { "program", "-c", "-x" }; int argc = sizeof(argv)/sizeof(*argv); arg::Parser> args(argc, argv); std::vector r; args.add('x', {}, std::function([&](){ r.push_back("x"); return 0;}), {}); args.add('c', {}, std::function([&](std::optional c) { uASSERT(!c.has_value()); r.push_back("c"); return 0; }), {}); auto res = args.parse(); uASSERT_EQUAL(0, res); uASSERT_EQUAL(2u, r.size()); uASSERT_EQUAL("c"s, r[0]); uASSERT_EQUAL("x"s, r[1]); } { // -c with argument "-x" const char* argv[] = { "program", "-c-x" }; int argc = sizeof(argv)/sizeof(*argv); arg::Parser> args(argc, argv); std::vector r; args.add('x', {}, std::function([&](){ r.push_back("x"); return 0;}), {}); args.add('c', {}, std::function([&](std::optional c) { uASSERT(c.has_value()); r.push_back(*c); return 0; }), {}); auto res = args.parse(); uASSERT_EQUAL(0, res); uASSERT_EQUAL(1u, r.size()); uASSERT_EQUAL("-x"s, r[0]); } { const char* argv[] = { "program", "-a", "-b", "foo", "bar" }; int argc = sizeof(argv)/sizeof(*argv); arg::Parser<> args(argc, argv); std::vector r; args.add('a', {}, std::function([&](){ r.push_back("a"); return 0;}), {}); args.add('b', {}, std::function([&](){ r.push_back("b"); return 0;}), {}); args.set_pos_cb(std::function([&](std::string_view pos) { r.push_back(std::string(pos)); return 0; })); auto res = args.parse(); uASSERT_EQUAL(0, res); uASSERT_EQUAL(4u, r.size()); uASSERT_EQUAL("a"s, r[0]); uASSERT_EQUAL("b"s, r[1]); uASSERT_EQUAL("foo"s, r[2]); uASSERT_EQUAL("bar"s, r[3]); } { const char* argv[] = { "program", "-b", "-a", "foo", "bar" }; int argc = sizeof(argv)/sizeof(*argv); arg::Parser<> args(argc, argv); std::vector r; args.add('a', {}, std::function([&](){ r.push_back("a"); return 0;}), {}); args.add('b', {}, std::function([&](){ r.push_back("b"); return 0;}), {}); args.set_pos_cb(std::function([&](std::string_view pos) { r.push_back(std::string(pos)); return 0; })); auto res = args.parse(); uASSERT_EQUAL(0, res); uASSERT_EQUAL(4u, r.size()); uASSERT_EQUAL("b"s, r[0]); uASSERT_EQUAL("a"s, r[1]); uASSERT_EQUAL("foo"s, r[2]); uASSERT_EQUAL("bar"s, r[3]); } { const char* argv[] = { "program", "-a", "foo", "-b", "bar" }; int argc = sizeof(argv)/sizeof(*argv); arg::Parser<> args(argc, argv); std::vector r; args.add('a', {}, std::function([&](){ r.push_back("a"); return 0;}), {}); args.add('b', {}, std::function([&](){ r.push_back("b"); return 0;}), {}); args.set_pos_cb(std::function([&](std::string_view pos) { r.push_back(std::string(pos)); return 0; })); auto res = args.parse(); uASSERT_EQUAL(0, res); uASSERT_EQUAL(4u, r.size()); uASSERT_EQUAL("a"s, r[0]); uASSERT_EQUAL("foo"s, r[1]); uASSERT_EQUAL("b"s, r[2]); uASSERT_EQUAL("bar"s, r[3]); } { const char* argv[] = { "program", "foo", "-a", "-b", "bar" }; int argc = sizeof(argv)/sizeof(*argv); arg::Parser<> args(argc, argv); std::vector r; args.add('a', {}, std::function([&](){ r.push_back("a"); return 0;}), {}); args.add('b', {}, std::function([&](){ r.push_back("b"); return 0;}), {}); args.set_pos_cb(std::function([&](std::string_view pos) { r.push_back(std::string(pos)); return 0; })); auto res = args.parse(); uASSERT_EQUAL(0, res); uASSERT_EQUAL(4u, r.size()); uASSERT_EQUAL("foo"s, r[0]); uASSERT_EQUAL("a"s, r[1]); uASSERT_EQUAL("b"s, r[2]); uASSERT_EQUAL("bar"s, r[3]); } { const char* argv[] = { "program", "foo", "bar", "-a", "-b" }; int argc = sizeof(argv)/sizeof(*argv); arg::Parser<> args(argc, argv); std::vector r; args.add('a', {}, std::function([&](){ r.push_back("a"); return 0;}), {}); args.add('b', {}, std::function([&](){ r.push_back("b"); return 0;}), {}); args.set_pos_cb(std::function([&](std::string_view pos) { r.push_back(std::string(pos)); return 0; })); auto res = args.parse(); uASSERT_EQUAL(0, res); uASSERT_EQUAL(4u, r.size()); uASSERT_EQUAL("foo"s, r[0]); uASSERT_EQUAL("bar"s, r[1]); uASSERT_EQUAL("a"s, r[2]); uASSERT_EQUAL("b"s, r[3]); } { const char* argv[] = { "program", "-a", "-b", "--", "-x", "foo", "bar" }; int argc = sizeof(argv)/sizeof(*argv); arg::Parser<> args(argc, argv); std::vector r; args.add('a', {}, std::function([&](){ r.push_back("a"); return 0;}), {}); args.add('b', {}, std::function([&](){ r.push_back("b"); return 0;}), {}); args.set_pos_cb(std::function([&](std::string_view pos) { r.push_back(std::string(pos)); return 0; })); auto res = args.parse(); uASSERT_EQUAL(0, res); uASSERT_EQUAL(5u, r.size()); uASSERT_EQUAL("a"s, r[0]); uASSERT_EQUAL("b"s, r[1]); uASSERT_EQUAL("-x"s, r[2]); uASSERT_EQUAL("foo"s, r[3]); uASSERT_EQUAL("bar"s, r[4]); } // // Long options // { const char* argv[] = { "program", "--sort" }; int argc = sizeof(argv)/sizeof(*argv); arg::Parser<> args(argc, argv); std::vector r; args.add({}, "--sort", std::function([&](){ r.push_back("sort"); return 0;}), {}); auto res = args.parse(); uASSERT_EQUAL(0, res); uASSERT_EQUAL(1u, r.size()); uASSERT_EQUAL("sort"s, r[0]); } { const char* argv[] = { "program", "--no-sort" }; int argc = sizeof(argv)/sizeof(*argv); arg::Parser<> args(argc, argv); std::vector r; args.add({}, "--no-sort", std::function([&](){ r.push_back("no-sort"); return 0;}), {}); auto res = args.parse(); uASSERT_EQUAL(0, res); uASSERT_EQUAL(1u, r.size()); uASSERT_EQUAL("no-sort"s, r[0]); } { const char* argv[] = { "program", "--output", "output.txt", "--block-size", "1024" }; int argc = sizeof(argv)/sizeof(*argv); arg::Parser args(argc, argv); std::vector r; args.add({}, "--output", std::function([&](std::string output) { r.push_back(output); return 0; }), {}); args.add({}, "--block-size", std::function([&](int block_size) { r.push_back("["s + std::to_string(block_size) + "]"s); return 0; }), {}); auto res = args.parse(); uASSERT_EQUAL(0, res); uASSERT_EQUAL(2u, r.size()); uASSERT_EQUAL("output.txt"s, r[0]); uASSERT_EQUAL("[1024]"s, r[1]); } { const char* argv[] = { "program", "--output=output.txt", "--block-size=1024" }; int argc = sizeof(argv)/sizeof(*argv); arg::Parser args(argc, argv); std::vector r; args.add({}, "--output", std::function([&](std::string output) { r.push_back(output); return 0; }), {}); args.add({}, "--block-size", std::function([&](int block_size) { r.push_back("["s + std::to_string(block_size) + "]"s); return 0; }), {}); auto res = args.parse(); uASSERT_EQUAL(0, res); uASSERT_EQUAL(2u, r.size()); uASSERT_EQUAL("output.txt"s, r[0]); uASSERT_EQUAL("[1024]"s, r[1]); } { const char* argv[] = { "program", "--color", "--reverse" }; int argc = sizeof(argv)/sizeof(*argv); arg::Parser> args(argc, argv); std::vector r; args.add({}, "--color", std::function([&](std::optional color) { uASSERT(!color.has_value()); r.push_back("color"); return 0; }), {}); args.add({}, "--reverse", std::function([&]() { r.push_back("reverse"); return 0; }), {}); auto res = args.parse(); uASSERT_EQUAL(0, res); uASSERT_EQUAL(2u, r.size()); uASSERT_EQUAL("color"s, r[0]); uASSERT_EQUAL("reverse"s, r[1]); } { const char* argv[] = { "program", "--color=never", "--reverse" }; int argc = sizeof(argv)/sizeof(*argv); arg::Parser> args(argc, argv); std::vector r; args.add({}, "--color", std::function([&](std::optional color) { uASSERT(color.has_value()); r.push_back(*color); return 0; }), {}); args.add({}, "--reverse", std::function([&]() { r.push_back("reverse"); return 0; }), {}); auto res = args.parse(); uASSERT_EQUAL(0, res); uASSERT_EQUAL(2u, r.size()); uASSERT_EQUAL("never"s, r[0]); uASSERT_EQUAL("reverse"s, r[1]); } } }; // Registers the fixture into the 'registry' static ArgParserTest test;