forked from OctaForge/libostd
improved threaded test runner
parent
d359e46818
commit
b885e57fdb
1
build.sh
1
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
|
||||
|
|
|
@ -26,6 +26,7 @@
|
|||
#ifdef OSTD_BUILD_TESTS
|
||||
#include <cstdio>
|
||||
#include <cstddef>
|
||||
#include <utility>
|
||||
#include <vector>
|
||||
#include <string>
|
||||
#include <functional>
|
||||
|
@ -72,7 +73,7 @@ void fail_if_not(bool b) {
|
|||
}
|
||||
}
|
||||
|
||||
void run() {
|
||||
std::pair<int, int> 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 */
|
||||
|
|
146
test_runner.cc
146
test_runner.cc
|
@ -1,10 +1,14 @@
|
|||
#include <atomic>
|
||||
#include <unordered_map>
|
||||
|
||||
#include <ostd/platform.hh>
|
||||
#include <ostd/range.hh>
|
||||
#include <ostd/format.hh>
|
||||
#include <ostd/io.hh>
|
||||
#include <ostd/string.hh>
|
||||
#include <ostd/filesystem.hh>
|
||||
#include <ostd/environ.hh>
|
||||
#include <ostd/thread_pool.hh>
|
||||
|
||||
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 <ostd/unit_test.hh>\n"
|
||||
"#include <ostd/%s.hh>\n"
|
||||
"#include <ostd/io.hh>\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<std::string>();
|
||||
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<std::string>();
|
||||
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);
|
||||
}
|
||||
|
|
|
@ -1,9 +0,0 @@
|
|||
#define OSTD_BUILD_TESTS range
|
||||
|
||||
#include <ostd/unit_test.hh>
|
||||
#include <ostd/range.hh>
|
||||
|
||||
int main() {
|
||||
ostd::test::run();
|
||||
return 0;
|
||||
}
|
Loading…
Reference in New Issue