forked from girving/mandelbrot
-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathtests.cc
130 lines (114 loc) · 3.79 KB
/
tests.cc
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
// Very simple testing infrastructure
#include "tests.h"
#include "print.h"
#include "shutdown.h"
#include "wall_time.h"
#include <functional>
#include <unistd.h>
#include <unordered_set>
#include <filesystem>
namespace mandelbrot {
using std::exception;
using std::function;
using std::tuple;
using std::unordered_set;
typedef vector<tuple<string,function<void()>>> Tests;
static Tests& tests() { static Tests tests; return tests; }
int register_test(const char* name, void (*test)()) {
tests().emplace_back(name, test);
return 0;
}
void test_throw(const function<void()>& f, const char* sx, const char* se, const char* function, const int line) {
try {
f();
} catch (const exception& e) {
const string s = typeid(e).name();
if (s.find(string(se)) != string::npos)
return;
print("%s %s threw %s, not %s", red(format("%s:%d:", function, line)), sx, s, se);
throw test_error();
}
print("%s %s didn't throw %s", red(format("%s:%d:", function, line)), sx, se);
throw test_error();
}
Tmpfile::Tmpfile(string_view prefix) {
string p = "/tmp/" + string(prefix) + "XXXXXX";
const int fd = mkstemp(p.data());
slow_assert(fd >= 0, strerror(errno));
const_cast<string&>(path) = p;
}
Tmpfile::~Tmpfile() {
if (path.size())
unlink(path.c_str());
}
Tmpdir::Tmpdir(string_view prefix) {
string p = "/tmp/" + string(prefix) + "XXXXXX";
slow_assert(mkdtemp(p.data()), strerror(errno));
const_cast<string&>(path) = p;
}
Tmpdir::~Tmpdir() {
if (path.size())
std::filesystem::remove_all(path);
}
// See https://stackoverflow.com/questions/2616906/how-do-i-output-coloured-text-to-a-linux-terminal
static string color(const string& s, const int color) { return format("\033[%dm%s\033[0m", color, s); }
string red(const string& s) { return color(s, 31); }
string green(const string& s) { return color(s, 32); }
string blue(const string& s) { return color(s, 34); }
static int run_tests(const vector<string>& args) {
const auto& tests = mandelbrot::tests();
const unordered_set<string> chosen(args.begin() + 1, args.end());
const auto skip = [&chosen](const string& name) {
return chosen.size() && chosen.find(name) == chosen.end();
};
const auto count = [](const int n) { return format("%d %s", n, n == 1 ? "test" : "tests"); };
wall_time_t total;
print("%s %s: %s", green("[==========]"), args[0], count(tests.size()));
// Log skipped tests
for (const auto& [name, test] : tests)
if (skip(name))
print("%s %s", blue("[ SKIP ]"), name);
// Run non-skipped tests
int passed = 0;
vector<string> failed;
for (const auto& [name, test] : tests) {
if (skip(name)) continue;
print("%s %s", green("[ RUN ]"), name);
const auto start = wall_time();
bool good;
try {
test();
good = true;
} catch (const test_error& e) {
good = false;
} catch (const exception& e) {
print(" %s %s, %s", red("exception:"), typeid(e).name(), e.what());
good = false;
}
const auto elapsed = wall_time() - start;
total += elapsed;
print("%s %s (%d ms)", good ? green("[ OK ]") : red("[ FAILED ]"),
name, int(rint(elapsed.milliseconds())));
if (good) passed++;
else failed.push_back(name);
}
// Finish up
print("%s %s ran (%d ms total)", green("[==========]"), count(tests.size()), int(rint(total.milliseconds())));
print("%s %s", green("[ PASSED ]"), count(passed));
if (failed.size()) {
print("%s %s", red("[ FAILED ]"), count(failed.size()));
for (const auto& name : failed)
print("%s %s", red("[ FAILED ]"), name);
}
shutdown();
return failed.size() ? 1 : 0;
}
} // namespace mandelbrot
using namespace mandelbrot;
int main(int argc, char** argv) {
try {
return run_tests({argv, argv + argc});
} catch (const exception& e) {
die(e.what());
}
}