-
Notifications
You must be signed in to change notification settings - Fork 0
/
jester.hpp
131 lines (106 loc) · 2.9 KB
/
jester.hpp
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
131
#ifndef JESTER_HPP
#define JESTER_HPP
#include <iostream>
#include <stack>
#include <sstream>
#include <functional>
#include <map>
namespace jester {
bool assert_true(bool expression) {
if(!expression) throw std::runtime_error("Expression evaluated false");
return expression;
}
bool assert_false(bool expression) {
if(expression) throw std::runtime_error("Expression evaluated true");
return expression;
}
template <typename a_type, typename b_type>
bool assert_equal(a_type a, b_type b) {
const bool equal = (a == b);
if(!equal) {
std::stringstream detailed;
detailed << "Failed asserting that: "
<< "\x1B[33m"
<< a
<< "\x1B[0m"
<< " equals: "
<< "\x1B[33m"
<< b
<< "\x1B[0m";
throw std::runtime_error(detailed.str());
}
return equal;
}
struct test_context {
std::map<std::string, std::function<void()>>* tests;
std::function<void()> before_each;
std::function<void()> after_each;
};
std::stack<test_context*> contexts;
void describe(std::string name, std::function<void()> func) {
std::string prefix;
test_context context = { new std::map<std::string, std::function<void()>>()
};
auto& tests = *context.tests;
size_t failed = 0;
prefix.reserve(contexts.size() * 2);
for(int i = 0; i < contexts.size(); ++i) {
prefix += " ";
}
std::cout << prefix << name << std::endl;
contexts.push(&context);
try {
func();
} catch(const std::exception& e) {
failed++;
}
contexts.pop();
for(auto kv : tests) {
if(context.before_each) context.before_each();
try {
kv.second();
std::cout
<< prefix
<< "\x1B[32m"
<< " \u2714 "
<< kv.first
<< "\x1B[0m"
<< std::endl;
} catch(const std::exception& e) {
std::cout
<< prefix
<< "\x1B[31m"
<< " \u2716 "
<< kv.first
<< "\x1B[0m"
<< std::endl
<< prefix
<< e.what()
<< std::endl;
failed++;
}
if(context.after_each) context.after_each();
}
std::cout << std::endl;
if(contexts.size() == 0) {
if(failed > 0) {
std::cout << (failed) << " Test(s) failed" << std::endl;
} else {
std::cout << "OK" << std::endl;
}
}
if(failed > 0) {
throw std::runtime_error("Describe block failed");
}
}
void it(std::string name, std::function<void()> func) {
contexts.top()->tests->emplace(name, func);
}
void before_each(std::function<void()> func) {
contexts.top()->before_each = func;
}
void after_each(std::function<void()> func) {
contexts.top()->before_each = func;
}
}
#endif