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

© 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