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