[ VIGRA Homepage | Function Index | Class Index | Namespaces | File List | Main Page ]

unittest.hxx VIGRA

1 /************************************************************************/
2 /* */
3 /* a simple unit test framework, similar to Kent Beck's JUnit */
4 /* */
5 /* Copyright 2002-2004 by Ullrich Koethe */
6 /* */
7 /* This file is part of the VIGRA computer vision library. */
8 /* The VIGRA Website is */
9 /* http://hci.iwr.uni-heidelberg.de/vigra/ */
10 /* Please direct questions, bug reports, and contributions to */
11 /* ullrich.koethe@iwr.uni-heidelberg.de or */
12 /* vigra@informatik.uni-hamburg.de */
13 /* */
14 /* Permission is hereby granted, free of charge, to any person */
15 /* obtaining a copy of this software and associated documentation */
16 /* files (the "Software"), to deal in the Software without */
17 /* restriction, including without limitation the rights to use, */
18 /* copy, modify, merge, publish, distribute, sublicense, and/or */
19 /* sell copies of the Software, and to permit persons to whom the */
20 /* Software is furnished to do so, subject to the following */
21 /* conditions: */
22 /* */
23 /* The above copyright notice and this permission notice shall be */
24 /* included in all copies or substantial portions of the */
25 /* Software. */
26 /* */
27 /* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND */
28 /* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES */
29 /* OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND */
30 /* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT */
31 /* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, */
32 /* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING */
33 /* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR */
34 /* OTHER DEALINGS IN THE SOFTWARE. */
35 /* */
36 /************************************************************************/
37 
38 #ifndef VIGRA_UNIT_TEST_HPP
39 #define VIGRA_UNIT_TEST_HPP
40 
41 #include <vector>
42 #include <string>
43 #include <new> // for bad_alloc
44 #include <typeinfo> // for bad_cast, bad_typeid
45 #include <exception> // for exception, bad_exception
46 #include <stdexcept>
47 #include <iostream>
48 #include <limits>
49 #include <cfloat>
50 #include <cmath>
51 #include "vigra/config.hxx"
52 #include "vigra/error.hxx"
53 
54 #ifdef VIGRA_NO_WORKING_STRINGSTREAM
55 #include <strstream>
56 #define VIGRA_SSTREAM std::strstream
57 #define VIGRA_SSTREAM_STR(s) ((s << char()), std::string(s.str()))
58 #else
59 #include <sstream>
60 #define VIGRA_SSTREAM std::basic_stringstream<char>
61 #define VIGRA_SSTREAM_STR(s) s.str()
62 #endif
63 
64 
65 #ifdef _MSC_VER
66 
67 #include <wtypes.h>
68 #include <winbase.h>
69 #include <excpt.h>
70 
71 #ifdef min
72 #undef min
73 #endif
74 #ifdef max
75 #undef max
76 #endif
77 #ifdef DIFFERENCE
78 #undef DIFFERENCE
79 #endif
80 #ifdef RGB
81 #undef RGB
82 #endif
83 
84 #elif defined(__CYGWIN__)
85 
86 #define VIGRA_CANT_CATCH_SIGNALS
87 
88 #elif defined(__unix) || defined(unix)
89 
90 #include <unistd.h>
91 #include <signal.h>
92 #include <sys/signal.h>
93 #include <setjmp.h>
94 
95 #else
96 
97 #define VIGRA_CANT_CATCH_SIGNALS
98 
99 #endif
100 
101 #define VIGRA_TEST_CASE(function) vigra::create_test_case(function, #function "()")
102 
103 #define testCase VIGRA_TEST_CASE
104 
105 #define VIGRA_TEST_SUITE(testsuite) ( new testsuite )
106 
107 #define VIGRA_CHECKPOINT(message) \
108  vigra::detail::checkpoint_impl(message, __FILE__, __LINE__)
109 
110 #define VIGRA_ASSERT(predicate) \
111  vigra::detail::should_impl((predicate), #predicate, __FILE__, __LINE__)
112 
113 #define should VIGRA_ASSERT
114 
115 #define VIGRA_ASSERT_MESSAGE(predicate, message) \
116  vigra::detail::should_impl((predicate), message, __FILE__, __LINE__)
117 
118 #define shouldMsg VIGRA_ASSERT_MESSAGE
119 
120 #define shouldEqual(left, right) \
121  vigra::detail::equal_impl(left, right, #left " == " #right, __FILE__, __LINE__)
122 
123 #define shouldEqualMessage(left, right, message) \
124  vigra::detail::equal_impl(left, right, message "\n" #left " == " #right, __FILE__, __LINE__)
125 
126 #define shouldEqualTolerance(left, right, eps) \
127  vigra::detail::tolerance_equal_impl(left, right, eps, #left " == " #right, __FILE__, __LINE__)
128 
129 #define shouldEqualToleranceMessage(left, right, eps, message) \
130  vigra::detail::tolerance_equal_impl(left, right, eps, message "\n" #left " == " #right, __FILE__, __LINE__)
131 
132 #define shouldEqualSequence(begin1, end1, begin2) \
133  vigra::detail::sequence_equal_impl(begin1, end1, begin2, __FILE__, __LINE__)
134 
135 #define shouldEqualSequenceTolerance(begin1, end1, begin2, eps) \
136  vigra::detail::sequence_equal_tolerance_impl(begin1, end1, begin2, eps, __FILE__, __LINE__)
137 
138 #define VIGRA_ERROR(message) \
139  vigra::detail::should_impl(false, message, __FILE__, __LINE__)
140 
141 #define failTest VIGRA_ERROR
142 
143 namespace vigra {
144 
145 class test_suite;
146 
147 namespace detail {
148 
149 struct errstream
150 {
151  VIGRA_SSTREAM buf;
152  std::string str() { return VIGRA_SSTREAM_STR(buf); }
153  template <class T>
154  errstream & operator<<(T t) { buf << t; return *this; }
155 };
156 
157 inline std::string & exception_checkpoint()
158 {
159  static std::string test_checkpoint_;
160  return test_checkpoint_;
161 }
162 
163 // A separate reporting function was requested during formal review.
164 inline void report_exception( detail::errstream & os,
165  const char * name, const char * info )
166 {
167  os << "Unexpected " << name << " " << info << "\n";
168  if(exception_checkpoint().size() > 0)
169  {
170  os << "Last checkpoint: " << exception_checkpoint() << "\n";
171  }
172 }
173 
174 enum {
175  unexpected_exception = -1,
176  os_exception = -2,
177  memory_access_violation = -3,
178  destructor_failure = -4
179 };
180 
181 inline bool critical_error(int i)
182 { return i <= memory_access_violation; }
183 
184 inline bool unexpected_error(int i)
185 { return i < 0; }
186 
187 #ifndef VIGRA_CANT_CATCH_SIGNALS
188 
189 #ifdef _MSC_VER
190 
191 inline long handle_signal_here(long code)
192 {
193  switch (code)
194  {
195  case EXCEPTION_ACCESS_VIOLATION:
196  case EXCEPTION_INT_DIVIDE_BY_ZERO:
197  return EXCEPTION_EXECUTE_HANDLER;
198  default:
199  return EXCEPTION_CONTINUE_SEARCH;
200  }
201 }
202 
203 template< class Generator > // Generator is function object returning int
204 int catch_signals( Generator function_object, detail::errstream & err, int timeout )
205 {
206  int result = 0;
207  int code;
208  __try
209  {
210  result = function_object();
211  }
212  __except (handle_signal_here(code = GetExceptionCode()))
213  {
214  switch (code)
215  {
216  case EXCEPTION_ACCESS_VIOLATION:
217  report_exception(err, "operating system exception:", "memory access violation");
218  result = memory_access_violation;
219  break;
220  case EXCEPTION_INT_DIVIDE_BY_ZERO:
221  report_exception(err, "operating system exception:", "integer divide by zero");
222  result = os_exception;
223  break;
224  default:
225  report_exception(err, "operating system exception:", "unrecognized exception or signal");
226  result = os_exception;
227  }
228  }
229  return result;
230 
231 }
232 
233 
234 #elif defined(__unix)
235 
236 extern "C" {
237 
238 inline jmp_buf & unit_test_jump_buffer()
239 {
240  static jmp_buf unit_test_jump_buffer_;
241  return unit_test_jump_buffer_;
242 }
243 
244 static void unit_test_signal_handler(int sig)
245 {
246  longjmp(unit_test_jump_buffer(), sig);
247 }
248 
249 } // extern "C"
250 
251 template< class Generator > // Generator is function object returning int
252 int catch_signals( Generator function_object, detail::errstream & err, int timeout)
253 {
254  volatile int sigtype;
255  int result;
256 
257 #if defined(linux) || defined(__linux)
258  signal(SIGFPE, &unit_test_signal_handler);
259  signal(SIGTRAP, &unit_test_signal_handler);
260  signal(SIGSEGV, &unit_test_signal_handler);
261  signal(SIGBUS, &unit_test_signal_handler);
262 #else
263  sigset(SIGFPE, &unit_test_signal_handler);
264  sigset(SIGTRAP, &unit_test_signal_handler);
265  sigset(SIGSEGV, &unit_test_signal_handler);
266  sigset(SIGBUS, &unit_test_signal_handler);
267 #endif
268 
269  if(timeout)
270  {
271 #if defined(linux) || defined(__linux)
272  signal(SIGALRM, &unit_test_signal_handler);
273 #else
274  sigset(SIGALRM, &unit_test_signal_handler);
275 #endif
276  alarm(timeout);
277  }
278 
279  sigtype = setjmp(unit_test_jump_buffer());
280  if(sigtype == 0)
281  {
282  result = function_object();
283  }
284  else
285  {
286  switch(sigtype)
287  {
288  case SIGALRM:
289  report_exception(err, "signal:", "SIGALRM (timeout while executing function)");
290  result = os_exception;
291  break;
292  case SIGTRAP:
293  report_exception(err, "signal:", "SIGTRAP (perhaps integer divide by zero)");
294  result = os_exception;
295  break;
296  case SIGFPE:
297  report_exception(err, "signal:", "SIGFPE (arithmetic exception)");
298  result = os_exception;
299  break;
300  case SIGSEGV:
301  case SIGBUS:
302  report_exception(err, "signal:", "memory access violation");
303  result = memory_access_violation;
304  break;
305  default:
306  report_exception(err, "signal:", "unrecognized signal");
307  result = os_exception;
308  }
309  }
310 
311  if(timeout)
312  {
313  alarm(0);
314 #if defined(linux) || defined(__linux)
315 #else
316  sigrelse(SIGALRM);
317 #endif
318  }
319 
320 #if defined(linux) || defined(__linux)
321 #else
322  sigrelse(SIGFPE);
323  sigrelse(SIGTRAP);
324  sigrelse(SIGSEGV);
325  sigrelse(SIGBUS);
326 #endif
327 
328  return result;
329 }
330 
331 #endif /* _MSC_VER || __unix */
332 
333 #else /* VIGRA_CANT_CATCH_SIGNALS */
334 
335 template< class Generator > // Generator is function object returning int
336 int catch_signals( Generator function_object, detail::errstream & err , int)
337 {
338  return function_object();
339 }
340 
341 #endif /* VIGRA_CANT_CATCH_SIGNALS */
342 
343 } // namespace detail
344 
345 template< class Generator > // Generator is function object returning int
346 int catch_exceptions( Generator function_object, detail::errstream & err, int timeout )
347 {
348  int result = detail::unexpected_exception;
349 
350  try
351  {
352  result = detail::catch_signals(function_object, err, timeout);
353  }
354 
355  // As a result of hard experience with strangely interleaved output
356  // under some compilers, there is a lot of use of endl in the code below
357  // where a simple '\n' might appear to do.
358 
359  // The rules for catch & arguments are a bit different from function
360  // arguments (ISO 15.3 paragraphs 18 & 19). Apparently const isn't
361  // required, but it doesn't hurt and some programmers ask for it.
362 
363  catch ( vigra::ContractViolation & ex )
364  { detail::report_exception( err, "Contract exception: ", ex.what() ); }
365  catch ( const char * ex )
366  { detail::report_exception( err, "string exception: ", ex ); }
367  catch ( const std::string & ex )
368  { detail::report_exception( err, "string exception: ", ex.c_str() ); }
369 
370  // std:: exceptions
371  catch ( const std::bad_alloc & ex )
372  { detail::report_exception( err, "exception: std::bad_alloc:", ex.what() ); }
373 
374 # if !defined(__BORLANDC__) || __BORLANDC__ > 0x0551
375  catch ( const std::bad_cast & ex )
376  { detail::report_exception( err, "exception: std::bad_cast:", ex.what() ); }
377  catch ( const std::bad_typeid & ex )
378  { detail::report_exception( err, "exception: std::bad_typeid:", ex.what() ); }
379 # else
380  catch ( const std::bad_cast & ex )
381  { detail::report_exception( err, "exception: std::bad_cast", "" ); }
382  catch ( const std::bad_typeid & ex )
383  { detail::report_exception( err, "exception: std::bad_typeid", "" ); }
384 # endif
385 
386  catch ( const std::bad_exception & ex )
387  { detail::report_exception( err, "exception: std::bad_exception:", ex.what() ); }
388  catch ( const std::domain_error & ex )
389  { detail::report_exception( err, "exception: std::domain_error:", ex.what() ); }
390  catch ( const std::invalid_argument & ex )
391  { detail::report_exception( err, "exception: std::invalid_argument:", ex.what() ); }
392  catch ( const std::length_error & ex )
393  { detail::report_exception( err, "exception: std::length_error:", ex.what() ); }
394  catch ( const std::out_of_range & ex )
395  { detail::report_exception( err, "exception: std::out_of_range:", ex.what() ); }
396  catch ( const std::range_error & ex )
397  { detail::report_exception( err, "exception: std::range_error:", ex.what() ); }
398  catch ( const std::overflow_error & ex )
399  { detail::report_exception( err, "exception: std::overflow_error:", ex.what() ); }
400  catch ( const std::underflow_error & ex )
401  { detail::report_exception( err, "exception: std::underflow_error:", ex.what() ); }
402  catch ( const std::logic_error & ex )
403  { detail::report_exception( err, "exception: std::logic_error:", ex.what() ); }
404  catch ( const std::runtime_error & ex )
405  { detail::report_exception( err, "exception: std::runtime_error:", ex.what() ); }
406  catch ( const std::exception & ex )
407  { detail::report_exception( err, "exception: std::exception:", ex.what() ); }
408 
409  catch ( ... )
410  {
411  detail::report_exception( err, "unknown exception", "" );
412  throw;
413  }
414 
415  return result;
416 } // catch_exceptions
417 
418 template< class Generator > // Generator is function object returning int
419 inline
420 int catch_exceptions( Generator function_object, detail::errstream & err)
421 {
422  return catch_exceptions(function_object, err, 0);
423 }
424 
425 namespace detail {
426 
427 struct unit_test_failed
428 : public std::exception
429 {
430  unit_test_failed(std::string const & message)
431  : what_(message)
432  {}
433 
434  virtual ~unit_test_failed() throw()
435  {
436  }
437 
438  virtual const char * what() const throw()
439  {
440  return what_.c_str();
441  }
442 
443  std::string what_;
444 };
445 
446 inline void
447 checkpoint_impl(const char * message, const char * file, int line)
448 {
449  detail::errstream buf;
450  buf << message << " (" << file <<":" << line << ")";
451  exception_checkpoint() = buf.str();
452 }
453 
454 inline void
455 should_impl(bool predicate, const char * message, const char * file, int line)
456 {
457  checkpoint_impl(message, file, line);
458  if(!predicate)
459  {
460  detail::errstream buf;
461  buf << message << " (" << file <<":" << line << ")";
462  throw unit_test_failed(buf.str());
463  }
464 }
465 
466 template <class Iter1, class Iter2>
467 void
468 sequence_equal_impl(Iter1 i1, Iter1 end1, Iter2 i2, const char * file, int line)
469 {
470  for(int counter = 0; i1 != end1; ++i1, ++i2, ++counter)
471  {
472  if(*i1 != *i2)
473  {
474  detail::errstream buf;
475  buf << "Sequence items differ at index " << counter <<
476  " ["<< *i1 << " != " << *i2 << "]";
477  should_impl(false, buf.str().c_str(), file, line);
478  }
479  }
480 }
481 
482 /******************Floating point comparison********************************/
483 /**
484 * See Knuth "The art of computer programming" (Vol II, Ch.4.2)
485 */
486 struct ScalarType {};
487 struct VectorType {};
488 
489 template<class T>
490 struct FloatTraits
491 {
492  typedef VectorType ScalarOrVector;
493 };
494 
495 template<>
496 struct FloatTraits<float>
497 {
498  typedef ScalarType ScalarOrVector;
499  static float epsilon() { return FLT_EPSILON; }
500  static float smallestPositive() { return FLT_MIN; }
501  static float min() { return -FLT_MAX; }
502  static float max() { return FLT_MAX; }
503 };
504 
505 template<>
506 struct FloatTraits<double>
507 {
508  typedef ScalarType ScalarOrVector;
509  static double epsilon() { return DBL_EPSILON; }
510  static double smallestPositive() { return DBL_MIN; }
511  static double min() { return -DBL_MAX; }
512  static double max() { return DBL_MAX; }
513 };
514 
515 template<>
516 struct FloatTraits<long double>
517 {
518  typedef ScalarType ScalarOrVector;
519  static long double epsilon() { return LDBL_EPSILON; }
520  static long double smallestPositive() { return LDBL_MIN; }
521  static long double min() { return -LDBL_MAX; }
522  static long double max() { return LDBL_MAX; }
523 };
524 
525 template<class FPT>
526 inline
527 FPT fpt_abs( FPT arg )
528 {
529  return arg < 0 ? -arg : arg;
530 }
531 
532 
533 /***********************************************************************/
534 
535 // both f1 and f2 are unsigned here
536 template<class FPT>
537 inline
538 FPT safe_fpt_division( FPT f1, FPT f2 )
539 {
540  /* ist f1 das absolute minimum (in diesem Fall einfach nur sehr kleine Zahl)
541  * aber nicht null (1.65242e-28) und f2 = 0,
542  * dann tritt die erste Bedingung in Kraft 0<1 && 1.65242e-28 > 0*1.79769e+308 (max)
543  * deshalb schlaegt es fehl sogar wenn min closed at tolarance zu 0 ist ???
544  * Der Vergleich aller Zahlen closed at tolarance zu 0 wuerden fehlschlagen;
545  * Sie umzudrehen bringt nichts, denn diese Funktion wird symetrisch fuer beide
546  * angewendet wird.
547  * 0 mit 0 zu Vergleichen bereitet keine Probleme.
548  * Ausweg: evl. eine extra Behandlung der F = 0 ???
549  */
550  return ((f2 < 1) && (f1 > (f2 * FloatTraits<FPT>::max()))) ?
551  FloatTraits<FPT>::max() :
552  ((((f2 > 1) && (f1 < (f2 * FloatTraits<FPT>::smallestPositive())))
553  || (f1 == 0)) ? 0 : f1/f2 );
554  /* Die Multiplikation mit max in 1.ten Bedingung und mit min in der 2.ten ist eine Absicherung gegen
555  * die Owerflow bzw Underflow ???
556  */
557 }
558 
559 /***********************************************************************/
560 
561 template<class FPT>
562 class close_at_tolerance {
563 public:
564  explicit close_at_tolerance( FPT tolerance, bool strong_test = true )
565  : m_strong_test( strong_test ),
566  m_tolerance( tolerance ) {}
567 
568  explicit close_at_tolerance( int number_of_rounding_errors, bool strong_test = true )
569  : m_strong_test( strong_test ),
570  m_tolerance( FloatTraits<FPT>::epsilon() * number_of_rounding_errors / 2.0 ) {}
571 
572  bool operator()( FPT left, FPT right ) const
573  {
574  if (left == 0 && right != 0)
575  {
576  return (fpt_abs(right) <= m_tolerance);
577  }
578  if (right == 0 && left != 0)
579  {
580  return (fpt_abs(left) <= m_tolerance);
581  }
582  FPT diff = fpt_abs( left - right );
583  FPT d1 = safe_fpt_division( diff, fpt_abs( right ) );
584  FPT d2 = safe_fpt_division( diff, fpt_abs( left ) );
585 
586  return m_strong_test ? (d1 <= m_tolerance && d2 <= m_tolerance)
587  : (d1 <= m_tolerance || d2 <= m_tolerance);
588  }
589 
590 private:
591  bool m_strong_test;
592  FPT m_tolerance;
593 };
594 
595 /*****************end of float comparison***********************************/
596 
597 template <class T1, class T2, class T3>
598 void
599 tolerance_equal_impl(T1 left, T2 right, T3 epsilon,
600  const char * message, const char * file, int line, ScalarType)
601 {
602  detail::errstream buf;
603  buf << message << " [" << left << " != " << right << "]";
604 
605  close_at_tolerance<T3> fcomparator( epsilon );
606  bool compare = fcomparator ( (T3)left , (T3)right );
607  should_impl(compare, buf.str().c_str(), file, line);
608 
609 }
610 
611 template <class T1, class T2, class T3>
612 void
613 tolerance_equal_impl(T1 left, T2 right, T3 epsilon,
614  const char * message, const char * file, int line, VectorType)
615 {
616  detail::errstream buf;
617  buf << message << " [" << left << " != " << right << "]";
618 
619  bool compare = true;
620  for(unsigned int i=0; i<epsilon.size(); ++i)
621  {
622  close_at_tolerance<typename T3::value_type> fcomparator( epsilon[i] );
623  compare = compare && fcomparator ( left[i] , right[i] );
624  }
625  should_impl(compare, buf.str().c_str(), file, line);
626 }
627 
628 template <class T1, class T2, class T3>
629 void
630 tolerance_equal_impl(T1 left, T2 right, T3 epsilon, const char * message, const char * file, int line)
631 {
632  tolerance_equal_impl(left, right, epsilon,
633  message, file, line, typename FloatTraits<T3>::ScalarOrVector());
634 }
635 
636 template <class Iter1, class Iter2, class T>
637 void
638 sequence_equal_tolerance_impl(Iter1 i1, Iter1 end1, Iter2 i2, T epsilon, const char * file, int line)
639 {
640  for(int counter = 0; i1 != end1; ++i1, ++i2, ++counter)
641  {
642  detail::errstream buf;
643  buf << "Sequence items differ at index " << counter;
644  tolerance_equal_impl(*i1, *i2, epsilon, buf.str().c_str(), file, line, typename FloatTraits<T>::ScalarOrVector());
645  }
646 }
647 
648 template <class Left, class Right>
649 void
650 equal_impl(Left left, Right right, const char * message, const char * file, int line)
651 {
652  detail::errstream buf;
653  buf << message << " [" << left << " != " << right << "]";
654  should_impl(left == right, buf.str().c_str(), file, line);
655 }
656 
657 template <class Left, class Right>
658 void
659 equal_impl(Left * left, Right * right, const char * message, const char * file, int line)
660 {
661  detail::errstream buf;
662  buf << message << " [" << (void*)left << " != " << (void*)right << "]";
663  should_impl(left == right, buf.str().c_str(), file, line);
664 }
665 
666 inline void
667 equal_impl(double left, double right, const char * message, const char * file, int line)
668 {
669  tolerance_equal_impl(left, right, 1.0e-16, message, file, line);
670 }
671 
672 inline void
673 equal_impl(float left, float right, const char * message, const char * file, int line)
674 {
675  tolerance_equal_impl(left, right, 1.0e-6f, message, file, line);
676 }
677 
678 inline void
679 equal_impl(float left, double right, const char * message, const char * file, int line)
680 {
681  tolerance_equal_impl(left, right, 1.0e-6f, message, file, line);
682 }
683 
684 inline void
685 equal_impl(double left, float right, const char * message, const char * file, int line)
686 {
687  tolerance_equal_impl(left, right, 1.0e-6f, message, file, line);
688 }
689 
690 class test_case
691 {
692  public:
693 
694  test_case(char const * name = "Unnamed")
695  : name_(name), timeout(0)
696  {}
697 
698  virtual ~test_case() {}
699 
700  virtual int run() { return run(std::vector<std::string>()); }
701  virtual int run(std::vector<std::string> const & testsToBeRun) = 0;
702  virtual void do_init() {}
703  virtual void do_run() {}
704  virtual void do_destroy() {}
705 
706  virtual char const * name() { return name_.c_str(); }
707  virtual int size() const { return 1; }
708 
709  virtual int numberOfTestsToRun(std::vector<std::string> const & testsToBeRun) const
710  {
711  if(testsToBeRun.empty()) // empty list => run all tests
712  return 1;
713  for(unsigned int k=0; k<testsToBeRun.size(); ++k)
714  if(this->name_.find(testsToBeRun[k]) != std::string::npos)
715  return 1;
716  return 0;
717  }
718 
719  std::string name_;
720  std::string report_;
721  int timeout;
722 };
723 
724 
725 } // namespace detail
726 
727 std::vector<std::string> testsToBeExecuted(int argc, char ** argv)
728 {
729  std::vector<std::string> res;
730  for(int i=1; i < argc; ++i)
731  res.push_back(std::string(argv[i]));
732  return res;
733 }
734 
735 class test_suite
736 : public detail::test_case
737 {
738  public:
739  using detail::test_case::run;
740 
741  test_suite(char const * name = "TopLevel")
742  : detail::test_case(name),
743  size_(0)
744  {}
745 
746  virtual ~test_suite()
747  {
748  for(unsigned int i=0; i != testcases_.size(); ++i)
749  delete testcases_[i];
750  }
751 
752  virtual void add(detail::test_case * t, int timeout = 0)
753  {
754  t->timeout = timeout;
755  testcases_.push_back(t);
756  size_ += t->size();
757  }
758 
759  virtual int run(std::vector<std::string> const & testsToBeRun)
760  {
761  int size = numberOfTestsToRun(testsToBeRun);
762 
763  std::vector<std::string> testsToBeRunRecursive =
764  size < this->size()
765  ? testsToBeRun // run selectively
766  : std::vector<std::string>(); // run all
767 
768  int failed = 0;
769  report_ = std::string("Entering test suite ") + name() + "\n";
770 
771  for(unsigned int i=0; i != testcases_.size(); ++i)
772  {
773  int result = testcases_[i]->run(testsToBeRunRecursive);
774  report_ += testcases_[i]->report_;
775 
776  if(detail::critical_error(result))
777  {
778  report_ += std::string("\nFatal error - aborting test suite ") + name() + ".\n";
779  return result;
780  }
781  else if(detail::unexpected_error(result))
782  failed++;
783  else
784  failed += result;
785  }
786 
787  if(failed)
788  {
789  detail::errstream buf;
790  buf << "\n" << failed << " of " << size <<
791  " tests failed in test suite " << name() << "\n";
792  report_ += buf.str();
793  }
794  else
795  {
796  detail::errstream buf;
797  buf << "All (" << size <<
798  ") tests passed in test suite " << name() << "\n";
799  report_ += buf.str();
800  }
801 
802  report_ += std::string("Leaving test suite ") + name() + "\n";
803 
804  return failed;
805  }
806 
807  virtual int numberOfTestsToRun(std::vector<std::string> const & testsToBeRun) const
808  {
809  if(detail::test_case::numberOfTestsToRun(testsToBeRun) > 0)
810  return this->size();
811  int size = 0;
812  for(unsigned int i=0; i != testcases_.size(); ++i)
813  size += testcases_[i]->numberOfTestsToRun(testsToBeRun);
814  return size;
815  }
816 
817  virtual int size() const { return size_; }
818  virtual std::string report() { return report_; }
819 
820  std::vector<detail::test_case *> testcases_;
821  int size_;
822 };
823 
824 namespace detail {
825 
826 struct test_case_init_functor
827 {
828  detail::errstream & buf_;
829  test_case * test_case_;
830 
831  test_case_init_functor(detail::errstream & b, test_case * tc)
832  : buf_(b), test_case_(tc)
833  {}
834 
835  int operator()()
836  {
837  try
838  {
839  test_case_->do_init();
840  return 0;
841  }
842  catch(unit_test_failed & e)
843  {
844  buf_ << "Assertion failed: " << e.what() << "\n";
845  return 1;
846  }
847  }
848 };
849 
850 struct test_case_run_functor
851 {
852  detail::errstream & buf_;
853  test_case * test_case_;
854 
855  test_case_run_functor(detail::errstream & b, test_case * tc)
856  : buf_(b), test_case_(tc)
857  {}
858 
859  int operator()()
860  {
861  try
862  {
863  test_case_->do_run();
864  return 0;
865  }
866  catch(unit_test_failed & e)
867  {
868  buf_ << "Assertion failed: " << e.what() << "\n";
869  return 1;
870  }
871  }
872 };
873 
874 struct test_case_destroy_functor
875 {
876  detail::errstream & buf_;
877  test_case * test_case_;
878 
879  test_case_destroy_functor(detail::errstream & b, test_case * tc)
880  : buf_(b), test_case_(tc)
881  {}
882 
883  int operator()()
884  {
885  try
886  {
887  test_case_->do_destroy();
888  return 0;
889  }
890  catch(unit_test_failed & e)
891  {
892  buf_ << "Assertion failed: " << e.what() << "\n";
893  return 1;
894  }
895  }
896 };
897 
898 template <class TESTCASE>
899 class class_test_case
900 : public test_case
901 {
902  public:
903  using test_case::run;
904 
905  class_test_case(void (TESTCASE::*fct)(), char const * name)
906  : test_case(name),
907  fct_(fct),
908  testcase_(0)
909  {}
910 
911  virtual ~class_test_case()
912  {
913  delete testcase_;
914  }
915 
916  virtual void do_init()
917  {
918  testcase_ = new TESTCASE;
919  }
920 
921  int init()
922  {
923  exception_checkpoint() = "";
924  report_ = "";
925  int failed = 0;
926 
927  detail::errstream buf;
928  buf << "\nFailure in initialization of " << name() << "\n";
929  if(testcase_ != 0)
930  {
931  buf << "Test case failed to clean up after previous run.\n";
932  failed = 1;
933  }
934  else
935  {
936  failed = catch_exceptions(
937  detail::test_case_init_functor(buf, this), buf, timeout);
938  }
939 
940  if(failed)
941  {
942  report_ += buf.str();
943  }
944 
945  return failed;
946  }
947 
948  virtual void do_run()
949  {
950  if(testcase_ != 0)
951  (testcase_->*fct_)();
952  }
953 
954  virtual int run(std::vector<std::string> const & testsToBeRun)
955  {
956  if(numberOfTestsToRun(testsToBeRun) == 0)
957  return 0;
958 
959  int failed = init();
960 
961  if(failed)
962  return failed;
963 
964  detail::errstream buf;
965  buf << "\nFailure in " << name() << "\n";
966 
967  failed = catch_exceptions(
968  detail::test_case_run_functor(buf, this), buf, timeout);
969  if(failed)
970  report_ += buf.str();
971 
972  if(critical_error(failed))
973  return failed;
974 
975  int destruction_failed = destroy();
976 
977  return destruction_failed ?
978  destruction_failed :
979  failed;
980  }
981 
982  virtual void do_destroy()
983  {
984  delete testcase_;
985  testcase_ = 0;
986  }
987 
988  int destroy()
989  {
990  detail::errstream buf;
991  buf << "\nFailure in destruction of " << "\n";
992 
993  int failed = catch_exceptions(
994  detail::test_case_destroy_functor(buf, this), buf, timeout);
995  if(failed)
996  {
997  report_ += buf.str();
998  return destructor_failure;
999  }
1000  else
1001  {
1002  return 0;
1003  }
1004  }
1005 
1006  void (TESTCASE::*fct_)();
1007  TESTCASE * testcase_;
1008 };
1009 
1010 class function_test_case
1011 : public test_case
1012 {
1013  public:
1014  using test_case::run;
1015 
1016  function_test_case(void (*fct)(), char const * name)
1017  : test_case(name),
1018  fct_(fct)
1019  {}
1020 
1021  virtual void do_run()
1022  {
1023  (*fct_)();
1024  }
1025 
1026  virtual int run(std::vector<std::string> const & testsToBeRun)
1027  {
1028  if(numberOfTestsToRun(testsToBeRun) == 0)
1029  return 0;
1030 
1031  report_ = "";
1032  exception_checkpoint() = "";
1033 
1034  detail::errstream buf;
1035  buf << "\nFailure in " << name() << "\n";
1036 
1037  int failed = catch_exceptions(
1038  detail::test_case_run_functor(buf, this), buf, timeout);
1039  if(failed)
1040  {
1041  report_ += buf.str();
1042  }
1043 
1044  return failed;
1045  }
1046 
1047  void (*fct_)();
1048 };
1049 
1050 template <class FCT>
1051 struct test_functor
1052 {
1053  virtual ~test_functor() {}
1054  virtual void operator()() = 0;
1055 
1056  FCT clone() const
1057  { return FCT(static_cast<FCT const &>(*this)); }
1058 };
1059 
1060 template <class FCT>
1061 class functor_test_case
1062 : public test_case
1063 {
1064  public:
1065  using test_case::run;
1066 
1067  functor_test_case(FCT const & fct, char const * name)
1068  : test_case(name),
1069  fct_(fct)
1070  {}
1071 
1072  virtual void do_run()
1073  {
1074  fct_();
1075  }
1076 
1077  virtual int run(std::vector<std::string> const & testsToBeRun)
1078  {
1079  if(numberOfTestsToRun(testsToBeRun) == 0)
1080  return 0;
1081 
1082  report_ = "";
1083  exception_checkpoint() = "";
1084 
1085  detail::errstream buf;
1086  buf << "\nFailure in " << name() << "\n";
1087 
1088  int failed = catch_exceptions(
1089  detail::test_case_run_functor(buf, this), buf, timeout);
1090  if(failed)
1091  {
1092  report_ += buf.str();
1093  }
1094 
1095  return failed;
1096  }
1097 
1098  FCT fct_;
1099 };
1100 
1101 } // namespace detail
1102 
1103 template <class TESTCASE>
1104 inline
1105 detail::test_case *
1106 create_test_case(void (TESTCASE::*fct)(), char const * name)
1107 {
1108  if(*name == '&') ++name;
1109  return new detail::class_test_case<TESTCASE>(fct, name);
1110 }
1111 
1112 inline
1113 detail::test_case *
1114 create_test_case(void (*fct)(), char const * name)
1115 {
1116  if(*name == '&') ++name;
1117  return new detail::function_test_case(fct, name);
1118 }
1119 
1120 template <class FCT>
1121 inline
1122 detail::test_case *
1123 create_test_case(detail::test_functor<FCT> const & fct, char const * name)
1124 {
1125  if(*name == '&') ++name;
1126  return new detail::functor_test_case<FCT>(fct.clone(), name);
1127 }
1128 
1129 } // namespace vigra
1130 
1131 
1132 #if !defined(__GNUC__) || __GNUC__ >= 3
1133 
1134 // provide more convenient output functions, used like:
1135 // std::cerr << 1, 2, 3, 4, "\n";
1136 template <class E, class T, class V>
1137 inline
1138 std::basic_ostream<E,T> & operator,(std::basic_ostream<E,T> & o, V const & t)
1139 {
1140  return (o << ' ' << t);
1141 }
1142 
1143 template <class E, class T>
1144 inline
1145 std::basic_ostream<E,T> & operator,(std::basic_ostream<E,T> & o,
1146  std::basic_ostream<E,T> & (*t)(std::basic_ostream<E,T> &))
1147 {
1148  return (o << t);
1149 }
1150 
1151 #else
1152 
1153 template <class V>
1154 inline
1155 std::ostream & operator,(std::ostream & o, V const & t)
1156 {
1157  return (o << ' ' << t);
1158 }
1159 
1160 inline
1161 std::ostream & operator,(std::ostream & o,
1162  std::ostream & (*t)(std::ostream &))
1163 {
1164  return (o << t);
1165 }
1166 
1167 #endif
1168 
1169 
1170 #endif /* VIGRA_UNIT_TEST_HPP */
R arg(const FFTWComplex< R > &a)
pahse
Definition: fftw3.hxx:1009
void add(FixedPoint< IntBits1, FracBits1 > l, FixedPoint< IntBits2, FracBits2 > r, FixedPoint< IntBits3, FracBits3 > &result)
addition with enforced result type.
Definition: fixedpoint.hxx:561

© Ullrich Köthe (ullrich.koethe@iwr.uni-heidelberg.de)
Heidelberg Collaboratory for Image Processing, University of Heidelberg, Germany

html generated using doxygen and Python
vigra 1.10.0 (Fri Feb 21 2014)