diff options
Diffstat (limited to 'test')
-rw-r--r-- | test/argparser_test.cc | 1019 | ||||
-rw-r--r-- | test/ctor.cc | 16 | ||||
-rw-r--r-- | test/execute_test.cc | 2 | ||||
-rwxr-xr-x | test/suite/test.sh | 2 | ||||
-rw-r--r-- | test/tasks_test.cc | 12 | ||||
-rw-r--r-- | test/tmpfile.h | 44 |
6 files changed, 1059 insertions, 36 deletions
diff --git a/test/argparser_test.cc b/test/argparser_test.cc new file mode 100644 index 0000000..b649e8c --- /dev/null +++ b/test/argparser_test.cc @@ -0,0 +1,1019 @@ +#include <argparser.h> + +#include <iostream> +#include <string> + +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 <uunit.h> + +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<int> 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<int> 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<int> 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<int> 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<int> 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<int> 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<int> 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<int> 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<int> 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<int, std::optional<int>> 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<int> i) + { + uASSERT(i.has_value()); + X = *i; + return 0; + }), + "Help X"); + + args.add('Y', "--opt-y", + std::function([&](std::optional<int> i) + { + uASSERT(!i.has_value()); + Y = 1; + return 0; + }), + "Help X"); + + std::vector<std::string> 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<int> 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<int> 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<int, std::optional<int>> 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<int> 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<int, std::optional<int>> 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<int> 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<int, std::optional<int>> 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<int> 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<char> 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<char> 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<char> 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<std::string> args(argc, argv); + + std::vector<std::string> 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<std::string> args(argc, argv); + + std::vector<std::string> 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<std::string> args(argc, argv); + + std::vector<std::string> 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<std::string> args(argc, argv); + + std::vector<std::string> 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<std::optional<std::string>> args(argc, argv); + + std::vector<std::string> r; + args.add('c', {}, + std::function([&](std::optional<std::string> 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<std::optional<std::string>> args(argc, argv); + + std::vector<std::string> r; + args.add('c', {}, + std::function([&](std::optional<std::string> 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<std::optional<std::string>> args(argc, argv); + + std::vector<std::string> r; + args.add('c', {}, + std::function([&](std::optional<std::string> 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<std::optional<std::string>> args(argc, argv); + + std::vector<std::string> r; + args.add('x', {}, std::function([&](){ r.push_back("x"); return 0;}), {}); + args.add('c', {}, + std::function([&](std::optional<std::string> 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<std::optional<std::string>> args(argc, argv); + + std::vector<std::string> r; + args.add('x', {}, std::function([&](){ r.push_back("x"); return 0;}), {}); + args.add('c', {}, + std::function([&](std::optional<std::string> 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<std::string> 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<std::string> 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<std::string> 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<std::string> 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<std::string> 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<std::string> 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<std::string> 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<std::string> 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<std::string, int> args(argc, argv); + + std::vector<std::string> 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<std::string, int> args(argc, argv); + + std::vector<std::string> 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<std::optional<std::string>> args(argc, argv); + + std::vector<std::string> r; + args.add({}, "--color", + std::function([&](std::optional<std::string> 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<std::optional<std::string>> args(argc, argv); + + std::vector<std::string> r; + args.add({}, "--color", + std::function([&](std::optional<std::string> 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; diff --git a/test/ctor.cc b/test/ctor.cc index b7bcc6d..0d77a3e 100644 --- a/test/ctor.cc +++ b/test/ctor.cc @@ -12,6 +12,22 @@ ctor::build_configurations ctorTestConfigs(const ctor::settings& settings) { .type = ctor::target_type::unit_test, .system = ctor::output_system::build, + .target = "argparser_test", + .sources = { + "argparser_test.cc", + "testmain.cc", + }, + .flags = { + .cxxflags = { + "-std=c++20", "-O3", "-Wall", "-Werror", + "-I../src", "-Iuunit", + "-DOUTPUT=\"argparser\"", + }, + }, + }, + { + .type = ctor::target_type::unit_test, + .system = ctor::output_system::build, .target = "argsplit_test", .sources = { "argsplit_test.cc", diff --git a/test/execute_test.cc b/test/execute_test.cc index 722b6ea..11b067f 100644 --- a/test/execute_test.cc +++ b/test/execute_test.cc @@ -53,7 +53,7 @@ public: auto cmd = locate("testprog", paths); uASSERT(!cmd.empty()); - tmp_file tmp; + TmpFile tmp; std::map<std::string, std::string> env; diff --git a/test/suite/test.sh b/test/suite/test.sh index 97d2551..c54137a 100755 --- a/test/suite/test.sh +++ b/test/suite/test.sh @@ -70,8 +70,6 @@ ctor -v # Object file should have been recompiled MOD2=`stat $STAT_FORMAT ${BUILDDIR}/hello-hello_cc.o` -echo $MOD1 -echo $MOD2 [[ $MOD1 == $MOD2 ]] && fail ${LINENO} # Replacve -DFOO with -DBAR in foo external.cxxflags diff --git a/test/tasks_test.cc b/test/tasks_test.cc index b444bd5..cbd0864 100644 --- a/test/tasks_test.cc +++ b/test/tasks_test.cc @@ -170,7 +170,7 @@ public: uASSERT_EQUAL(0, task->registerDepTasks(allTasks)); } - uASSERT_EQUAL(nullptr, getNextTask(allTasks, dirtyTasks)); + uASSERT_EQUAL(nullptr, getNextTask({}, allTasks, dirtyTasks)); } { // Zero (One task, no dirty) @@ -187,7 +187,7 @@ public: uASSERT_EQUAL(0, task->registerDepTasks(allTasks)); } - uASSERT_EQUAL(nullptr, getNextTask(allTasks, dirtyTasks)); + uASSERT_EQUAL(nullptr, getNextTask({}, allTasks, dirtyTasks)); } { // One (One task, one dirty) @@ -205,7 +205,7 @@ public: uASSERT_EQUAL(0, task->registerDepTasks(allTasks)); } - uASSERT_EQUAL(task1, getNextTask(allTasks, dirtyTasks)); + uASSERT_EQUAL(task1, getNextTask({}, allTasks, dirtyTasks)); uASSERT_EQUAL(0u, dirtyTasks.size()); } @@ -226,7 +226,7 @@ public: uASSERT_EQUAL(0, task->registerDepTasks(allTasks)); } - uASSERT_EQUAL(task2, getNextTask(allTasks, dirtyTasks)); + uASSERT_EQUAL(task2, getNextTask({}, allTasks, dirtyTasks)); uASSERT_EQUAL(0u, dirtyTasks.size()); } @@ -250,7 +250,7 @@ public: uASSERT_EQUAL(0, task->registerDepTasks(allTasks)); } - uASSERT_EQUAL(task2, getNextTask(allTasks, dirtyTasks)); + uASSERT_EQUAL(task2, getNextTask({}, allTasks, dirtyTasks)); uASSERT_EQUAL(0u, dirtyTasks.size()); } @@ -275,7 +275,7 @@ public: uASSERT_EQUAL(0, task->registerDepTasks(allTasks)); } - uASSERT_EQUAL(task1, getNextTask(allTasks, dirtyTasks)); + uASSERT_EQUAL(task1, getNextTask({}, allTasks, dirtyTasks)); uASSERT_EQUAL(1u, dirtyTasks.size()); } } diff --git a/test/tmpfile.h b/test/tmpfile.h index 5d114d0..0f83a20 100644 --- a/test/tmpfile.h +++ b/test/tmpfile.h @@ -3,39 +3,29 @@ // See accompanying file LICENSE for details. #pragma once -#include <cstdlib> -#include <unistd.h> +#include <cstdio> -#ifdef _WIN32 -#define WIN32_LEAN_AND_MEAN -#include <windows.h> -#include <sys/types.h> -#include <sys/stat.h> -#include <fcntl.h> -#endif - -struct tmp_file +class TmpFile { - tmp_file(const std::string& data = {}) +public: + TmpFile(const std::string& data = {}) { - int fd; -#ifdef _WIN32 - char templ[] = "ctor_tmp_file-XXXXXX"; // buffer for filename - _mktemp_s(templ, sizeof(templ)); - fd = open(templ, O_CREAT | O_RDWR); -#else - char templ[] = "/tmp/ctor_tmp_file-XXXXXX"; // buffer for filename - fd = mkstemp(templ); -#endif - filename = templ; - auto sz = write(fd, data.data(), data.size()); - (void)sz; - close(fd); + auto tmp_dir = std::filesystem::temp_directory_path(); + auto tmp_file_template = tmp_dir / "ctor_tmp_file-"; + std::FILE* fp{nullptr}; + int counter{}; + while(!fp) + { + filename = tmp_file_template.string() + std::to_string(counter++); + fp = std::fopen(filename.data(), "wx"); + } + std::fwrite(data.data(), data.size(), 1, fp); + std::fclose(fp); } - ~tmp_file() + ~TmpFile() { - unlink(filename.data()); + std::filesystem::remove(filename); } const std::string& get() const |