stator
A math, geometry, and utility library
unit_test.hpp
Go to the documentation of this file.
1 /*
2  Copyright (C) 2017 Marcus Bannerman <[email protected]>
3 
4  This file is part of stator.
5 
6  stator is free software: you can redistribute it and/or modify
7  it under the terms of the GNU General Public License as published by
8  the Free Software Foundation, either version 3 of the License, or
9  (at your option) any later version.
10 
11  stator is distributed in the hope that it will be useful,
12  but WITHOUT ANY WARRANTY; without even the implied warranty of
13  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14  GNU General Public License for more details.
15 
16  You should have received a copy of the GNU General Public License
17  along with stator. If not, see <http://www.gnu.org/licenses/>.
18 */
19 
20 #pragma once
21 
22 #include <iostream>
23 #include <string>
24 #include <functional>
25 #include <vector>
26 #include <chrono>
27 #include <cmath>
28 
29 class UnitTests {
30 public:
31  UnitTests() : _error_counter(0) {}
32 
33  static UnitTests& get() {
34  static UnitTests instance;
35  return instance;
36  }
37 
38  void register_test(std::string name, std::function<void()> cb) {
39  _tests.emplace_back(name, cb);
40  }
41 
42  int run_tests() {
43  for (auto& test : _tests) {
44  std::cout << "### Running test: " << test._name << "\n";
45  _running_test_name = test._name;
46  auto start = std::chrono::steady_clock::now();
47  try {
48  test._callback();
49  } catch (std::exception& e) {
50  _error_counter += 1;
51  std::cerr << "Aborting test, exception thrown in \"" << test._name << "\":" << std::endl
52  << e.what() << std::endl;
53  break;
54  } catch (...) {
55  std::cerr << "Aborting all tests, uncaught exception!" << std::endl;
56  throw;
57  }
58  auto end = std::chrono::steady_clock::now();
59  std::cout << "## " << test._name << " complete in " << std::chrono::duration <double, std::nano> (end-start).count() / 1e6 << " ms" << std::endl;
60  }
61 
62  std::cout << "# Tests complete with " << _error_counter << " errors" << std::endl;
63  return _error_counter > 0;
64  }
65 
66  template<class L, class R>
67  void check_equal(const L& l, const R& r, std::string file, int line, std::string Lname, std::string Rname) {
68  if (l != r) {
69  ++_error_counter;
70  std::cerr << file << "(" << line << "): error in \"" << _running_test_name << "\": check " << Lname << " == " << Rname << " failed, " << l << " != " << r << std::endl;
71  }
72  }
73 
74  void check(bool l, std::string file, int line, std::string Lname) {
75  if (!l) {
76  ++_error_counter;
77  std::cerr << file << "(" << line << "): error in \"" << _running_test_name << "\": check " << Lname << " failed" << std::endl;
78  }
79  }
80 
81  template<class L, class R, class Tol_t>
82  void check_close(L l, R r, std::string file, int line, std::string Lname, std::string Rname, Tol_t tol)
83  {
84  double difference = std::max(std::abs(l - r) / std::abs(l), std::abs(l - r) / std::abs(r));
85 
86  if (l == 0)
87  difference = std::abs(r);
88 
89  //Check if the values are close
90  if (difference <= tol) return;
91 
92  ++_error_counter;
93  std::cerr << file << "(" << line << "): error in \"" << _running_test_name << "\": difference (" << difference*100 << "%) between " << Lname << "{"<<l<<"} and " << Rname << "{"<<r<<"} exceeds " << tol*100.00 << "%" << std::endl;
94  }
95 
96  template<class T, class Tol_t>
97  void check_small(T l, std::string file, int line, std::string Lname, Tol_t tol) {
98  if (!(std::abs(l) <= std::abs(tol))) {
99  ++_error_counter;
100  std::cerr << file << "(" << line << "): error in \"" << _running_test_name << "\": absolute value of " << Lname << "{"<<l<<"} exceeds " << tol << std::endl;
101  }
102  }
103 
104  void error(std::string msg, std::string file, int line) {
105  ++_error_counter;
106  std::cerr << file << "(" << line << "): error in \"" << _running_test_name << "\": " << msg << std::endl;
107  }
108 
109 private:
110  struct Test {
111  Test(std::string name, std::function<void()> cb): _name(name), _callback(cb) {}
112 
113  std::string _name;
114  std::function<void()> _callback;
115  };
116 
117  std::vector<Test> _tests;
118 
119  std::string _running_test_name;
120 
121  size_t _error_counter;
122 };
123 
125  UnitTestRegisterer(std::string name, std::function<void()> cb) {
126  UnitTests::get().register_test(name, cb);
127  };
128 };
129 
130 #define UNIT_TEST(A) void A(); UnitTestRegisterer A ## _reg(#A, A); void A()
131 
132 #define UNIT_TEST_CHECK_EQUAL(A, B) UnitTests::get().check_equal(A, B, __FILE__, __LINE__, #A, #B)
133 #define UNIT_TEST_CHECK(Expr) UnitTests::get().check(Expr, __FILE__, __LINE__, #Expr)
134 #define UNIT_TEST_CHECK_CLOSE(A, B, TOL) UnitTests::get().check_close(A, B, __FILE__, __LINE__, #A, #B, TOL)
135 #define UNIT_TEST_CHECK_SMALL(A, TOL) UnitTests::get().check_small(A, __FILE__, __LINE__, #A, TOL)
136 #define UNIT_TEST_ERROR(MSG) UnitTests::get().error(MSG, __FILE__, __LINE__)
137 
138 int main() {
139  try {
140  return UnitTests::get().run_tests();
141  } catch (const std::exception& e) {
142  std::cerr << "Unit tests aborting due to exception:\n" << e.what() << std::endl;
143  return 1;
144  }
145 }
void check(bool l, std::string file, int line, std::string Lname)
Definition: unit_test.hpp:74
detail::C_wrap< stator::constant_ratio::e >::type e
A symbolic/compile-time rational approximation of .
Definition: constants.hpp:59
UnitTestRegisterer(std::string name, std::function< void()> cb)
Definition: unit_test.hpp:125
static UnitTests & get()
Definition: unit_test.hpp:33
int main()
Definition: unit_test.hpp:138
void register_test(std::string name, std::function< void()> cb)
Definition: unit_test.hpp:38
void check_close(L l, R r, std::string file, int line, std::string Lname, std::string Rname, Tol_t tol)
Definition: unit_test.hpp:82
void error(std::string msg, std::string file, int line)
Definition: unit_test.hpp:104
void check_equal(const L &l, const R &r, std::string file, int line, std::string Lname, std::string Rname)
Definition: unit_test.hpp:67
constexpr C<(1 - 2 *(num< 0)) *num,(1 - 2 *(den< 0)) *den > abs(const C< num, den > &a)
Definition: constants.hpp:189
void check_small(T l, std::string file, int line, std::string Lname, Tol_t tol)
Definition: unit_test.hpp:97
int run_tests()
Definition: unit_test.hpp:42