diff options
Diffstat (limited to 'test')
| -rw-r--r-- | test/argparser_test.cc | 1019 | ||||
| -rw-r--r-- | test/ctor.cc | 337 | ||||
| -rw-r--r-- | test/cycle_test.cc | 14 | ||||
| -rw-r--r-- | test/execute_test.cc | 21 | ||||
| -rw-r--r-- | test/generated_sources_test.cc | 135 | ||||
| -rw-r--r-- | test/source_type_test.cc | 11 | ||||
| -rw-r--r-- | test/suite/ctor_files/ctor.cc.bar | 37 | ||||
| -rw-r--r-- | test/suite/ctor_files/ctor.cc.base | 37 | ||||
| -rw-r--r-- | test/suite/ctor_files/ctor.cc.generated | 104 | ||||
| -rw-r--r-- | test/suite/ctor_files/ctor.cc.generated2 | 87 | ||||
| -rw-r--r-- | test/suite/ctor_files/ctor.cc.multi | 37 | ||||
| -rw-r--r-- | test/suite/test.cc | 370 | ||||
| -rwxr-xr-x | test/suite/test.sh | 120 | ||||
| -rw-r--r-- | test/tasks_test.cc | 30 | ||||
| -rw-r--r-- | test/tmpfile.h | 44 | ||||
| -rw-r--r-- | test/tools_test.cc | 23 |
16 files changed, 2011 insertions, 415 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..d1c0188 100644 --- a/test/ctor.cc +++ b/test/ctor.cc @@ -8,198 +8,221 @@ namespace ctor::build_configurations ctorTestConfigs(const ctor::settings& settings) { return - { { - .type = ctor::target_type::unit_test, - .system = ctor::output_system::build, - .target = "argsplit_test", - .sources = { - "argsplit_test.cc", - "testmain.cc", - "../src/util.cc", + { + ctor::target_type::unit_test, + ctor::output_system::build, + ctor::target("argparser_test"), + ctor::sources{ + "argparser_test.cc", + "testmain.cc", + }, + ctor::cxx_flags{ + "-std=c++20", "-O3", "-Wall", + "-I../src", "-Iuunit", + "-DOUTPUT=\"argparser\"", + "-fexceptions", + }, }, - .flags = { - .cxxflags = { - "-std=c++20", "-O3", "-Wall", "-Werror", + { + ctor::target_type::unit_test, + ctor::output_system::build, + ctor::target("generated_sources_test"), + ctor::sources{ + "generated_sources_test.cc", + "testmain.cc", + "../configuration.cc", + }, + ctor::depends({"libctor_nomain.a"}), + ctor::cxx_flags{ + "-std=c++20", "-O3", "-Wall", "-I../src", "-Iuunit", - "-DOUTPUT=\"argsplit\"", + "-DOUTPUT=\"generated_sources\"", + "-fexceptions", }, }, - }, - { - .type = ctor::target_type::unit_test, - .system = ctor::output_system::build, - .target = "pointerlist_test", - .sources = { - "pointerlist_test.cc", - "testmain.cc", - "../src/pointerlist.cc", + { + ctor::target_type::unit_test, + ctor::output_system::build, + ctor::target("argsplit_test"), + ctor::sources{ + "argsplit_test.cc", + "testmain.cc", + "../src/util.cc", + }, + ctor::cxx_flags{ + "-std=c++20", "-O3", "-Wall", + "-I../src", "-Iuunit", + "-DOUTPUT=\"argsplit\"", + "-fexceptions", + }, }, - .flags = { - .cxxflags = { - "-std=c++20", "-O3", "-Wall", "-Werror", + { + ctor::target_type::unit_test, + ctor::output_system::build, + ctor::target("pointerlist_test"), + ctor::sources{ + "pointerlist_test.cc", + "testmain.cc", + "../src/pointerlist.cc", + }, + ctor::cxx_flags{ + "-std=c++20", "-O3", "-Wall", "-I../src", "-Iuunit", "-DOUTPUT=\"pointerlist\"", + "-fexceptions", }, }, - }, - { - .type = ctor::target_type::unit_test, - .system = ctor::output_system::build, - .target = "deps_test", - .sources = { - "deps_test.cc", - "testmain.cc", - "../src/deps.cc", - "../src/util.cc", - }, - .depends = { "testprog", }, - .flags = { - .cxxflags = { - "-std=c++20", "-O3", "-Wall", "-Werror", + { + ctor::target_type::unit_test, + ctor::output_system::build, + ctor::target("deps_test"), + ctor::sources{ + "deps_test.cc", + "testmain.cc", + "../src/deps.cc", + "../src/util.cc", + }, + ctor::depends({"testprog"}), + ctor::cxx_flags{ + "-std=c++20", "-O3", "-Wall", "-I../src", "-Iuunit", "-DOUTPUT=\"deps\"", + "-fexceptions", }, }, - }, - { - .type = ctor::target_type::unit_test, - .system = ctor::output_system::build, - .target = "testprog", - .sources = { - "testprog.cc", - }, - .flags = { - .cxxflags = { - "-std=c++20", "-O3", "-Wall", "-Werror", + { + ctor::target_type::unit_test, + ctor::output_system::build, + ctor::target("testprog"), + ctor::sources{ + "testprog.cc", + }, + ctor::cxx_flags{ + "-std=c++20", "-O3", "-Wall", + "-fexceptions", }, }, - }, - { - .type = ctor::target_type::unit_test, - .system = ctor::output_system::build, - .target = "execute_test", - .sources = { - "execute_test.cc", - "testmain.cc", - "../src/execute.cc", - "../src/pointerlist.cc", - "../src/util.cc", - }, - .depends = { "testprog", }, - .flags = { - .cxxflags = { - "-std=c++20", "-O3", "-Wall", "-Werror", + { + ctor::target_type::unit_test, + ctor::output_system::build, + ctor::target("execute_test"), + ctor::sources{ + "execute_test.cc", + "testmain.cc", + "../src/execute.cc", + "../src/pointerlist.cc", + "../src/util.cc", + }, + ctor::depends({"testprog"}), + ctor::cxx_flags{ + "-std=c++20", "-O3", "-Wall", "-I../src", "-Iuunit", "-DOUTPUT=\"execute\"", + "-fexceptions", }, - .ldflags = { "-pthread" }, - }, - }, - { - .type = ctor::target_type::unit_test, - .system = ctor::output_system::build, - .target = "tasks_test", - .sources = { - "tasks_test.cc", - "testmain.cc", - }, - .depends = { "libctor_nomain.a" }, - .flags = { - .cxxflags = { - "-std=c++20", "-O3", "-Wall", "-Werror", + ctor::ld_flags{ "-pthread" }, + }, + { + ctor::target_type::unit_test, + ctor::output_system::build, + ctor::target("tasks_test"), + ctor::sources{ + "tasks_test.cc", + "testmain.cc", + }, + ctor::depends({"libctor_nomain.a"}), + ctor::cxx_flags{ + "-std=c++20", "-O3", "-Wall", "-I../src", "-Iuunit", "-DOUTPUT=\"tasks\"", + "-fexceptions", }, - .ldflags = { "-pthread" }, - }, - }, - { - .type = ctor::target_type::unit_test, - .system = ctor::output_system::build, - .target = "cycle_test", - .sources = { - "cycle_test.cc", - "testmain.cc", - }, - .depends = { "libctor_nomain.a" }, - .flags = { - .cxxflags = { - "-std=c++20", "-O3", "-Wall", "-Werror", + ctor::ld_flags{ "-pthread" }, + }, + { + ctor::target_type::unit_test, + ctor::output_system::build, + ctor::target("cycle_test"), + ctor::sources{ + "cycle_test.cc", + "testmain.cc", + "../configuration.cc", + }, + ctor::depends({"libctor_nomain.a"}), + ctor::cxx_flags{ + "-std=c++20", "-O3", "-Wall", "-I../src", "-Iuunit", "-DOUTPUT=\"cycle\"", + "-fexceptions", }, - .ldflags = { "-pthread" }, - }, - }, - { - .type = ctor::target_type::unit_test, - .system = ctor::output_system::build, - .target = "source_type_test", - .sources = { - "source_type_test.cc", - "testmain.cc", - }, - .depends = { "libctor_nomain.a" }, - .flags = { - .cxxflags = { - "-std=c++20", "-O3", "-Wall", "-Werror", + ctor::ld_flags{ "-pthread" }, + }, + { + ctor::target_type::unit_test, + ctor::output_system::build, + ctor::target("source_type_test"), + ctor::sources{ + "source_type_test.cc", + "testmain.cc", + "../configuration.cc", + }, + ctor::depends({"libctor_nomain.a"}), + ctor::cxx_flags{ + "-std=c++20", "-O3", "-Wall", "-I../src", "-Iuunit", "-DOUTPUT=\"source_type\"", + "-fexceptions", }, - .ldflags = { "-pthread" }, - }, - }, - { - .type = ctor::target_type::unit_test, - .system = ctor::output_system::build, - .target = "tools_test", - .sources = { - "tools_test.cc", - "testmain.cc", - "../src/util.cc", - "../src/tools.cc", - }, - //.depends = { "libctor_nomain.a" }, - .flags = { - .cxxflags = { - "-std=c++20", "-O3", "-Wall", "-Werror", + ctor::ld_flags{ "-pthread" }, + }, + { + ctor::target_type::unit_test, + ctor::output_system::build, + ctor::target("tools_test"), + ctor::sources{ + "tools_test.cc", + "testmain.cc", + "../configuration.cc", + }, + ctor::depends({"libctor_nomain.a"}), + ctor::cxx_flags{ + "-std=c++20", "-O3", "-Wall", "-I../src", "-Iuunit", "-DOUTPUT=\"tools\"", + "-fexceptions", }, }, - }, - { - .type = ctor::target_type::unit_test_library, - .system = ctor::output_system::build, - .target = "libctor_nomain.a", - .sources = { - "../src/build.cc", - "../src/configure.cc", - "../src/deps.cc", - "../src/execute.cc", - "../src/pointerlist.cc", - "../src/rebuild.cc", - "../src/tasks.cc", - "../src/task.cc", - "../src/task_ar.cc", - "../src/task_cc.cc", - "../src/task_fn.cc", - "../src/task_ld.cc", - "../src/task_so.cc", - "../src/tools.cc", - "../src/util.cc", - "../src/externals_manual.cc", - }, - .flags = { - .cxxflags = { - "-std=c++20", "-O3", "-Wall", "-Werror", + { + ctor::target_type::unit_test_library, + ctor::output_system::build, + ctor::target("libctor_nomain.a"), + ctor::sources{ + "../src/build.cc", + "../src/configure.cc", + "../src/deps.cc", + "../src/execute.cc", + "../src/pointerlist.cc", + "../src/rebuild.cc", + "../src/tasks.cc", + "../src/task.cc", + "../src/task_ar.cc", + "../src/task_cc.cc", + "../src/task_fn.cc", + "../src/task_ld.cc", + "../src/task_so.cc", + "../src/tools.cc", + "../src/util.cc", + "../src/externals_manual.cc", + }, + ctor::cxx_flags{ + "-std=c++20", "-O3", "-Wall", "-I../src", + "-fexceptions", }, - .ldflags = { "-pthread" }, + ctor::ld_flags{ "-pthread" }, }, - }, - }; + }; } } diff --git a/test/cycle_test.cc b/test/cycle_test.cc index 3b45632..8f4c296 100644 --- a/test/cycle_test.cc +++ b/test/cycle_test.cc @@ -11,23 +11,23 @@ ctor::build_configurations ctorTestConfigsCyclic(const ctor::settings&) { // No dependency { - .target = "target0", + ctor::target("target0"), }, // Direct (self-depends) { - .target = "target1", - .depends = { "target1" }, + ctor::target("target1"), + ctor::depends({ "target1" }), }, // Indirect cyclic depends { - .target = "target2", - .depends = { "target3" }, + ctor::target("target2"), + ctor::depends({ "target3" }), }, { - .target = "target3", - .depends = { "target2" }, + ctor::target("target3"), + ctor::depends({ "target2" }), }, }; } diff --git a/test/execute_test.cc b/test/execute_test.cc index 722b6ea..f8f902f 100644 --- a/test/execute_test.cc +++ b/test/execute_test.cc @@ -23,6 +23,8 @@ public: void return_value() { + constexpr int segfault_return_value = 11; + constexpr int exception_return_value = 6; ctor::settings s; auto cur_path = std::filesystem::path(paths::argv_0).parent_path(); std::vector<std::string> paths{{cur_path.string()}}; @@ -31,16 +33,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 +60,7 @@ public: auto cmd = locate("testprog", paths); uASSERT(!cmd.empty()); - tmp_file tmp; + TmpFile tmp; std::map<std::string, std::string> env; @@ -83,11 +90,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/generated_sources_test.cc b/test/generated_sources_test.cc new file mode 100644 index 0000000..29a48fc --- /dev/null +++ b/test/generated_sources_test.cc @@ -0,0 +1,135 @@ +// -*- c++ -*- +// Distributed under the BSD 2-Clause License. +// See accompanying file LICENSE for details. +#include <uunit.h> + +#include <ctor.h> +#include <tasks.h> +#include <rebuild.h> + +class GeneratedSourcesTest + : public uUnit +{ +public: + GeneratedSourcesTest() + { + uTEST(GeneratedSourcesTest::test_custom_output); + uTEST(GeneratedSourcesTest::test_many_to_one_output); + } + + void setup() + { + // Make sure we start from a clean slate + getConfigFileList().clear(); + } + + void test_custom_output() + { + using namespace std::string_literals; + + ctor::reg( + [](const ctor::settings&) + { + return ctor::build_configurations{ + { + ctor::target("test1"), + ctor::sources{ + {"foo.cc", ctor::source_type::generated} + }, + }, + { + ctor::target("this_is_unused"), + ctor::sources{ + {"bar.x", ctor::output_file{"foo.cc"}}, + {"bar.y", ctor::output_file{"bar.cc"}}, + }, + []([[maybe_unused]]const std::string& input, + [[maybe_unused]]const std::string& output, + [[maybe_unused]]const ctor::build_configuration& config, + [[maybe_unused]]const ctor::settings& settings) + { + return 0; + }, + }, + }; + }); + ctor::settings settings{}; + auto tasks = getTasks(settings); + for(auto task : tasks) + { + uASSERT(task->registerDepTasks(tasks) == 0); + } + uASSERT_EQUAL(4u, tasks.size()); + bool found{false}; + for(const auto& task : tasks) + { + if(task->target() == "test1") + { + auto deps_test1 = task->getDependsTasks(); + uASSERT_EQUAL(1u, deps_test1.size()); + auto deps_foo_o = deps_test1[0]->getDependsTasks(); + uASSERT_EQUAL(1u, deps_foo_o.size()); + uASSERT_EQUAL("test/bar.x"s, deps_foo_o[0]->source()); + found = true; + } + } + uASSERT(found); + } + + void test_many_to_one_output() + { + using namespace std::string_literals; + + ctor::reg( + [](const ctor::settings&) + { + return ctor::build_configurations{ + { + ctor::target("test1"), + ctor::sources{ + {"foo.cc", ctor::source_type::generated} + }, + }, + { + ctor::target("foo.cc"), + ctor::sources{ + "bar.x", + "bar.y", + }, + []([[maybe_unused]]const std::vector<std::string>& input, + [[maybe_unused]]const std::string& output, + [[maybe_unused]]const ctor::build_configuration& config, + [[maybe_unused]]const ctor::settings& settings) + { + return 0; + }, + }, + }; + }); + ctor::settings settings{}; + auto tasks = getTasks(settings); + for(auto task : tasks) + { + uASSERT(task->registerDepTasks(tasks) == 0); + } + uASSERT_EQUAL(4u, tasks.size()); + bool found{false}; + for(const auto& task : tasks) + { + if(task->target() == "test1") + { + auto deps_test1 = task->getDependsTasks(); + uASSERT_EQUAL(1u, deps_test1.size()); + auto deps_foo_o = deps_test1[0]->getDependsTasks(); + uASSERT_EQUAL(1u, deps_foo_o.size()); + uASSERT_EQUAL("test/bar.x"s, deps_foo_o[0]->source()); + found = true; + } + } + uASSERT(found); + } + +}; + +// Registers the fixture into the 'registry' +static GeneratedSourcesTest test; diff --git a/test/source_type_test.cc b/test/source_type_test.cc index 288f1e5..345c591 100644 --- a/test/source_type_test.cc +++ b/test/source_type_test.cc @@ -26,12 +26,21 @@ std::ostream& operator<<(std::ostream& stream, const ctor::language& lang) return stream; } +const ctor::configuration& test_configuration() +{ + static ctor::configuration cfg{}; + cfg.build_toolchain = ctor::toolchain::gcc; + cfg.build_arch = ctor::arch::unix; + return cfg; +} +REG(test_configuration); + class TestableTaskCC : public TaskCC { public: TestableTaskCC(const ctor::source& source) - : TaskCC({}, {}, "build", source) + : TaskCC(ctor::target_type::object, {}, {}, "build", source) {} ctor::language language() const diff --git a/test/suite/ctor_files/ctor.cc.bar b/test/suite/ctor_files/ctor.cc.bar index 218f9cc..d77eb70 100644 --- a/test/suite/ctor_files/ctor.cc.bar +++ b/test/suite/ctor_files/ctor.cc.bar @@ -11,21 +11,20 @@ ctor::build_configurations ctorConfigs(const ctor::settings& settings) return { { - .name = "hello", - .target = "hello", - .sources = { + ctor::name("hello"), + ctor::target("hello"), + ctor::sources{ "hello.cc", }, - .flags = { - .cxxflags = { - "-std=c++20", - "-O3", - "-g", - "-Wall", - "-Werror", - }, + ctor::cxx_flags{ + "-std=c++20", + "-O3", + "-g", + "-Wall", + "-Werror", + "-fexceptions", }, - .externals = {"bar"}, + ctor::externals({"bar"}), } }; } @@ -35,14 +34,12 @@ ctor::external_configurations ctorExtConfigs(const ctor::settings& settings) return { { - .name = "bar", - .external = ctor::external_manual{ - .flags = { - .cflags = { "-D_B_" }, - .cxxflags = { "-D_A_", "-DBAR"}, - .ldflags = { "-D_C_" }, - .asmflags = { "-D_D_" }, - }, + ctor::name("bar"), + ctor::external_manual{ + ctor::c_flags{ "-D_B_" }, + ctor::cxx_flags{ "-D_A_", "-DBAR"}, + ctor::ld_flags{ "-D_C_" }, + ctor::asm_flags{ "-D_D_" }, }, // Creates --with-foo-prefix arg to configure which will be used for // -L and -I flags. diff --git a/test/suite/ctor_files/ctor.cc.base b/test/suite/ctor_files/ctor.cc.base index eab39c4..73b5cdb 100644 --- a/test/suite/ctor_files/ctor.cc.base +++ b/test/suite/ctor_files/ctor.cc.base @@ -11,21 +11,20 @@ ctor::build_configurations ctorConfigs(const ctor::settings& settings) return { { - .name = "hello", - .target = "hello", - .sources = { + ctor::name("hello"), + ctor::target("hello"), + ctor::sources{ "hello.cc", }, - .flags = { - .cxxflags = { - "-std=c++20", - "-O3", - "-g", - "-Wall", - "-Werror", - }, + ctor::cxx_flags{ + "-std=c++20", + "-O3", + "-g", + "-Wall", + "-Werror", + "-fexceptions", }, - .externals = {"bar"}, + ctor::externals({"bar"}), } }; } @@ -35,15 +34,13 @@ ctor::external_configurations ctorExtConfigs(const ctor::settings& settings) return { { - .name = "bar", - .external = ctor::external_manual + ctor::name("bar"), + ctor::external_manual { - .flags = { - .cflags = { "-D_B_" }, - .cxxflags = { "-D_A_", "-DFOO"}, - .ldflags = { "-D_C_" }, - .asmflags = { "-D_D_" }, - }, + ctor::c_flags{ "-D_B_" }, + ctor::cxx_flags{ "-D_A_", "-DFOO"}, + ctor::ld_flags{ "-D_C_" }, + ctor::asm_flags{ "-D_D_" }, }, // Creates --with-foo-prefix arg to configure which will be used for // -L and -I flags. diff --git a/test/suite/ctor_files/ctor.cc.generated b/test/suite/ctor_files/ctor.cc.generated new file mode 100644 index 0000000..96b6fb5 --- /dev/null +++ b/test/suite/ctor_files/ctor.cc.generated @@ -0,0 +1,104 @@ +// -*- c++ -*- +// Distributed under the BSD 2-Clause License. +// See accompanying file LICENSE for details. +#include <ctor.h> +#include <filesystem> +#include <iostream> +#include <fstream> + +namespace +{ +ctor::build_configurations ctorConfigs(const ctor::settings& settings) +{ + return + { + { + ctor::target("world"), + ctor::sources{ + { "world.cc", ctor::source_type::generated }, + }, + ctor::cxx_flags{ + "-std=c++20", + "-O3", + "-g", + "-Wall", + "-Werror", + "-fexceptions", + }, + }, + { + ctor::target("foo"), + ctor::sources{ + { "foo.cc", ctor::source_type::generated }, + }, + ctor::cxx_flags{ + "-std=c++20", + "-O3", + "-g", + "-Wall", + "-Werror", + "-fexceptions", + }, + }, + { + ctor::target("this_is_unused"), + ctor::sources{ + {"hello.cc", ctor::output_file{"world.cc"}}, + {"hello.cc", ctor::output_file{"foo.cc"}}, + }, + [](const std::string& input, + const std::string& output, + const ctor::build_configuration& config, + const ctor::settings& settings) + { + namespace fs = std::filesystem; + std::cout << "Input: " << input << '\n'; + std::cout << "Output: " << output << '\n'; + fs::copy_file(input, output, fs::copy_options::overwrite_existing); + return 0; + }, + }, + + { + ctor::target("many_to_one"), + ctor::sources{ + {"many_to_one.cc", ctor::source_type::generated} + }, + ctor::cxx_flags{"-fexceptions"}, + }, + { + ctor::target("many_to_one.cc"), + ctor::sources{ + {"foo.cc", ctor::source_type::generated}, + {"hello.cc"}, + }, + [](const std::vector<std::string>& input, + const std::string& output, + const ctor::build_configuration& config, + const ctor::settings& settings) + { + std::cout << "Output: " << output << '\n'; + std::ofstream ofs(output); + bool comment{true}; + for(const auto& input_file : input) + { + std::cout << "Input: " << input_file << '\n'; + std::ifstream ifs(input_file); + std::string line; + while(std::getline(ifs, line)) + { + ofs << line << '\n'; + } + if(comment) ofs << "/*\n"; + comment = false; + } + ofs << "*/\n"; + return 0; + } + }, + + }; +} +} + +REG(ctorConfigs); diff --git a/test/suite/ctor_files/ctor.cc.generated2 b/test/suite/ctor_files/ctor.cc.generated2 new file mode 100644 index 0000000..2e36c0e --- /dev/null +++ b/test/suite/ctor_files/ctor.cc.generated2 @@ -0,0 +1,87 @@ +// -*- c++ -*- +// Distributed under the BSD 2-Clause License. +// See accompanying file LICENSE for details. +#include <ctor.h> +#include <filesystem> +#include <iostream> +#include <fstream> + +namespace +{ +ctor::build_configurations ctorConfigs(const ctor::settings& settings) +{ + return + { + { + ctor::target("world"), + ctor::sources{ + { "world.cc", ctor::source_type::generated }, + }, + }, + { + ctor::target("foo"), + ctor::sources{ + { "foo.cc", ctor::source_type::generated }, + }, + }, + { + ctor::target("this_is_unused"), + ctor::sources{ + {"hello.cc", ctor::output_file{"world.cc"}}, + {"hello.cc", ctor::output_file{"foo.cc"}}, + }, + [](const std::string& input, + const std::string& output, + const ctor::build_configuration& config, + const ctor::settings& settings) + { + namespace fs = std::filesystem; + std::cout << "Input: " << input << '\n'; + std::cout << "Output: " << output << '\n'; + fs::copy_file(input, output, fs::copy_options::overwrite_existing); + return 0; + } + }, + + { + ctor::target("many_to_one"), + ctor::sources{ + {"many_to_one.cc", ctor::source_type::generated} + }, + ctor::cxx_flags{ "-fexceptions", }, + }, + { + ctor::target("many_to_one.cc"), + ctor::sources{ + {"hello.cc"}, + }, + [](const std::vector<std::string>& input, + const std::string& output, + const ctor::build_configuration& config, + const ctor::settings& settings) + { + std::cout << "Output: " << output << '\n'; + std::ofstream ofs(output); + bool comment{true}; + for(const auto& input_file : input) + { + std::cout << "Input: " << input_file << '\n'; + std::ifstream ifs(input_file); + std::string line; + while(std::getline(ifs, line)) + { + ofs << line << '\n'; + } + if(comment) ofs << "/*\n"; + comment = false; + } + ofs << "*/\n"; + return 0; + } + }, + + }; +} +} + +REG(ctorConfigs); diff --git a/test/suite/ctor_files/ctor.cc.multi b/test/suite/ctor_files/ctor.cc.multi index 2b88afe..fc4c7a4 100644 --- a/test/suite/ctor_files/ctor.cc.multi +++ b/test/suite/ctor_files/ctor.cc.multi @@ -13,21 +13,20 @@ ctor::build_configurations ctorConfigs(const ctor::settings& settings) return { { - .name = "hello", - .target = "hello", - .sources = { + ctor::name("hello"), + ctor::target("hello"), + ctor::sources{ "hello.cc", }, - .flags = { - .cxxflags = { - "-std=c++20", - "-O3", - "-g", - "-Wall", - "-Werror", - }, + ctor::cxx_flags{ + "-std=c++20", + "-O3", + "-g", + "-Wall", + "-Werror", + "-fexceptions", }, - .externals = {"bar"}, + ctor::externals({"bar"}), } }; } @@ -37,14 +36,12 @@ ctor::external_configurations ctorExtConfigs(const ctor::settings& settings) return { { - .name = "bar", - .external = ctor::external_manual{ - .flags = { - .cflags = { "-D_B_" }, - .cxxflags = { "-D_A_", "-DFOO"}, - .ldflags = { "-D_C_" }, - .asmflags = { "-D_D_" }, - }, + ctor::name("bar"), + ctor::external_manual{ + ctor::c_flags{ "-D_B_" }, + ctor::cxx_flags{ "-D_A_", "-DFOO"}, + ctor::ld_flags{ "-D_C_" }, + ctor::asm_flags{ "-D_D_" }, }, // Creates --with-foo-prefix arg to configure which will be used for // -L and -I flags. diff --git a/test/suite/test.cc b/test/suite/test.cc new file mode 100644 index 0000000..b096a8b --- /dev/null +++ b/test/suite/test.cc @@ -0,0 +1,370 @@ +// -*- c++ -*- +// Distributed under the BSD 2-Clause License. +// See accompanying file LICENSE for details. +#include "../../src/util.cc" +#include "../../src/pointerlist.cc" +#include "../../src/execute.cc" + +#include <iostream> +#include <string> +#include <filesystem> +#include <thread> +#include <chrono> +#include <sstream> + +using namespace std::chrono_literals; + +int fail(int value = 1, + const std::source_location location = std::source_location::current()) +{ + std::cout << "*** Failure at line " << location.line() << '\n'; + exit(value); +} + +const std::string ctor_exe{"./ctor"}; +const std::string obj_ext{".o"}; + +void run_ctor(const std::vector<std::string>& args, + const std::source_location location = std::source_location::current()) +{ + ctor::settings settings{.verbose = 2}; + auto ret = execute(settings, ctor_exe, args); + if(ret != 0) + { + fail(ret, location); + } +} + +void assert_not_exists(const std::string& path, + const std::source_location location = std::source_location::current()) +{ + if(std::filesystem::exists(path)) + { + fail(1, location); + } +} + +void assert_exists(const std::string& path, + const std::source_location location = std::source_location::current()) +{ + if(!std::filesystem::exists(path)) + { + fail(1, location); + } +} + +void copy_config(std::string cfg) +{ + std::cout << "** ctor_files/ctor.cc." + cfg + "\n"; + std::filesystem::copy("ctor_files/ctor.cc." + cfg, "ctor.cc", + std::filesystem::copy_options::overwrite_existing); + if(std::filesystem::exists(ctor_exe)) + { + auto ctor_exe_time = std::filesystem::last_write_time(ctor_exe); + std::filesystem::last_write_time("ctor.cc", ctor_exe_time + 1s); + } +} + +class Tracker +{ +public: + Tracker(const std::string& file_) : file(file_) + { + capture(); // capture initial value + } + + void capture() + { + changed(); + } + + bool changed() + { + auto tmp = readFile(file); + auto content_changed = tmp != content; + content = tmp; + return content_changed; + } + +private: + std::string file; + std::string content; +}; + +void assert_not_changed(Tracker& tracker, + const std::source_location location = std::source_location::current()) +{ + if(tracker.changed()) + { + fail(1, location); + } +} + +void assert_changed(Tracker& tracker, + const std::source_location location = std::source_location::current()) +{ + if(!tracker.changed()) + { + fail(1, location); + } +} + +int main() +{ + ctor::settings settings{}; + settings.verbose = 2; + auto paths = get_paths(); + + std::string CXX = "g++"; + get_env("CXX", CXX); + std::string CTORDIR = "../../build"; + get_env("CTORDIR", CTORDIR); + std::string BUILDDIR = "build"; + get_env("BUILDDIR", BUILDDIR); + std::string CXXFLAGS; + get_env("CXXFLAGS", CXXFLAGS); + std::string LDFLAGS; + get_env("LDFLAGS", LDFLAGS); + + // Wipe the board + std::filesystem::remove_all(BUILDDIR); + std::filesystem::remove("configuration.cc"); + std::filesystem::remove("config.h"); + std::filesystem::remove(ctor_exe); + + ////////////////////////////////////////////////////////////////////////////// + // bootstrap + { + auto cxx_prog = locate(CXX, paths); + + std::vector<std::string> args = + {"-pthread", "-std=c++20", "-L", CTORDIR, "-lctor", "-I", "../../src", + "ctor.cc", "-o", ctor_exe}; + if(!CXXFLAGS.empty()) + { + auto tokens = argsplit(CXXFLAGS); + for(const auto& token : tokens) + { + args.push_back(token); + } + } + if(!LDFLAGS.empty()) + { + auto tokens = argsplit(LDFLAGS); + for(const auto& token : tokens) + { + args.push_back(token); + } + } + + // Compile bootstrap binary + copy_config("base"); + auto ret = execute(settings, cxx_prog, args); + if(ret != 0) + { + fail(ret); + } + } + ////////////////////////////////////////////////////////////////////////////// + // check if source file changes are tracked + { + // No build files should have been created yet + assert_not_exists(BUILDDIR); + + // capture ctor binary before configure is called + Tracker ctor_bin(ctor_exe); + run_ctor( + {"configure", "--ctor-includedir", "../../src", + "--ctor-libdir=" + CTORDIR, "--build-dir=" + BUILDDIR}); + + // ctor should be rebuilt at this point, so binary should have changed + assert_changed(ctor_bin); + + // configuration.cc should have been generated now + assert_exists("configuration.cc"); + assert_exists("config.h"); + + // Shouldn't compile anything yet - only configure + assert_not_exists(BUILDDIR + "/hello-hello_cc" + obj_ext); + + ctor_bin.capture(); + + // Run normally to build project + run_ctor({"-v"}); + + // Compiled object should now exist + assert_exists(BUILDDIR + "/hello-hello_cc" + obj_ext); + + // ctor should not have been rebuilt, so binary should be the same + assert_not_changed(ctor_bin); + + std::this_thread::sleep_for(1100ms); + + auto time = + std::filesystem::last_write_time(BUILDDIR + "/hello-hello_cc" + obj_ext); + std::filesystem::last_write_time("hello.cc", time + 1s); + std::this_thread::sleep_for(1100ms); + + // Run normally to rebuild hello.cc + run_ctor({"-v"}); + + // Object file should have been recompiled + auto time2 = + std::filesystem::last_write_time(BUILDDIR + "/hello-hello_cc" + obj_ext); + if(time == time2) + { + fail(); + } + } + + ////////////////////////////////////////////////////////////////////////////// + // check if flags change trigger rebuild + { + // Replace -DFOO with -DBAR in foo external.cxxflags + copy_config("bar"); + Tracker configuration_cc_bin("configuration.cc"); + Tracker ctor_bin(ctor_exe); + auto time = + std::filesystem::last_write_time(BUILDDIR + "/hello-hello_cc" + obj_ext); + std::this_thread::sleep_for(1100ms); + + // Run normally to reconfigure, rebuild ctor and rebuild hello.cc + run_ctor({"-v"}); + + auto time2 = + std::filesystem::last_write_time(BUILDDIR + "/hello-hello_cc" + obj_ext); + if(time == time2) + { + fail(); + } + + assert_changed(configuration_cc_bin); + assert_changed(ctor_bin); + } + + ////////////////////////////////////////////////////////////////////////////// + // check if included files in ctor.cc is tracked for changes + { + copy_config("multi"); + Tracker configuration_cc_bin("configuration.cc"); + Tracker ctor_bin(ctor_exe); + auto time = + std::filesystem::last_write_time(BUILDDIR + "/hello-hello_cc" + obj_ext); + std::this_thread::sleep_for(1100ms); + + // Run normally to reconfigure, rebuild ctor and rebuild hello.cc + run_ctor({"-v"}); + + auto time2 = + std::filesystem::last_write_time(BUILDDIR + "/hello-hello_cc" + obj_ext); + if(time == time2) + { + fail(); + } + + assert_changed(configuration_cc_bin); + assert_changed(ctor_bin); + + // now touching foobar.h, should retrigger re-configuration + time = std::filesystem::last_write_time(ctor_exe); + std::filesystem::last_write_time("foobar.h", time + 1s); + std::this_thread::sleep_for(1100ms); + + // Run normally to reconfigure, rebuild ctor and rebuild hello.cc + run_ctor({"-v"}); + + time2 = std::filesystem::last_write_time(ctor_exe); + if(time == time2) + { + fail(); + } + } + + ////////////////////////////////////////////////////////////////////////////// + // generated part1: one-to-one generation + { + copy_config("generated"); + std::filesystem::remove(BUILDDIR + "/world.cc"); + std::filesystem::remove(BUILDDIR + "/foo.cc"); + + Tracker configuration_cc_bin("configuration.cc"); + Tracker ctor_bin(ctor_exe); + std::this_thread::sleep_for(1100ms); + + // Run normally to reconfigure, rebuild ctor and build world.cc + run_ctor({"-v", "world"}); + + assert_changed(configuration_cc_bin); + assert_changed(ctor_bin); + + // foo.cc should not be generated at this point + assert_not_exists(BUILDDIR+"/foo.cc"); + + auto time_w = std::filesystem::last_write_time(BUILDDIR + "/world.cc"); + auto time_wo = + std::filesystem::last_write_time(BUILDDIR + "/" + BUILDDIR+ + "/world-world_cc" + obj_ext); + std::this_thread::sleep_for(1100ms); + + // now touching hello.cc, should trigger regeneration of world.cc and + // rebuild + std::filesystem::last_write_time("hello.cc", time_w + 1s); + run_ctor({"-v", "world"}); + + auto time_w2 = std::filesystem::last_write_time(BUILDDIR + "/world.cc"); + auto time_wo2 = + std::filesystem::last_write_time(BUILDDIR + "/" + BUILDDIR + + "/world-world_cc" + obj_ext); + if(time_w == time_w2) + { + fail(); + } + if(time_wo == time_wo2) + { + fail(); + } + } + + ////////////////////////////////////////////////////////////////////////////// + // generated part2: many-to-one generation + { + std::filesystem::remove(BUILDDIR + "/world.cc"); + std::filesystem::remove(BUILDDIR + "/foo.cc"); + std::filesystem::remove(BUILDDIR + "/many_to_one.cc"); + + run_ctor({"-v", "many_to_one"}); + + // world.cc should not be generated at this point + assert_not_exists(BUILDDIR+"/world.cc"); + + // foo.cc should have been generated at this point + assert_exists(BUILDDIR+"/foo.cc"); + + // many_to_one.cc should have been generated + assert_exists(BUILDDIR+"/many_to_one.cc"); + + auto time = std::filesystem::last_write_time(BUILDDIR + "/many_to_one.cc"); + std::this_thread::sleep_for(1100ms); + + Tracker ctor_bin(ctor_exe); + + // remove "foo.cc" from sources list, so it only contains hello.cc + copy_config("generated2"); + + // rebuild + run_ctor({"-v", "many_to_one"}); + + // Verify that the change resulted in a ctor rebuild + assert_changed(ctor_bin); + + // Verify that source-list change triggered a new build of many_to_one.cc + auto time2 = + std::filesystem::last_write_time(BUILDDIR + "/many_to_one.cc"); + if(time == time2) + { + fail(); + } + } + + return 0; +} diff --git a/test/suite/test.sh b/test/suite/test.sh index 97d2551..4638c0d 100755 --- a/test/suite/test.sh +++ b/test/suite/test.sh @@ -1,122 +1,4 @@ #!/bin/bash : ${CXX:=g++} -: ${CTORDIR:=../../build} -: ${BUILDDIR:=build} -CXX=$(which $CXX) - -function fail -{ - echo "*** Failure at line $1" - exit 1 -} - -function ctor -{ - echo "*** Running: ./ctor $*" - ./ctor $* -} - -STAT_FORMAT="-c %Y" -if [[ "$OSTYPE" == "darwin"* ]]; then - # Mac OSX - STAT_FORMAT="-f %B" -fi - -# Wipe the board -rm -Rf ${BUILDDIR} -rm -f configuration.cc -rm -f ctor - -echo "** ctor_files/ctor.cc.base" -cp ctor_files/ctor.cc.base ctor.cc - -# Compile bootstrap binary -$CXX -pthread $LDFLAGS $CXXFLAGS -std=c++20 -L${CTORDIR} -lctor -I../../src ctor.cc -o ctor || fail ${LINENO} - -# No build files should have been created yet -[ -d ${BUILDDIR} ] && fail ${LINENO} - -# capture md5 sum of ctor binary before configure is called -MD5=`md5sum ctor` -ctor configure --ctor-includedir ../../src --ctor-libdir=${CTORDIR} --build-dir=${BUILDDIR} - -# ctor should be rebuilt at this point, so md5 sum should have changed -(echo $MD5 | md5sum --status -c) && fail ${LINENO} - -# configuration.cc should have been generated now -[ ! -f configuration.cc ] && fail ${LINENO} - -# Shouldn't compile anything yet - only configure -[ -f ${BUILDDIR}/hello-hello_cc.o ] && fail ${LINENO} - -MD5=`md5sum ctor` - -# Run normally to build project -ctor -v - -# Compiled object should now exist -[ ! -f ${BUILDDIR}/hello-hello_cc.o ] && fail ${LINENO} - -# ctor should not have been rebuilt, so md5 sum should be the same -(echo $MD5 | md5sum --status -c) || fail ${LINENO} - -MOD1=`stat $STAT_FORMAT ${BUILDDIR}/hello-hello_cc.o` -touch hello.cc -sleep 1.1 - -# Run normally to rebuild hello.cc -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 -echo "** ctor_files/ctor.cc.bar" -cp ctor_files/ctor.cc.bar ctor.cc - -MD5C=`md5sum configuration.cc` -MD5=`md5sum ctor` -MOD1=`stat $STAT_FORMAT build/hello-hello_cc.o` -sleep 1.1 - -# Run normally to reconfigure, rebuild ctor and rebuild hello.cc -ctor -v - -MOD2=`stat $STAT_FORMAT ${BUILDDIR}/hello-hello_cc.o` -[[ $MOD1 == $MOD2 ]] && fail ${LINENO} -(echo $MD5C | md5sum --status -c) && fail ${LINENO} -(echo $MD5 | md5sum --status -c) && fail ${LINENO} - -echo "** ctor_files/ctor.cc.multi" -cp ctor_files/ctor.cc.multi ctor.cc - -MD5C=`md5sum configuration.cc` -MD5=`md5sum ctor` -MOD1=`stat $STAT_FORMAT ${BUILDDIR}/hello-hello_cc.o` -sleep 1.1 - -# Run normally to reconfigure, rebuild ctor and rebuild hello.cc -ctor -v - -MOD2=`stat $STAT_FORMAT ${BUILDDIR}/hello-hello_cc.o` -[[ $MOD1 == $MOD2 ]] && fail ${LINENO} -(echo $MD5C | md5sum --status -c) && fail ${LINENO} -(echo $MD5 | md5sum --status -c) && fail ${LINENO} - -# now touching foobar.h, should retrigger re-configuration -touch foobar.h - -MOD1=`stat $STAT_FORMAT ctor` -sleep 1.1 - -# Run normally to reconfigure, rebuild ctor and rebuild hello.cc -ctor -v - -MOD2=`stat $STAT_FORMAT ctor` -[[ $MOD1 == $MOD2 ]] && fail ${LINENO} - -exit 0 +$CXX $LDFLAGS $CXXFLAGS -std=c++20 -Wall test.cc -o test && ./test diff --git a/test/tasks_test.cc b/test/tasks_test.cc index b444bd5..c8e4cf8 100644 --- a/test/tasks_test.cc +++ b/test/tasks_test.cc @@ -10,12 +10,12 @@ ctor::build_configurations ctorTestConfigs1(const ctor::settings&) return { { - .name = "Target1", - .target = "target1", - .sources = {"foo.cc", "bar.c"}, + ctor::name("Target1"), + ctor::target("target1"), + ctor::sources({"foo.cc", "bar.c"}), }, { - .target = "target2", + ctor::target("target2"), }, }; } @@ -25,10 +25,10 @@ ctor::build_configurations ctorTestConfigs2(const ctor::settings&) return { { - .target = "target3", + ctor::target("target3"), }, { - .target = "target4", + ctor::target("target4"), }, }; } @@ -38,14 +38,14 @@ namespace test_global { ctor::toolchain toolchain{}; ctor::arch arch{}; } -const ctor::configuration& ctor::get_configuration() +const ctor::configuration& test_configuration() { static ctor::configuration cfg{}; cfg.build_toolchain = test_global::toolchain; cfg.build_arch = test_global::arch; return cfg; } - +REG(test_configuration); REG(ctorTestConfigs1); REG(ctorTestConfigs2); @@ -72,7 +72,7 @@ public: const ctor::settings& settings, const std::string& name, bool dirty, const std::vector<std::string>& deps = {}) - : Task(config, settings, {}) + : Task(ctor::target_type::executable, config, settings, {}) , task_name(name) , task_dirty(dirty) , task_deps(deps) @@ -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 diff --git a/test/tools_test.cc b/test/tools_test.cc index 5ae04c3..cfbcbce 100644 --- a/test/tools_test.cc +++ b/test/tools_test.cc @@ -114,29 +114,6 @@ bool operator!=(const ctor::asm_flag& a, const ctor::asm_flag& b) #include <uunit.h> -const ctor::configuration& ctor::get_configuration() -{ - static ctor::configuration cfg; - return cfg; -} - -std::string ctor::configuration::get(const std::string& key, [[maybe_unused]]const std::string& default_value) const -{ - if(key == ctor::cfg::host_cxx) - { - return {}; - } - - if(key == ctor::cfg::build_cxx) - { - return {}; - } - - assert(false); // bad key - - return {}; -} - class ToolsTest : public uUnit { |
