diff --git a/build.sh b/build.sh index 5232700..c34da5c 100755 --- a/build.sh +++ b/build.sh @@ -236,6 +236,7 @@ build_example() { # build test runner build_test_runner() { + OSTD_CXXFLAGS="${OSTD_CXXFLAGS} -DOSTD_DEFAULT_LIB='\"${OSTD_DEFAULT_LIB}\"'" call_cxx test_runner.cc test_runner.o call_ld test_runner test_runner.o "$OSTD_DEFAULT_LIB" rm -f test_runner.o diff --git a/ostd/unit_test.hh b/ostd/unit_test.hh index 5360857..64d9a0e 100644 --- a/ostd/unit_test.hh +++ b/ostd/unit_test.hh @@ -26,6 +26,7 @@ #ifdef OSTD_BUILD_TESTS #include #include +#include #include #include #include @@ -72,7 +73,7 @@ void fail_if_not(bool b) { } } -void run() { +std::pair run() { int succ = 0, fail = 0; for (auto &f: test_cases) { try { @@ -83,18 +84,7 @@ void run() { } ++succ; } -#if defined(_WIN32) || defined(WIN32) - printf( - "%s...\t%d out of %d (%d failures)\n", - OSTD_TEST_MODULE, succ, succ + fail, fail - ); -#else - printf( - "%s...\t%s\033[1m%d out of %d\033[0m (%d failures)\n", - OSTD_TEST_MODULE, fail ? "\033[91m" : "\033[92m", - succ, succ + fail, fail - ); -#endif + return std::make_pair(succ, fail); } #else /* OSTD_BUILD_TESTS */ diff --git a/test_runner.cc b/test_runner.cc index f8a2fc1..faa45f3 100644 --- a/test_runner.cc +++ b/test_runner.cc @@ -1,10 +1,14 @@ +#include #include #include +#include +#include #include #include #include #include +#include using namespace ostd; @@ -20,80 +24,138 @@ constexpr auto COLOR_GREEN = ""; constexpr auto COLOR_BLUE = ""; constexpr auto COLOR_BOLD = ""; constexpr auto COLOR_END = ""; +#define popen _popen #endif +#ifndef OSTD_DEFAULT_LIB +#define OSTD_DEFAULT_LIB "libostd.a" +#endif + +static void write_test_src(file_stream &s, string_range modname) { + s.writefln( + "#define OSTD_BUILD_TESTS %s\n" + "\n" + "#include \n" + "#include \n" + "#include \n" + "\n" + "int main() {\n" + " auto [ succ, fail ] = ostd::test::run();\n" + " ostd::writeln(succ, \" \", fail);\n" + " return 0;\n" + "}", + modname, modname + ); +} + +static void write_padded(string_range s, std::size_t n) { + write(s, "..."); + if ((s.size() + 3) >= n) { + return; + } + for (size_t i = 0; i < (n - (s.size() + 3)); ++i) { + write(' '); + } +} + int main() { /* configurable section */ auto compiler = env_get("CXX").value_or("c++"); auto cxxflags = "-std=c++1z -I. -Wall -Wextra -Wshadow -Wold-style-cast " "-Wno-missing-braces"; /* clang false positive */ - auto testdir = env_get("TESTDIR").value_or("tests"); - auto srcext = ".cc"; auto userflags = env_get("CXXFLAGS").value_or(""); /* do not change past this point */ - int nsuccess = 0, nfailed = 0; - std::string modname; + std::atomic_int nsuccess = 0, nfailed = 0; - auto print_error = [&](string_range fmsg) { - write(modname, "...\t"); + auto print_error = [&](string_range modname, string_range fmsg) { + write_padded(modname, 20); writeln(COLOR_RED, COLOR_BOLD, '(', fmsg, ')', COLOR_END); ++nfailed; }; - filesystem::directory_iterator ds{testdir}; + ostd::thread_pool tpool; + tpool.start(std::thread::hardware_concurrency()); + + filesystem::directory_iterator ds{"ostd"}; for (auto &v: ds) { auto p = filesystem::path{v}; if ( (!filesystem::is_regular_file(p)) || - (p.extension().string() != srcext) + (p.extension().string() != ".hh") ) { continue; } - - modname = p.stem().string(); - - std::string exepath = testdir; - exepath += char(filesystem::path::preferred_separator); - exepath += modname; + tpool.push([&, modname = p.stem().string()]() { #ifdef OSTD_PLATFORM_WIN32 - exepath += ".exe"; + std::string exepath = ".\\test_"; + exepath += modname; + exepath += ".exe"; +#else + std::string exepath = "./test_"; + exepath += modname; #endif - auto cxxcmd = appender(); - format( - cxxcmd, "%s %s%s%s -o %s %s ", compiler, testdir, - char(filesystem::path::preferred_separator), - p.filename(), exepath, cxxflags - ); - if (!userflags.empty()) { - cxxcmd.get() += ' '; - cxxcmd.get() += userflags; - } - cxxcmd.get() += ' '; - cxxcmd.get() += "-DOSTD_BUILD_TESTS="; - cxxcmd.get() += modname; + auto cxxcmd = appender(); + format(cxxcmd, "%s -o %s %s", compiler, exepath, cxxflags); + if (!userflags.empty()) { + cxxcmd.get() += ' '; + cxxcmd.get() += userflags; + } + cxxcmd.get() += " -xc++ - -xnone "; + cxxcmd.get() += OSTD_DEFAULT_LIB; - int ret = system(cxxcmd.get().data()); - if (ret) { - print_error("compile errror"); - continue; - } + /* compile */ + auto cf = popen(cxxcmd.get().data(), "w"); + if (!cf) { + print_error(modname, "compile errror"); + return; + } - ret = system(exepath.data()); - if (ret) { - print_error("runtime error"); - continue; - } + file_stream cfs{cf}; + write_test_src(cfs, modname); - remove(exepath.data()); - ++nsuccess; + if (pclose(cf)) { + print_error(modname, "compile errror"); + return; + } + + /* run */ + auto rf = popen(exepath.data(), "r"); + if (!rf) { + print_error(modname, "runtime error"); + return; + } + + int succ = 0, fail = 0; + if (fscanf(rf, "%d %d", &succ, &fail) != 2) { + print_error(modname, "runtime error"); + } + + if (pclose(rf)) { + print_error(modname, "runtime error"); + return; + } + + write_padded(modname, 20); + writefln( + "%s%s%d out of %d%s (%d failures)", + fail ? COLOR_RED : COLOR_GREEN, COLOR_BOLD, + succ, succ + fail, COLOR_END, fail + ); + + remove(exepath.data()); + ++nsuccess; + }); } + /* wait for tasks */ + tpool.destroy(); + writeln("\n", COLOR_BLUE, COLOR_BOLD, "testing done:", COLOR_END); - writeln(COLOR_GREEN, "SUCCESS: ", nsuccess, COLOR_END); - writeln(COLOR_RED, "FAILURE: ", nfailed, COLOR_END); + writeln(COLOR_GREEN, "SUCCESS: ", int(nsuccess), COLOR_END); + writeln(COLOR_RED, "FAILURE: ", int(nfailed), COLOR_END); } diff --git a/tests/range.cc b/tests/range.cc deleted file mode 100644 index ae7e59c..0000000 --- a/tests/range.cc +++ /dev/null @@ -1,9 +0,0 @@ -#define OSTD_BUILD_TESTS range - -#include -#include - -int main() { - ostd::test::run(); - return 0; -}