]> git.tdb.fi Git - libs/test.git/blob - source/test.cpp
Initial commit
[libs/test.git] / source / test.cpp
1 #include <typeinfo>
2 #include <msp/debug/demangle.h>
3 #include <msp/io/print.h>
4 #include <msp/strings/utils.h>
5 #include "runner.h"
6 #include "test.h"
7
8 using namespace std;
9
10 namespace {
11
12 /* This makes the linker pull in the Runner class when linking msptest as a
13 static library */
14 void *dummy()
15 { return new Msp::Test::Runner(0, 0); }
16
17 }
18
19
20 namespace Msp {
21 namespace Test {
22
23 Test::Test(const string &n):
24         name(n)
25 { }
26
27 Test::~Test()
28 {
29         for(list<Function *>::iterator i=functions.begin(); i!=functions.end(); ++i)
30                 delete *i;
31 }
32
33 list<Test::Factory *> &Test::get_factories()
34 {
35         static list<Factory *> factories;
36         return factories;
37 }
38
39 void Test::run_single(const string &name, bool verbose)
40 {
41         const list<Factory *> &factories = get_factories();
42         for(list<Factory *>::const_iterator i=factories.begin(); i!=factories.end(); ++i)
43                 if((*i)->get_name()==name)
44                 {
45                         Test *test = (*i)->create();
46                         test->run(verbose);
47                         delete test;
48                 }
49 }
50
51 void Test::run_all(bool verbose)
52 {
53         const list<Factory *> &factories = get_factories();
54         IO::print("Running %d test suites\n", factories.size());
55         for(list<Factory *>::const_iterator i=factories.begin(); i!=factories.end(); ++i)
56         {
57                 Test *test = (*i)->create();
58                 test->run(verbose);
59                 delete test;
60         }
61 }
62
63 void Test::run(bool verbose)
64 {
65         IO::print("Running tests for %s\n", name);
66
67         unsigned n_passed = 0;
68         unsigned total = 0;
69         for(list<Function *>::const_iterator i=functions.begin(); i!=functions.end(); ++i)
70         {
71                 detail_info = string();
72                 detail_debug = string();
73                 passed = false;
74                 start_test((*i)->get_description());
75                 const ExceptionCheck *exc_check = (*i)->get_exception_check();
76                 try
77                 {
78                         (*i)->run(*this);
79                         if(exc_check)
80                                 fail_test("Exception expected but none thrown");
81                         else
82                                 pass_test();
83                 }
84                 catch(const test_failed &e)
85                 {
86                         fail_test(e.what());
87                 }
88                 catch(const exception &e)
89                 {
90                         if(exc_check && exc_check->check(e))
91                         {
92                                 pass_test();
93                                 debug(Debug::demangle(typeid(e).name()));
94                                 debug(e.what());
95                         }
96                         else
97                                 fail_test(e.what());
98                 }
99                 catch(...)
100                 {
101                         fail_test("Unknown object thrown");
102                 }
103
104                 if(verbose)
105                         detail_info += detail_debug;
106                 if(!detail_info.empty())
107                 {
108                         vector<string> lines = split(detail_info, '\n');
109                         for(vector<string>::const_iterator j=lines.begin(); j!=lines.end(); ++j)
110                                 IO::print("    %s\n", *j);
111                 }
112
113                 ++total;
114                 if(passed)
115                         ++n_passed;
116         }
117
118         IO::print("  %d/%d passed\n", n_passed, total);
119 }
120
121 void Test::start_test(const string &descr)
122 {
123         IO::print("  %s: ", descr);
124 }
125
126 void Test::pass_test()
127 {
128         IO::print("\033[32mok\033[0m\n");
129         ++passed;
130 }
131
132 void Test::fail_test(const string &why)
133 {
134         IO::print("\033[31mfailed\033[0m\n");
135         IO::print("    %s\n", why);
136 }
137
138 void Test::expect(bool cond, const string &expr)
139 {
140         if(!cond)
141                 throw test_failed(format("!(%s)", expr));
142         debug(expr);
143 }
144
145 void Test::info(const string &str)
146 {
147         detail_info += format("%s\n", str);
148 }
149
150 void Test::debug(const string &str)
151 {
152         detail_debug += format("%s\n", str);
153 }
154
155
156 Test::Factory::Factory()
157 {
158         get_factories().push_back(this);
159 }
160
161 } // namespace Test
162 } // namespace Msp