cpp-ElementTree
Python ElementTree-alike XML API for C++
myunit.hpp
1 /*
2  * Copyright David Wilson, 2016.
3  * License: http://opensource.org/licenses/MIT
4  */
5 
6 #ifndef MYUNIT_H
7 #define MYUNIT_H
8 
28 #include <algorithm>
29 #include <cstdio>
30 #include <iostream>
31 #include <stdexcept>
32 #include <string>
33 #include <typeinfo>
34 #include <vector>
35 
36 
37 namespace myunit {
38 
39 
40 struct Test;
41 static inline std::string getUnitName(const char *n_);
42 static inline std::string getTestName(const Test *t);
43 typedef void (*test_func)();
44 
45 
50 struct Test {
51  std::string unit;
52  std::string name;
53  test_func func;
54 
55  Test(const char *file, const char *name_, test_func func_)
56  : name(name_)
57  , func(func_)
58  {
59  unit = getUnitName(file);
60  Test::getTests().push_back(this);
61  }
62 
63  static std::vector<Test*> &getTests() {
64  static std::vector<Test*> tests;
65  return tests;
66  }
67 };
68 
69 
74 struct TestSetup {
75  test_func func;
76 
77  TestSetup(test_func func_)
78  : func(func_)
79  {
80  TestSetup::getSetups().push_back(this);
81  }
82 
83  static std::vector<TestSetup*> &getSetups() {
84  static std::vector<TestSetup*> setups;
85  return setups;
86  }
87 };
88 
89 
90 static inline int
91 main(int argc, const char **argv)
92 {
93  for(auto setup : TestSetup::getSetups()) {
94  setup->func();
95  }
96 
97  auto filtered(Test::getTests());
98  filtered.erase(
99  std::remove_if(filtered.begin(), filtered.end(),
100  [&](const Test *x) {
101  return argc > 1 && !std::any_of(argv + 1, argv + argc,
102  [&](const char *substr) {
103  return getTestName(x).find(substr) != std::string::npos;
104  });
105  }),
106  filtered.end());
107 
108  std::sort(filtered.begin(), filtered.end(),
109  [](const Test *x, const Test *y) {
110  return getTestName(x) < getTestName(y);
111  });
112 
113  int run_count = 1;
114  if(getenv("RUN_COUNT")) {
115  run_count = std::stoi(getenv("RUN_COUNT"));
116  }
117 
118  std::cout << "Selected " << filtered.size() << " tests." << std::endl;
119  for(int i = 0; i < run_count; i++) {
120  for(auto test : filtered) {
121  std::cout << "Running " << getTestName(test) << " ..." << std::endl;
122  test->func();
123  }
124  }
125 
126  return 0;
127 }
128 
129 
134 static inline std::string
135 getUnitName(const char *n_)
136 {
137  std::string n(n_);
138  n = n.erase(n.find_last_of("."));
139 
140  size_t slash_p = n.find_last_of("/");
141  if(slash_p != std::string::npos) {
142  n = n.erase(0, 1+slash_p);
143  }
144 
145  return n;
146 }
147 
148 
149 static inline std::string
150 getTestName(const Test *t)
151 {
152  std::string out;
153  out.append(t->unit);
154  out.append(".");
155  out.append(t->name);
156  return out;
157 }
158 
159 
170 template<typename Exception,
171  typename Expr>
172 Exception
173 raises(Expr expr)
174 {
175  try {
176  (expr)();
177  std::string s;
178  s += "myunit :";
179  s += typeid(Exception).name();
180  s += " was not raised";
181  fprintf(stderr, "%s\n", s.c_str());
182  throw std::runtime_error(s);
183  } catch(Exception &e) {
184  return e;
185  }
186 }
187 
188 
189 } // ::myunit
190 
191 
192 #define MU_DEBUG(x, ...) \
193  fprintf(stderr, __FILE__ ": " x "\n", __VA_ARGS__);
194 
195 
196 #define MU_SETUP(name) \
197  static void setup_##name(); \
198  namespace myunit { \
199  static TestSetup _##name##_testsetup (&setup_##name); \
200  } \
201  static void setup_##name()
202 
203 
214 #define MU_TEST(name) \
215  static void test_##name(); \
216  namespace myunit { \
217  static Test _##name##_testinfo (__FILE__, #name, &test_##name); \
218  } \
219  static void test_##name()
220 
221 
227 #define MU_MAIN() \
228  int main(int argc, const char **argv) { \
229  return myunit::main(argc, argv); \
230  }
231 
232 
233 #endif /* !MYUNIT_H */
myunit: Ultra tiny test framework.
Definition: myunit.hpp:37
Internal descriptor for a function to be executed once during unit initialization.
Definition: myunit.hpp:74
Internal descriptor for a test case, tracks the name of the unit where the test was defined...
Definition: myunit.hpp:50
Exception raises(Expr expr)
Crash if an exception was not thrown.
Definition: myunit.hpp:173