summaryrefslogtreecommitdiff
path: root/test
diff options
context:
space:
mode:
Diffstat (limited to 'test')
-rw-r--r--test/argparser_test.cc1019
-rw-r--r--test/ctor.cc29
-rw-r--r--test/execute_test.cc26
-rw-r--r--test/source_type_test.cc8
-rwxr-xr-xtest/suite/test.sh4
-rw-r--r--test/testprog.cc38
-rw-r--r--test/tmpfile.h45
-rw-r--r--test/tools_test.cc3
8 files changed, 1139 insertions, 33 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..768708c 100644
--- a/test/ctor.cc
+++ b/test/ctor.cc
@@ -12,6 +12,23 @@ 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\"",
+ "-fexceptions",
+ },
+ },
+ },
+ {
+ .type = ctor::target_type::unit_test,
+ .system = ctor::output_system::build,
.target = "argsplit_test",
.sources = {
"argsplit_test.cc",
@@ -23,6 +40,7 @@ ctor::build_configurations ctorTestConfigs(const ctor::settings& settings)
"-std=c++20", "-O3", "-Wall", "-Werror",
"-I../src", "-Iuunit",
"-DOUTPUT=\"argsplit\"",
+ "-fexceptions",
},
},
},
@@ -40,6 +58,7 @@ ctor::build_configurations ctorTestConfigs(const ctor::settings& settings)
"-std=c++20", "-O3", "-Wall", "-Werror",
"-I../src", "-Iuunit",
"-DOUTPUT=\"pointerlist\"",
+ "-fexceptions",
},
},
},
@@ -58,7 +77,9 @@ ctor::build_configurations ctorTestConfigs(const ctor::settings& settings)
.cxxflags = {
"-std=c++20", "-O3", "-Wall", "-Werror",
"-I../src", "-Iuunit",
+ "-I../json/include",
"-DOUTPUT=\"deps\"",
+ "-fexceptions",
},
},
},
@@ -72,6 +93,7 @@ ctor::build_configurations ctorTestConfigs(const ctor::settings& settings)
.flags = {
.cxxflags = {
"-std=c++20", "-O3", "-Wall", "-Werror",
+ "-fexceptions",
},
},
},
@@ -92,6 +114,7 @@ ctor::build_configurations ctorTestConfigs(const ctor::settings& settings)
"-std=c++20", "-O3", "-Wall", "-Werror",
"-I../src", "-Iuunit",
"-DOUTPUT=\"execute\"",
+ "-fexceptions",
},
.ldflags = { "-pthread" },
},
@@ -110,6 +133,7 @@ ctor::build_configurations ctorTestConfigs(const ctor::settings& settings)
"-std=c++20", "-O3", "-Wall", "-Werror",
"-I../src", "-Iuunit",
"-DOUTPUT=\"tasks\"",
+ "-fexceptions",
},
.ldflags = { "-pthread" },
},
@@ -128,6 +152,7 @@ ctor::build_configurations ctorTestConfigs(const ctor::settings& settings)
"-std=c++20", "-O3", "-Wall", "-Werror",
"-I../src", "-Iuunit",
"-DOUTPUT=\"cycle\"",
+ "-fexceptions",
},
.ldflags = { "-pthread" },
},
@@ -146,6 +171,7 @@ ctor::build_configurations ctorTestConfigs(const ctor::settings& settings)
"-std=c++20", "-O3", "-Wall", "-Werror",
"-I../src", "-Iuunit",
"-DOUTPUT=\"source_type\"",
+ "-fexceptions",
},
.ldflags = { "-pthread" },
},
@@ -166,6 +192,7 @@ ctor::build_configurations ctorTestConfigs(const ctor::settings& settings)
"-std=c++20", "-O3", "-Wall", "-Werror",
"-I../src", "-Iuunit",
"-DOUTPUT=\"tools\"",
+ "-fexceptions",
},
},
},
@@ -195,6 +222,8 @@ ctor::build_configurations ctorTestConfigs(const ctor::settings& settings)
.cxxflags = {
"-std=c++20", "-O3", "-Wall", "-Werror",
"-I../src",
+ "-I../json/include",
+ "-fexceptions",
},
.ldflags = { "-pthread" },
},
diff --git a/test/execute_test.cc b/test/execute_test.cc
index 722b6ea..3cdb309 100644
--- a/test/execute_test.cc
+++ b/test/execute_test.cc
@@ -23,6 +23,13 @@ public:
void return_value()
{
+#if defined(_WIN32)
+ constexpr int segfault_return_value = 3;
+ constexpr int exception_return_value = 0xC0000409;
+#else
+ constexpr int segfault_return_value = 11;
+ constexpr int exception_return_value = 6;
+#endif
ctor::settings s;
auto cur_path = std::filesystem::path(paths::argv_0).parent_path();
std::vector<std::string> paths{{cur_path.string()}};
@@ -31,16 +38,21 @@ public:
auto value = execute(s, cmd, {"retval", "0"}, {}, false);
uASSERT_EQUAL(0, value);
+
value = execute(s, cmd, {"retval", "1"}, {}, false);
uASSERT_EQUAL(1, value);
+
value = execute(s, "no-such-binary", {}, {}, false);
uASSERT_EQUAL(1, value);
+
value = execute(s, cmd, {"segfault"}, {}, false);
- uASSERT_EQUAL(11, value);
+ uASSERT_EQUAL(segfault_return_value, value);
+
value = execute(s, cmd, {"throw"}, {}, false);
- uASSERT_EQUAL(6, value);
+ uASSERT_EQUAL(exception_return_value, value);
+
value = execute(s, cmd, {"abort"}, {}, false);
- uASSERT_EQUAL(6, value);
+ uASSERT_EQUAL(exception_return_value, value);
}
void env()
@@ -53,7 +65,7 @@ public:
auto cmd = locate("testprog", paths);
uASSERT(!cmd.empty());
- tmp_file tmp;
+ TmpFile tmp;
std::map<std::string, std::string> env;
@@ -83,11 +95,13 @@ public:
chk = std::find(vars.begin(), vars.end(), "bar=42"s);
uASSERT(chk != vars.end());
- // Check the one that should have overwritten the existing one (probably LANG=en_US.UTF-8 or something)
+ // Check the one that should have overwritten the existing one (probably
+ // LANG=en_US.UTF-8 or something)
chk = std::find(vars.begin(), vars.end(), "LANG=foo"s);
uASSERT(chk != vars.end());
- // Check that other vars are also there (ie. the env wasn't cleared on entry)
+ // Check that other vars are also there (ie. the env wasn't cleared on
+ // entry)
uASSERT(vars.size() > 3);
}
};
diff --git a/test/source_type_test.cc b/test/source_type_test.cc
index 288f1e5..657260e 100644
--- a/test/source_type_test.cc
+++ b/test/source_type_test.cc
@@ -26,6 +26,14 @@ std::ostream& operator<<(std::ostream& stream, const ctor::language& lang)
return stream;
}
+const ctor::configuration& ctor::get_configuration()
+{
+ static ctor::configuration cfg{};
+ cfg.build_toolchain = ctor::toolchain::gcc;
+ cfg.build_arch = ctor::arch::unix;
+ return cfg;
+}
+
class TestableTaskCC
: public TaskCC
{
diff --git a/test/suite/test.sh b/test/suite/test.sh
index 97d2551..ec603f5 100755
--- a/test/suite/test.sh
+++ b/test/suite/test.sh
@@ -1,4 +1,6 @@
#!/bin/bash
+#set -x
+
: ${CXX:=g++}
: ${CTORDIR:=../../build}
: ${BUILDDIR:=build}
@@ -70,8 +72,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/testprog.cc b/test/testprog.cc
index 93edc3f..18c2c74 100644
--- a/test/testprog.cc
+++ b/test/testprog.cc
@@ -5,6 +5,14 @@
extern char **environ;
+#if defined(_WIN32)
+#define WINDOWS_LEAN_AND_MEAN
+#include <windows.h>
+#undef max
+#else
+extern char **environ; // see 'man environ'
+#endif
+
int main(int argc, const char* argv[])
{
if(argc < 2)
@@ -20,11 +28,41 @@ int main(int argc, const char* argv[])
{
return 0;
}
+
std::ofstream ostrm(argv[2], std::ios::binary);
+ if(ostrm.bad())
+ {
+ std::cout << "Error: Could not write to " << argv[2] << "\n";
+ }
+#if defined(_WIN32)
+ auto env_strings = GetEnvironmentStrings();
+ const char* ptr = env_strings;
+ std::string env;
+ while(true)
+ {
+ if(*ptr == '\0')
+ {
+ if(env.empty())
+ {
+ // no more
+ break;
+ }
+ ostrm << env << "\n";
+ env.clear();
+ ++ptr;
+ continue;
+ }
+
+ env += *ptr;
+ ++ptr;
+ }
+ FreeEnvironmentStrings(env_strings);
+#else
for(auto current = environ; *current; ++current)
{
ostrm << (*current) << "\n";
}
+#endif
}
if(cmd == "retval")
diff --git a/test/tmpfile.h b/test/tmpfile.h
index 5d114d0..5887e36 100644
--- a/test/tmpfile.h
+++ b/test/tmpfile.h
@@ -3,39 +3,34 @@
// 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);
+ 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++);
+ // TODO: Use std::fstream.open() with openmode noreplace when using c++23
+#if defined(_WIN32)
+ fopen_s(&fp, filename.data(), "wx");
#else
- char templ[] = "/tmp/ctor_tmp_file-XXXXXX"; // buffer for filename
- fd = mkstemp(templ);
+ fp = std::fopen(filename.data(), "wx");
#endif
- filename = templ;
- auto sz = write(fd, data.data(), data.size());
- (void)sz;
- close(fd);
+ }
+ 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
diff --git a/test/tools_test.cc b/test/tools_test.cc
index 5ae04c3..15270b3 100644
--- a/test/tools_test.cc
+++ b/test/tools_test.cc
@@ -22,6 +22,9 @@ std::ostream& operator<<(std::ostream& stream, const ctor::toolchain& toolchain)
case ctor::toolchain::clang:
stream << "ctor::toolchain::clang";
break;
+ case ctor::toolchain::msvc:
+ stream << "ctor::toolchain::msvc";
+ break;
}
return stream;
}