wibble  1.1
tests.h
Go to the documentation of this file.
1 #ifndef WIBBLE_TESTS_H
2 #define WIBBLE_TESTS_H
3 
13 #include <string>
14 #include <sstream>
15 
16 #include <wibble/tests/tut.h>
18 
19 namespace wibble {
20 namespace tests {
21 struct Location;
22 struct LocationInfo;
23 }
24 }
25 
26 /*
27  * These global arguments will be shadowed by local variables in functions that
28  * implement tests.
29  *
30  * They are here to act as default root nodes to fulfill method signatures when
31  * tests are called from outside other tests.
32  */
35 
36 #define TESTGRP(name) \
37 typedef test_group<name ## _shar> tg; \
38 typedef tg::object to; \
39 tg name ## _tg (#name);
40 
41 
42 namespace wibble {
43 namespace tests {
44 
45 #define WIBBLE_TESTS_ALWAYS_THROWS __attribute__ ((noreturn))
46 
47 class Location
48 {
49  const Location* parent;
50  const wibble::tests::LocationInfo* info;
51  const char* file;
52  int line;
53  const char* args;
54 
55  Location(const Location* parent, const wibble::tests::LocationInfo& info, const char* file, int line, const char* args);
56 
57 public:
58  Location();
59  // legacy
60  Location(const char* file, int line, const char* args);
61  // legacy
62  Location(const Location& parent, const char* file, int line, const char* args);
63  Location nest(const wibble::tests::LocationInfo& info, const char* file, int line, const char* args=0) const;
64 
65  std::string locstr() const;
66  std::string msg(const std::string m) const;
67  void fail_test(const std::string& msg) const WIBBLE_TESTS_ALWAYS_THROWS;
68  void fail_test(const wibble::tests::LocationInfo& info, const char* file, int line, const char* args, const std::string& msg) const WIBBLE_TESTS_ALWAYS_THROWS;
69  void backtrace(std::ostream& out) const;
70 };
71 
72 struct LocationInfo : public std::stringstream
73 {
89  std::ostream& operator()();
91 };
92 
93 #define WIBBLE_TEST_LOCPRM wibble::tests::Location wibble_test_location
94 
97 #define WIBBLE_TEST_INFO(name) \
98  wibble::tests::LocationInfo wibble_test_location_info; \
99  wibble::tests::LocationInfo& name = wibble_test_location_info
100 
101 #define ensure(x) wibble::tests::impl_ensure(wibble::tests::Location(__FILE__, __LINE__, #x), (x))
102 #define inner_ensure(x) wibble::tests::impl_ensure(wibble::tests::Location(loc, __FILE__, __LINE__, #x), (x))
103 void impl_ensure(const Location& loc, bool res);
104 
105 #define ensure_equals(x, y) wibble::tests::impl_ensure_equals(wibble::tests::Location(__FILE__, __LINE__, #x " == " #y), (x), (y))
106 #define inner_ensure_equals(x, y) wibble::tests::impl_ensure_equals(wibble::tests::Location(loc, __FILE__, __LINE__, #x " == " #y), (x), (y))
107 
108 template <class Actual,class Expected>
109 void impl_ensure_equals(const Location& loc, const Actual& actual, const Expected& expected)
110 {
111  if( expected != actual )
112  {
113  std::stringstream ss;
114  ss << "expected '" << expected << "' actual '" << actual << "'";
115  loc.fail_test(ss.str());
116  }
117 }
118 
119 #define ensure_similar(x, y, prec) wibble::tests::impl_ensure_similar(wibble::tests::Location(__FILE__, __LINE__, #x " == " #y), (x), (y), (prec))
120 #define inner_ensure_similar(x, y, prec) wibble::tests::impl_ensure_similar(wibble::tests::Location(loc, __FILE__, __LINE__, #x " == " #y), (x), (y), (prec))
121 
122 template <class Actual, class Expected, class Precision>
123 void impl_ensure_similar(const Location& loc, const Actual& actual, const Expected& expected, const Precision& precision)
124 {
125  if( actual < expected - precision || expected + precision < actual )
126  {
127  std::stringstream ss;
128  ss << "expected '" << expected << "' actual '" << actual << "'";
129  loc.fail_test(ss.str());
130  }
131 }
132 
133 #define ensure_contains(x, y) wibble::tests::impl_ensure_contains(wibble::tests::Location(__FILE__, __LINE__, #x " == " #y), (x), (y))
134 #define inner_ensure_contains(x, y) wibblwibblempl_ensure_contains(wibble::tests::Location(loc, __FILE__, __LINE__, #x " == " #y), (x), (y))
135 void impl_ensure_contains(const wibble::tests::Location& loc, const std::string& haystack, const std::string& needle);
136 
137 #define ensure_not_contains(x, y) wibble::tests::impl_ensure_not_contains(wibble::tests::Location(__FILE__, __LINE__, #x " == " #y), (x), (y))
138 #define inner_ensure_not_contains(x, y) wibble::tests::impl_ensure_not_contains(wibble::tests::Location(loc, __FILE__, __LINE__, #x " == " #y), (x), (y))
139 void impl_ensure_not_contains(const wibble::tests::Location& loc, const std::string& haystack, const std::string& needle);
140 
141 
142 template<typename A>
143 struct TestBool
144 {
145  const A& actual;
146  bool inverted;
147  TestBool(const A& actual, bool inverted=false) : actual(actual), inverted(inverted) {}
148 
150 
152  {
153  if (!inverted)
154  {
155  if (actual) return;
156  wibble_test_location.fail_test("actual value is false");
157  } else {
158  if (!actual) return;
159  wibble_test_location.fail_test("actual value is true");
160  }
161  }
162 };
163 
164 template<typename A, typename E>
166 {
169  bool inverted;
170  TestEquals(const A& actual, const E& expected, bool inverted=false)
171  : actual(actual), expected(expected), inverted(inverted) {}
172 
175  {
176  if (!inverted)
177  {
178  if (actual == expected) return;
179  std::stringstream ss;
180  ss << "value '" << actual << "' is different than the expected '" << expected << "'";
181  wibble_test_location.fail_test(ss.str());
182  } else {
183  if (actual != expected) return;
184  std::stringstream ss;
185  ss << "value '" << actual << "' is not different than the expected '" << expected << "'";
186  wibble_test_location.fail_test(ss.str());
187  }
188  }
189 };
190 
191 template<typename A, typename E>
192 struct TestIsLt
193 {
196  bool inverted;
197  TestIsLt(const A& actual, const E& expected, bool inverted=false)
198  : actual(actual), expected(expected), inverted(inverted) {}
199 
202  {
203  if (!inverted)
204  {
205  if (actual < expected) return;
206  std::stringstream ss;
207  ss << "value '" << actual << "' is not less than the expected '" << expected << "'";
208  wibble_test_location.fail_test(ss.str());
209  } else {
210  if (!(actual < expected)) return;
211  std::stringstream ss;
212  ss << "value '" << actual << "' is less than the expected '" << expected << "'";
213  wibble_test_location.fail_test(ss.str());
214  }
215  }
216 };
217 
218 template<typename A, typename E>
219 struct TestIsLte
220 {
223  bool inverted;
224  TestIsLte(const A& actual, const E& expected, bool inverted=false) : actual(actual), expected(expected), inverted(inverted) {}
225 
228  {
229  if (!inverted)
230  {
231  if (actual <= expected) return;
232  std::stringstream ss;
233  ss << "value '" << actual << "' is not less than or equals to the expected '" << expected << "'";
234  wibble_test_location.fail_test(ss.str());
235  } else {
236  if (!(actual <= expected)) return;
237  std::stringstream ss;
238  ss << "value '" << actual << "' is less than or equals to the expected '" << expected << "'";
239  wibble_test_location.fail_test(ss.str());
240  }
241  }
242 };
243 
244 template<typename A, typename E>
245 struct TestIsGt
246 {
249  bool inverted;
250  TestIsGt(const A& actual, const E& expected, bool inverted=false) : actual(actual), expected(expected), inverted(inverted) {}
251 
254  {
255  if (!inverted)
256  {
257  if (actual > expected) return;
258  std::stringstream ss;
259  ss << "value '" << actual << "' is not greater than the expected '" << expected << "'";
260  wibble_test_location.fail_test(ss.str());
261  } else {
262  if (!(actual > expected)) return;
263  std::stringstream ss;
264  ss << "value '" << actual << "' is greater than the expected '" << expected << "'";
265  wibble_test_location.fail_test(ss.str());
266  }
267  }
268 };
269 
270 template<typename A, typename E>
271 struct TestIsGte
272 {
275  bool inverted;
276  TestIsGte(const A& actual, const E& expected, bool inverted=false) : actual(actual), expected(expected), inverted(inverted) {}
277 
280  {
281  if (!inverted)
282  {
283  if (actual >= expected) return;
284  std::stringstream ss;
285  ss << "value '" << actual << "' is not greater than or equals to the expected '" << expected << "'";
286  wibble_test_location.fail_test(ss.str());
287  } else {
288  if (!(actual >= expected)) return;
289  std::stringstream ss;
290  ss << "value '" << actual << "' is greater than or equals to the expected '" << expected << "'";
291  wibble_test_location.fail_test(ss.str());
292  }
293  }
294 };
295 
297 {
298  std::string actual;
299  std::string expected;
300  bool inverted;
301  TestStartsWith(const std::string& actual, const std::string& expected, bool inverted=false) : actual(actual), expected(expected), inverted(inverted) {}
302 
304  void check(WIBBLE_TEST_LOCPRM) const;
305 };
306 
308 {
309  std::string actual;
310  std::string expected;
311  bool inverted;
312  TestEndsWith(const std::string& actual, const std::string& expected, bool inverted=false) : actual(actual), expected(expected), inverted(inverted) {}
313 
315  void check(WIBBLE_TEST_LOCPRM) const;
316 };
317 
319 {
320  std::string actual;
321  std::string expected;
322  bool inverted;
323  TestContains(const std::string& actual, const std::string& expected, bool inverted=false) : actual(actual), expected(expected), inverted(inverted) {}
324 
326  void check(WIBBLE_TEST_LOCPRM) const;
327 };
328 
330 {
331  std::string actual;
332  std::string regexp;
333  bool inverted;
334  TestRegexp(const std::string& actual, const std::string& regexp, bool inverted=false) : actual(actual), regexp(regexp), inverted(inverted) {}
335 
337  void check(WIBBLE_TEST_LOCPRM) const;
338 };
339 
341 {
342  std::string pathname;
343  bool inverted;
344  TestFileExists(const std::string& pathname, bool inverted=false) : pathname(pathname), inverted(inverted) {}
346  void check(WIBBLE_TEST_LOCPRM) const;
347 };
348 
349 
350 template<class A>
351 struct Actual
352 {
354  Actual(const A& actual) : actual(actual) {}
355  ~Actual() {}
356 
357  template<typename E> TestEquals<A, E> operator==(const E& expected) const { return TestEquals<A, E>(actual, expected); }
358  template<typename E> TestEquals<A, E> operator!=(const E& expected) const { return !TestEquals<A, E>(actual, expected); }
359  template<typename E> TestIsLt<A, E> operator<(const E& expected) const { return TestIsLt<A, E>(actual, expected); }
360  template<typename E> TestIsLte<A, E> operator<=(const E& expected) const { return TestIsLte<A, E>(actual, expected); }
361  template<typename E> TestIsGt<A, E> operator>(const E& expected) const { return TestIsGt<A, E>(actual, expected); }
362  template<typename E> TestIsGte<A, E> operator>=(const E& expected) const { return TestIsGte<A, E>(actual, expected); }
363  TestBool<A> istrue() const { return TestBool<A>(actual); }
364  TestBool<A> isfalse() const { return TestBool<A>(actual, true); }
365 };
366 
367 struct ActualString : public Actual<std::string>
368 {
369  ActualString(const std::string& s) : Actual<std::string>(s) {}
370  TestEquals<std::string, std::string> operator==(const std::string& expected) const { return TestEquals<std::string, std::string>(actual, expected); }
371  TestEquals<std::string, std::string> operator!=(const std::string& expected) const { return !TestEquals<std::string, std::string>(actual, expected); }
372  TestIsLt<std::string, std::string> operator<(const std::string& expected) const { return TestIsLt<std::string, std::string>(actual, expected); }
373  TestIsLte<std::string, std::string> operator<=(const std::string& expected) const { return TestIsLte<std::string, std::string>(actual, expected); }
374  TestIsGt<std::string, std::string> operator>(const std::string& expected) const { return TestIsGt<std::string, std::string>(actual, expected); }
375  TestIsGte<std::string, std::string> operator>=(const std::string& expected) const { return TestIsGte<std::string, std::string>(actual, expected); }
376  TestStartsWith startswith(const std::string& expected) const { return TestStartsWith(actual, expected); }
377  TestEndsWith endswith(const std::string& expected) const { return TestEndsWith(actual, expected); }
378  TestContains contains(const std::string& expected) const { return TestContains(actual, expected); }
379  TestRegexp matches(const std::string& regexp) const { return TestRegexp(actual, regexp); }
381 };
382 
383 template<typename A>
384 inline Actual<A> actual(const A& actual) { return Actual<A>(actual); }
385 inline ActualString actual(const std::string& actual) { return ActualString(actual); }
386 inline ActualString actual(const char* actual) { return ActualString(actual ? actual : ""); }
387 inline ActualString actual(char* actual) { return ActualString(actual ? actual : ""); }
388 
389 /*
390 template<typename T, typename P>
391 void _wassert(WIBBLE_TEST_LOCPRM, T& a, P& op)
392 {
393  op.invoke(wibble_test_location, a);
394 }
395 */
396 
397 template<typename T>
398 static inline void _wassert(WIBBLE_TEST_LOCPRM, const T& expr)
399 {
400  expr.check(wibble_test_location);
401 }
402 
403 
404 #define wibble_test_runner(loc, func, ...) \
405  do { try { \
406  func(loc, ##__VA_ARGS__); \
407  } catch (tut::failure) { \
408  throw; \
409  } catch (std::exception& e) { \
410  loc.fail_test(e.what()); \
411  } } while(0)
412 
413 #define wrunchecked(func) \
414  do { try { \
415  func; \
416  } catch (tut::failure) { \
417  throw; \
418  } catch (std::exception& e) { \
419  wibble_test_location.fail_test(wibble_test_location_info, __FILE__, __LINE__, #func, e.what()); \
420  } } while(0)
421 
422 // function test, just runs the function without mangling its name
423 #define wruntest(test, ...) wibble_test_runner(wibble_test_location.nest(wibble_test_location_info, __FILE__, __LINE__, "function: " #test "(" #__VA_ARGS__ ")"), test, ##__VA_ARGS__)
424 
425 #define wassert(...) wibble_test_runner(wibble_test_location.nest(wibble_test_location_info, __FILE__, __LINE__, #__VA_ARGS__), _wassert, ##__VA_ARGS__)
426 
427 }
428 }
429 
430 #endif