tut logo

tut.hpp Source File


tut.hpp
1 #ifndef TUT_H_GUARD
2 #define TUT_H_GUARD
3 #include <tut/tut_config.hpp>
4 
5 #include <iostream>
6 #include <map>
7 #include <vector>
8 #include <set>
9 #include <string>
10 #include <sstream>
11 #include <iterator>
12 #include <algorithm>
13 
14 #include "tut_exception.hpp"
15 #include "tut_result.hpp"
16 #include "tut_posix.hpp"
17 #include "tut_assert.hpp"
18 #include "tut_runner.hpp"
19 
20 #if defined(TUT_USE_SEH)
21 #include <windows.h>
22 #include <winbase.h>
23 #endif
24 
31 namespace tut
32 {
33 
34 template <class, int>
35 class test_group;
36 
42 template <class Data>
43 class test_object : public Data, public test_object_posix
44 {
45  template<class D, int M>
46  friend class test_group;
47 
48  void set_test_group(const char *group)
49  {
50  current_test_group_ = group;
51  }
52 
53  void set_test_id(int current_test_id)
54  {
55  current_test_id_ = current_test_id;
56  }
57 
58 public:
59 
65  current_test_id_(0),
66  current_test_name_(),
67  current_test_group_()
68  {
69  }
70 
71  void set_test_name(const std::string& current_test_name)
72  {
73  current_test_name_ = current_test_name;
74  }
75 
76  const std::string& get_test_name() const
77  {
78  return current_test_name_;
79  }
80 
81  const std::string& get_test_group() const
82  {
83  return current_test_group_;
84  }
85 
86  int get_test_id() const
87  {
88  return current_test_id_;
89  }
90 
94  template <int n>
95  void test()
96  {
98  }
99 
107 
108  virtual ~test_object()
109  {
110  }
111 
112 private:
113  int current_test_id_;
114  std::string current_test_name_;
115  std::string current_test_group_;
116 };
117 
118 
123 template <class Test, class Group, int n>
125 {
126  static void reg(Group& group)
127  {
128  group.reg(n, &Test::template test<n>);
130  }
131 };
132 
133 template <class Test, class Group>
134 struct tests_registerer<Test, Group, 0>
135 {
136  static void reg(Group&)
137  {
138  }
139 };
140 
146 template <class Data, int MaxTestsInGroup = 50>
147 class test_group : public group_base, public test_group_posix
148 {
149  test_group(const test_group&);
150  void operator=(const test_group&);
151 
152  const char* name_;
153 
154  typedef void (test_object<Data>::*testmethod)();
155  typedef std::map<int, testmethod> tests;
156  typedef typename tests::iterator tests_iterator;
157  typedef typename tests::const_iterator tests_const_iterator;
158  typedef typename tests::const_reverse_iterator
159  tests_const_reverse_iterator;
160  typedef typename tests::size_type size_type;
161 
162  tests tests_;
163  tests_iterator current_test_;
164 
165  enum seh_result
166  {
167  SEH_OK,
168 #if defined(TUT_USE_SEH)
169  SEH_CTOR,
170  SEH_TEST,
171 #endif
172  SEH_DUMMY
173  };
174 
178  template <class T>
179  class safe_holder
180  {
181  T* p_;
182  bool permit_throw_in_dtor;
183 
184  safe_holder(const safe_holder&);
185  safe_holder& operator=(const safe_holder&);
186 
187  public:
188  safe_holder()
189  : p_(0),
190  permit_throw_in_dtor(false)
191  {
192  }
193 
194  ~safe_holder()
195  {
196  release();
197  }
198 
199  T* operator->() const
200  {
201  return p_;
202  }
203 
204  T* get() const
205  {
206  return p_;
207  }
208 
214  void permit_throw()
215  {
216  permit_throw_in_dtor = true;
217  }
218 
225  void release()
226  {
227  try
228  {
229 #if defined(TUT_USE_SEH)
230  if (delete_obj() == false)
231  {
232  throw warning("destructor of test object raised"
233  " an SEH exception");
234  }
235 #else
236  bool d = delete_obj();
237  assert(d && "delete failed with SEH disabled: runtime bug?");
238 #endif
239  }
240  catch (const std::exception& ex)
241  {
242  if (permit_throw_in_dtor)
243  {
244  std::string msg = "destructor of test object raised"
245  " exception: ";
246  msg += ex.what();
247  throw warning(msg);
248  }
249  }
250  catch( ... )
251  {
252  if (permit_throw_in_dtor)
253  {
254  throw warning("destructor of test object raised an"
255  " exception");
256  }
257  }
258  }
259 
263  void reset()
264  {
265  release();
266  permit_throw_in_dtor = false;
267  p_ = new T();
268  }
269 
270  bool delete_obj()
271  {
272 #if defined(TUT_USE_SEH)
273  __try
274  {
275 #endif
276  T* p = p_;
277  p_ = 0;
278  delete p;
279 #if defined(TUT_USE_SEH)
280  }
281  __except(handle_seh_(::GetExceptionCode()))
282  {
283  if (permit_throw_in_dtor)
284  {
285  return false;
286  }
287  }
288 #endif
289  return true;
290  }
291  };
292 
293 public:
294 
295  typedef test_object<Data> object;
296 
300  test_group(const char* name)
301  : name_(name),
302  tests_(),
303  current_test_()
304  {
305  // register itself
306  runner.get().register_group(name_,this);
307 
308  // register all tests
310  }
311 
315  test_group(const char* name, test_runner& another_runner)
316  : name_(name),
317  tests_(),
318  current_test_()
319  {
320  // register itself
321  another_runner.register_group(name_, this);
322 
323  // register all tests
325  MaxTestsInGroup>::reg(*this);
326  };
327 
331  void reg(int n, testmethod tm)
332  {
333  tests_[n] = tm;
334  }
335 
339  void rewind()
340  {
341  current_test_ = tests_.begin();
342  }
343 
348  {
349  if (current_test_ == tests_.end())
350  {
351  return false;
352  }
353 
354  // find next user-specialized test
355  safe_holder<object> obj;
356  while (current_test_ != tests_.end())
357  {
358  tests_iterator current_test = current_test_++;
359 
360  if(run_test_(current_test, obj, tr) && tr.result != test_result::dummy)
361  {
362  return true;
363  }
364  }
365 
366  return false;
367  }
368 
372  bool run_test(int n, test_result &tr)
373  {
374  if (tests_.rbegin() == tests_.rend() ||
375  tests_.rbegin()->first < n)
376  {
377  return false;
378  }
379 
380  // withing scope; check if given test exists
381  tests_iterator ti = tests_.find(n);
382  if (ti == tests_.end())
383  {
384  return false;
385  }
386 
387  safe_holder<object> obj;
388  return run_test_(ti, obj, tr);
389  }
390 
395  bool run_test_(const tests_iterator& ti, safe_holder<object>& obj, test_result &tr)
396  {
397  std::string current_test_name;
398 
399  tr = test_result(name_, ti->first, current_test_name, test_result::ok);
400 
401  try
402  {
403  switch (run_test_seh_(ti->second, obj, current_test_name, ti->first))
404  {
405 #if defined(TUT_USE_SEH)
406  case SEH_CTOR:
407  throw bad_ctor("seh");
408  break;
409 
410  case SEH_TEST:
411  throw seh("seh");
412  break;
413 #endif
414  case SEH_DUMMY:
415  tr.result = test_result::dummy;
416  break;
417 
418  case SEH_OK:
419  // ok
420  break;
421  }
422  }
423  catch (const rethrown& ex)
424  {
425  tr = ex.tr;
426  tr.result = test_result::rethrown;
427  }
428  catch (const tut_error& ex)
429  {
430  tr.result = ex.result();
431  tr.exception_typeid = ex.type();
432  tr.message = ex.what();
433  }
434  catch (const std::exception& ex)
435  {
436  tr.result = test_result::ex;
437  tr.exception_typeid = type_name(ex);
438  tr.message = ex.what();
439  }
440  catch (...)
441  {
442  // test failed with unknown exception
443  tr.result = test_result::ex;
444  }
445 
446  if (obj.get())
447  {
448  tr.name = obj->get_test_name();
449 
450  // try to report to parent, if exists
451  send_result_(obj.get(), tr);
452  }
453  else
454  {
455  tr.name = current_test_name;
456  }
457 
458  return true;
459  }
460 
464  seh_result run_test_seh_(testmethod tm, safe_holder<object>& obj,
465  std::string& current_test_name, int current_test_id)
466  {
467 #if defined(TUT_USE_SEH)
468  __try
469  {
470 #endif
471  if (obj.get() == 0)
472  {
473  reset_holder_(obj);
474  }
475 
476  obj->called_method_was_a_dummy_test_ = false;
477 
478 #if defined(TUT_USE_SEH)
479 
480  __try
481  {
482 #endif
483  obj.get()->set_test_id(current_test_id);
484  obj.get()->set_test_group(name_);
485  (obj.get()->*tm)();
486 #if defined(TUT_USE_SEH)
487  }
488  __except(handle_seh_(::GetExceptionCode()))
489  {
490  current_test_name = obj->get_test_name();
491  return SEH_TEST;
492  }
493 #endif
494 
495  if (obj->called_method_was_a_dummy_test_)
496  {
497  // do not call obj.release(); reuse object
498  return SEH_DUMMY;
499  }
500 
501  current_test_name = obj->get_test_name();
502  obj.permit_throw();
503  obj.release();
504 #if defined(TUT_USE_SEH)
505  }
506  __except(handle_seh_(::GetExceptionCode()))
507  {
508  return SEH_CTOR;
509  }
510 #endif
511  return SEH_OK;
512  }
513 
514  void reset_holder_(safe_holder<object>& obj)
515  {
516  try
517  {
518  obj.reset();
519  }
520  catch (const std::exception& ex)
521  {
522  throw bad_ctor(ex.what());
523  }
524  catch (...)
525  {
526  throw bad_ctor("test constructor has generated an exception;"
527  " group execution is terminated");
528  }
529  }
530 };
531 
532 #if defined(TUT_USE_SEH)
533 
536 inline int handle_seh_(DWORD excode)
537 {
538  switch(excode)
539  {
540  case EXCEPTION_ACCESS_VIOLATION:
541  case EXCEPTION_DATATYPE_MISALIGNMENT:
542  case EXCEPTION_BREAKPOINT:
543  case EXCEPTION_SINGLE_STEP:
544  case EXCEPTION_ARRAY_BOUNDS_EXCEEDED:
545  case EXCEPTION_FLT_DENORMAL_OPERAND:
546  case EXCEPTION_FLT_DIVIDE_BY_ZERO:
547  case EXCEPTION_FLT_INEXACT_RESULT:
548  case EXCEPTION_FLT_INVALID_OPERATION:
549  case EXCEPTION_FLT_OVERFLOW:
550  case EXCEPTION_FLT_STACK_CHECK:
551  case EXCEPTION_FLT_UNDERFLOW:
552  case EXCEPTION_INT_DIVIDE_BY_ZERO:
553  case EXCEPTION_INT_OVERFLOW:
554  case EXCEPTION_PRIV_INSTRUCTION:
555  case EXCEPTION_IN_PAGE_ERROR:
556  case EXCEPTION_ILLEGAL_INSTRUCTION:
557  case EXCEPTION_NONCONTINUABLE_EXCEPTION:
558  case EXCEPTION_STACK_OVERFLOW:
559  case EXCEPTION_INVALID_DISPOSITION:
560  case EXCEPTION_GUARD_PAGE:
561  case EXCEPTION_INVALID_HANDLE:
562  return EXCEPTION_EXECUTE_HANDLER;
563  };
564 
565  return EXCEPTION_CONTINUE_SEARCH;
566 }
567 #endif
568 }
569 
570 #endif // TUT_H_GUARD
571 
Definition: tut_exception.hpp:13
Definition: tut_posix.hpp:460
bool called_method_was_a_dummy_test_
Definition: tut.hpp:106
Definition: tut_runner.hpp:113
Definition: tut_posix.hpp:467
bool run_test(int n, test_result &tr)
Definition: tut.hpp:372
Definition: tut.hpp:35
Definition: tut.hpp:124
Definition: tut.hpp:43
test_group(const char *name)
Definition: tut.hpp:300
Definition: tut_exception.hpp:164
test finished successfully
Definition: tut_result.hpp:91
Definition: tut_exception.hpp:189
void reg(int n, testmethod tm)
Definition: tut.hpp:331
std::string name
Definition: tut_result.hpp:84
Definition: tut_exception.hpp:89
void register_group(const std::string &name, group_base *gr)
Definition: tut_runner.hpp:132
Definition: tut_runner.hpp:16
void test()
Definition: tut.hpp:95
void rewind()
Definition: tut.hpp:339
std::string message
Definition: tut_result.hpp:107
Definition: tut_result.hpp:69
test throwed an exceptions
Definition: tut_result.hpp:93
test_group(const char *name, test_runner &another_runner)
Definition: tut.hpp:315
seh_result run_test_seh_(testmethod tm, safe_holder< object > &obj, std::string &current_test_name, int current_test_id)
Definition: tut.hpp:464
bool run_next(test_result &tr)
Definition: tut.hpp:347
bool run_test_(const tests_iterator &ti, safe_holder< object > &obj, test_result &tr)
Definition: tut.hpp:395
test_object()
Definition: tut.hpp:63

All Rights Reserved. Generated on Wed Dec 18 2013 11:19:52 for TUT by doxygen 1.8.5