libwreport  3.42
testrunner.h
1 #ifndef WREPORT_TESTSRUNNER_H
2 #define WREPORT_TESTSRUNNER_H
3 
4 #include <functional>
5 #include <memory>
6 #include <string>
7 #include <vector>
8 
9 namespace wreport::term {
10 struct Terminal;
11 }
12 
13 namespace wreport::tests {
14 
15 struct TestFailed;
16 struct TestStack;
17 struct TestCase;
18 struct TestMethod;
19 
24 {
26  std::string test_case;
27 
29  std::string test_method;
30 
32  std::string error_message;
33 
35  std::shared_ptr<TestStack> error_stack;
36 
38  std::string exception_typeid;
39 
41  bool skipped = false;
42 
44  std::string skipped_reason;
45 
47  unsigned long long elapsed_ns = 0;
48 
49  TestMethodResult(const std::string& test_case_,
50  const std::string& test_method_)
51  : test_case(test_case_), test_method(test_method_)
52  {
53  }
54 
55  void set_failed(TestFailed& e);
56 
57  void set_exception(std::exception& e)
58  {
59  error_message = e.what();
60  if (error_message.empty())
62  "test threw an exception with an empty error message";
63  exception_typeid = typeid(e).name();
64  }
65 
66  void set_unknown_exception() { error_message = "unknown exception caught"; }
67 
68  void set_setup_exception(std::exception& e)
69  {
70  error_message = "[setup failed: ";
71  error_message += e.what();
72  error_message += "]";
73  }
74 
75  void set_teardown_exception(std::exception& e)
76  {
77  error_message = "[teardown failed: ";
78  error_message += e.what();
79  error_message += "]";
80  }
81 
82  bool is_success() const { return error_message.empty(); }
83 
84  void print_failure_details(FILE* out) const;
85 };
86 
91 {
93  std::string test_case;
95  std::vector<TestMethodResult> methods;
97  std::string fail_setup;
100  std::string fail_teardown;
102  bool skipped = false;
103 
104  explicit TestCaseResult(const std::string& test_case_)
105  : test_case(test_case_)
106  {
107  }
108 
109  void set_setup_failed()
110  {
111  fail_setup = "test case setup method threw an unknown exception";
112  }
113 
114  void set_setup_failed(std::exception& e)
115  {
116  fail_setup = "test case setup method threw an exception: ";
117  fail_setup += e.what();
118  }
119 
120  void set_teardown_failed()
121  {
122  fail_teardown = "test case teardown method threw an unknown exception";
123  }
124 
125  void set_teardown_failed(std::exception& e)
126  {
127  fail_teardown = "test case teardown method threw an exception: ";
128  fail_teardown += e.what();
129  }
130 
131  void add_test_method(TestMethodResult&& e)
132  {
133  methods.emplace_back(std::move(e));
134  }
135 
136  bool is_success() const
137  {
138  if (!fail_setup.empty() || !fail_teardown.empty())
139  return false;
140  for (const auto& m : methods)
141  if (!m.is_success())
142  return false;
143  return true;
144  }
145 
146  unsigned long long elapsed_ns() const;
147 };
148 
156 {
157  virtual ~TestController() {}
158 
165  virtual bool test_case_begin(const TestCase&, const TestCaseResult&)
166  {
167  return true;
168  }
169 
173  virtual void test_case_end(const TestCase&, const TestCaseResult&) {}
174 
181  virtual bool test_method_begin(const TestMethod&, const TestMethodResult&)
182  {
183  return true;
184  }
185 
189  virtual void test_method_end(const TestMethod&, const TestMethodResult&) {}
190 };
191 
197 {
199  std::string allowlist = std::string();
200 
202  std::string blocklist = std::string();
203 
204  bool test_method_should_run(const std::string& fullname) const;
205 };
206 
214 {
215  wreport::term::Terminal& output;
216 
218 
219  bool test_case_begin(const TestCase& test_case,
220  const TestCaseResult& test_case_result) override;
221  void test_case_end(const TestCase& test_case,
222  const TestCaseResult& test_case_result) override;
223  bool test_method_begin(const TestMethod& test_method,
224  const TestMethodResult& test_method_result) override;
225  void test_method_end(const TestMethod& test_method,
226  const TestMethodResult& test_method_result) override;
227 };
228 
236 {
237  wreport::term::Terminal& output;
238 
240 
241  bool test_case_begin(const TestCase& test_case,
242  const TestCaseResult& test_case_result) override;
243  void test_case_end(const TestCase& test_case,
244  const TestCaseResult& test_case_result) override;
245  bool test_method_begin(const TestMethod& test_method,
246  const TestMethodResult& test_method_result) override;
247  void test_method_end(const TestMethod& test_method,
248  const TestMethodResult& test_method_result) override;
249 };
250 
258 {
260  std::vector<TestCase*> entries = std::vector<TestCase*>();
261 
268  void register_test_case(TestCase& test_case);
269 
277  std::function<void(const TestCase&, const TestMethod&)>);
278 
282  std::vector<TestCaseResult> run_tests(TestController& controller);
283 
285  static TestRegistry& get();
286 };
287 
289 {
290  const std::vector<TestCaseResult>& results;
291  unsigned methods_ok = 0;
292  unsigned methods_failed = 0;
293  unsigned methods_skipped = 0;
294  unsigned test_cases_ok = 0;
295  unsigned test_cases_failed = 0;
296  bool success = false;
297  bool skipped = false;
298 
299  TestResultStats(const std::vector<TestCaseResult>& results);
300 
301  void print_results(wreport::term::Terminal& out);
302  void print_stats(wreport::term::Terminal& out);
303  void print_summary(wreport::term::Terminal& out);
304 };
305 
306 } // namespace wreport::tests
307 #endif
Test registry.
Definition: testrunner.h:257
bool test_method_begin(const TestMethod &test_method, const TestMethodResult &test_method_result) override
Called before running a test method.
std::string blocklist
Any method matching this glob expression will not be run.
Definition: testrunner.h:202
std::string skipped_reason
If the test has been skipped, this is an optional reason.
Definition: testrunner.h:44
Utility functions for the unit tests.
Definition: tests.h:38
bool test_case_begin(const TestCase &test_case, const TestCaseResult &test_case_result) override
Called before running a test case.
std::string exception_typeid
If non-empty, the test threw an exception and this is its type ID.
Definition: testrunner.h:38
void test_method_end(const TestMethod &test_method, const TestMethodResult &test_method_result) override
Called after running a test method.
Result of running a whole test case.
Definition: testrunner.h:90
Test case collecting several test methods, and self-registering with the singleton instance of TestRe...
Definition: utils/tests.h:702
std::string allowlist
Any method not matching this glob expression will not be run.
Definition: testrunner.h:199
void test_case_end(const TestCase &test_case, const TestCaseResult &test_case_result) override
Called after running a test case.
std::shared_ptr< TestStack > error_stack
Stack frame of where the error happened.
Definition: testrunner.h:35
std::string test_method
Name of the test method.
Definition: testrunner.h:29
std::vector< TestMethodResult > methods
Outcome of all the methods that have been run.
Definition: testrunner.h:95
Simple default implementation of TestController.
Definition: testrunner.h:213
Abstract interface for the objects that supervise test execution.
Definition: testrunner.h:155
std::string fail_teardown
Set to a non-empty string if the teardown method of the test case failed.
Definition: testrunner.h:100
Definition: testrunner.h:288
bool skipped
Set to true if this test case has been skipped.
Definition: testrunner.h:102
std::vector< TestCaseResult > run_tests(TestController &controller)
Run all the registered tests using the given controller.
Exception thrown when a test assertion fails, normally by Location::fail_test.
Definition: utils/tests.h:103
void register_test_case(TestCase &test_case)
Register a new test case.
Contrl terminal output.
Definition: term.h:14
unsigned long long elapsed_ns
Time in nanoseconds it took the test to run.
Definition: testrunner.h:47
std::vector< TestCase * > entries
All known test cases.
Definition: testrunner.h:260
std::string test_case
Name of the test case.
Definition: testrunner.h:93
bool skipped
True if the test has been skipped.
Definition: testrunner.h:41
Definition: term.h:16
Verbose implementation of TestController.
Definition: testrunner.h:235
Result of running a test method.
Definition: testrunner.h:23
void iterate_test_methods(std::function< void(const TestCase &, const TestMethod &)>)
Iterate on all test methods known by this registry.
std::string error_message
If non-empty, the test failed with this error.
Definition: testrunner.h:32
void test_method_end(const TestMethod &test_method, const TestMethodResult &test_method_result) override
Called after running a test method.
virtual void test_case_end(const TestCase &, const TestCaseResult &)
Called after running a test case.
Definition: testrunner.h:173
virtual void test_method_end(const TestMethod &, const TestMethodResult &)
Called after running a test method.
Definition: testrunner.h:189
Test method information.
Definition: utils/tests.h:675
virtual bool test_case_begin(const TestCase &, const TestCaseResult &)
Called before running a test case.
Definition: testrunner.h:165
std::string fail_setup
Set to a non-empty string if the setup method of the test case failed.
Definition: testrunner.h:97
Test controller that filters tests via a blocklist/allowlist system containing glob patterns on testc...
Definition: testrunner.h:196
std::string test_case
Name of the test case.
Definition: testrunner.h:26
virtual bool test_method_begin(const TestMethod &, const TestMethodResult &)
Called before running a test method.
Definition: testrunner.h:181
bool test_method_begin(const TestMethod &test_method, const TestMethodResult &test_method_result) override
Called before running a test method.
bool test_case_begin(const TestCase &test_case, const TestCaseResult &test_case_result) override
Called before running a test case.
void test_case_end(const TestCase &test_case, const TestCaseResult &test_case_result) override
Called after running a test case.