38 #ifndef VIGRA_UNIT_TEST_HPP
39 #define VIGRA_UNIT_TEST_HPP
51 #include "vigra/config.hxx"
52 #include "vigra/error.hxx"
54 #ifdef VIGRA_NO_WORKING_STRINGSTREAM
56 #define VIGRA_SSTREAM std::strstream
57 #define VIGRA_SSTREAM_STR(s) ((s << char()), std::string(s.str()))
60 #define VIGRA_SSTREAM std::basic_stringstream<char>
61 #define VIGRA_SSTREAM_STR(s) s.str()
84 #elif defined(__CYGWIN__)
86 #define VIGRA_CANT_CATCH_SIGNALS
88 #elif defined(__unix) || defined(unix)
92 #include <sys/signal.h>
97 #define VIGRA_CANT_CATCH_SIGNALS
101 #define VIGRA_TEST_CASE(function) vigra::create_test_case(function, #function "()")
103 #define testCase VIGRA_TEST_CASE
105 #define VIGRA_TEST_SUITE(testsuite) ( new testsuite )
107 #define VIGRA_CHECKPOINT(message) \
108 vigra::detail::checkpoint_impl(message, __FILE__, __LINE__)
110 #define VIGRA_ASSERT(predicate) \
111 vigra::detail::should_impl((predicate), #predicate, __FILE__, __LINE__)
113 #define VIGRA_ASSERT_NOT(predicate) \
114 vigra::detail::should_impl(!(predicate), "!(" #predicate ")", __FILE__, __LINE__)
116 #define should VIGRA_ASSERT
118 #define shouldNot VIGRA_ASSERT_NOT
120 #define VIGRA_ASSERT_MESSAGE(predicate, message) \
121 vigra::detail::should_impl((predicate), message, __FILE__, __LINE__)
123 #define shouldMsg VIGRA_ASSERT_MESSAGE
125 #define shouldMessage VIGRA_ASSERT_MESSAGE
127 #define shouldEqual(left, right) \
128 vigra::detail::equal_impl(left, right, #left " == " #right, __FILE__, __LINE__)
130 #define shouldEqualMessage(left, right, message) \
131 vigra::detail::equal_impl(left, right, message "\n" #left " == " #right, __FILE__, __LINE__)
133 #define shouldEqualTolerance(left, right, eps) \
134 vigra::detail::tolerance_equal_impl(left, right, eps, #left " == " #right, __FILE__, __LINE__)
136 #define shouldEqualToleranceMessage(left, right, eps, message) \
137 vigra::detail::tolerance_equal_impl(left, right, eps, message "\n" #left " == " #right, __FILE__, __LINE__)
139 #define shouldEqualSequence(begin1, end1, begin2) \
140 vigra::detail::sequence_equal_impl(begin1, end1, begin2, __FILE__, __LINE__)
142 #define shouldEqualSequenceTolerance(begin1, end1, begin2, eps) \
143 vigra::detail::sequence_equal_tolerance_impl(begin1, end1, begin2, eps, __FILE__, __LINE__)
145 #define VIGRA_ERROR(message) \
146 vigra::detail::should_impl(false, message, __FILE__, __LINE__)
148 #define failTest VIGRA_ERROR
159 std::string str() {
return VIGRA_SSTREAM_STR(buf); }
161 errstream & operator<<(T t) { buf << t;
return *
this; }
164 inline std::string & exception_checkpoint()
166 static std::string test_checkpoint_;
167 return test_checkpoint_;
171 inline void report_exception( detail::errstream & os,
172 const char * name,
const char * info )
174 os <<
"Unexpected " << name <<
" " << info <<
"\n";
175 if(exception_checkpoint().size() > 0)
177 os <<
"Last checkpoint: " << exception_checkpoint() <<
"\n";
182 unexpected_exception = -1,
184 memory_access_violation = -3,
185 destructor_failure = -4
188 inline bool critical_error(
int i)
189 {
return i <= memory_access_violation; }
191 inline bool unexpected_error(
int i)
194 #ifndef VIGRA_CANT_CATCH_SIGNALS
198 inline long handle_signal_here(
long code)
202 case EXCEPTION_ACCESS_VIOLATION:
203 case EXCEPTION_INT_DIVIDE_BY_ZERO:
204 return EXCEPTION_EXECUTE_HANDLER;
206 return EXCEPTION_CONTINUE_SEARCH;
210 template<
class Generator >
211 int catch_signals( Generator function_object, detail::errstream & err,
int timeout )
217 result = function_object();
219 __except (handle_signal_here(code = GetExceptionCode()))
223 case EXCEPTION_ACCESS_VIOLATION:
224 report_exception(err,
"operating system exception:",
"memory access violation");
225 result = memory_access_violation;
227 case EXCEPTION_INT_DIVIDE_BY_ZERO:
228 report_exception(err,
"operating system exception:",
"integer divide by zero");
229 result = os_exception;
232 report_exception(err,
"operating system exception:",
"unrecognized exception or signal");
233 result = os_exception;
241 #elif defined(__unix)
245 inline jmp_buf & unit_test_jump_buffer()
247 static jmp_buf unit_test_jump_buffer_;
248 return unit_test_jump_buffer_;
251 static void unit_test_signal_handler(
int sig)
253 longjmp(unit_test_jump_buffer(), sig);
258 template<
class Generator >
259 int catch_signals( Generator function_object, detail::errstream & err,
int timeout)
261 volatile int sigtype;
264 #if defined(linux) || defined(__linux)
265 signal(SIGFPE, &unit_test_signal_handler);
266 signal(SIGTRAP, &unit_test_signal_handler);
267 signal(SIGSEGV, &unit_test_signal_handler);
268 signal(SIGBUS, &unit_test_signal_handler);
270 sigset(SIGFPE, &unit_test_signal_handler);
271 sigset(SIGTRAP, &unit_test_signal_handler);
272 sigset(SIGSEGV, &unit_test_signal_handler);
273 sigset(SIGBUS, &unit_test_signal_handler);
278 #if defined(linux) || defined(__linux)
279 signal(SIGALRM, &unit_test_signal_handler);
281 sigset(SIGALRM, &unit_test_signal_handler);
286 sigtype = setjmp(unit_test_jump_buffer());
289 result = function_object();
296 report_exception(err,
"signal:",
"SIGALRM (timeout while executing function)");
297 result = os_exception;
300 report_exception(err,
"signal:",
"SIGTRAP (perhaps integer divide by zero)");
301 result = os_exception;
304 report_exception(err,
"signal:",
"SIGFPE (arithmetic exception)");
305 result = os_exception;
309 report_exception(err,
"signal:",
"memory access violation");
310 result = memory_access_violation;
313 report_exception(err,
"signal:",
"unrecognized signal");
314 result = os_exception;
321 #if defined(linux) || defined(__linux)
327 #if defined(linux) || defined(__linux)
342 template<
class Generator >
343 int catch_signals( Generator function_object, detail::errstream & err ,
int)
345 return function_object();
352 template<
class Generator >
353 int catch_exceptions( Generator function_object, detail::errstream & err,
int timeout )
355 int result = detail::unexpected_exception;
359 result = detail::catch_signals(function_object, err, timeout);
370 catch ( vigra::ContractViolation & ex )
371 { detail::report_exception( err,
"Contract exception: ", ex.what() ); }
372 catch (
const char * ex )
373 { detail::report_exception( err,
"string exception: ", ex ); }
374 catch (
const std::string & ex )
375 { detail::report_exception( err,
"string exception: ", ex.c_str() ); }
378 catch (
const std::bad_alloc & ex )
379 { detail::report_exception( err,
"exception: std::bad_alloc:", ex.what() ); }
381 # if !defined(__BORLANDC__) || __BORLANDC__ > 0x0551
382 catch (
const std::bad_cast & ex )
383 { detail::report_exception( err,
"exception: std::bad_cast:", ex.what() ); }
384 catch (
const std::bad_typeid & ex )
385 { detail::report_exception( err,
"exception: std::bad_typeid:", ex.what() ); }
387 catch (
const std::bad_cast & ex )
388 { detail::report_exception( err,
"exception: std::bad_cast",
"" ); }
389 catch (
const std::bad_typeid & ex )
390 { detail::report_exception( err,
"exception: std::bad_typeid",
"" ); }
393 catch (
const std::bad_exception & ex )
394 { detail::report_exception( err,
"exception: std::bad_exception:", ex.what() ); }
395 catch (
const std::domain_error & ex )
396 { detail::report_exception( err,
"exception: std::domain_error:", ex.what() ); }
397 catch (
const std::invalid_argument & ex )
398 { detail::report_exception( err,
"exception: std::invalid_argument:", ex.what() ); }
399 catch (
const std::length_error & ex )
400 { detail::report_exception( err,
"exception: std::length_error:", ex.what() ); }
401 catch (
const std::out_of_range & ex )
402 { detail::report_exception( err,
"exception: std::out_of_range:", ex.what() ); }
403 catch (
const std::range_error & ex )
404 { detail::report_exception( err,
"exception: std::range_error:", ex.what() ); }
405 catch (
const std::overflow_error & ex )
406 { detail::report_exception( err,
"exception: std::overflow_error:", ex.what() ); }
407 catch (
const std::underflow_error & ex )
408 { detail::report_exception( err,
"exception: std::underflow_error:", ex.what() ); }
409 catch (
const std::logic_error & ex )
410 { detail::report_exception( err,
"exception: std::logic_error:", ex.what() ); }
411 catch (
const std::runtime_error & ex )
412 { detail::report_exception( err,
"exception: std::runtime_error:", ex.what() ); }
413 catch (
const std::exception & ex )
414 { detail::report_exception( err,
"exception: std::exception:", ex.what() ); }
418 detail::report_exception( err,
"unknown exception",
"" );
425 template<
class Generator >
427 int catch_exceptions( Generator function_object, detail::errstream & err)
429 return catch_exceptions(function_object, err, 0);
434 struct unit_test_failed
435 :
public std::exception
437 unit_test_failed(std::string
const & message)
441 virtual ~unit_test_failed() throw()
445 virtual const char * what()
const throw()
447 return what_.c_str();
454 checkpoint_impl(
const char * message,
const char * file,
int line)
456 detail::errstream buf;
457 buf << message <<
" (" << file <<
":" << line <<
")";
458 exception_checkpoint() = buf.str();
462 should_impl(
bool predicate,
const char * message,
const char * file,
int line)
464 checkpoint_impl(message, file, line);
467 detail::errstream buf;
468 buf << message <<
" (" << file <<
":" << line <<
")";
469 throw unit_test_failed(buf.str());
474 should_impl(
bool predicate, std::string
const & message,
const char * file,
int line)
476 should_impl(predicate, message.c_str(), file, line);
479 template <
class Iter1,
class Iter2>
481 sequence_equal_impl(Iter1 i1, Iter1 end1, Iter2 i2,
const char * file,
int line)
483 for(
int counter = 0; i1 != end1; ++i1, ++i2, ++counter)
487 detail::errstream buf;
488 buf <<
"Sequence items differ at index " << counter <<
489 " ["<< *i1 <<
" != " << *i2 <<
"]";
490 should_impl(
false, buf.str().c_str(), file, line);
499 struct ScalarType {};
500 struct VectorType {};
505 typedef VectorType ScalarOrVector;
509 struct FloatTraits<float>
511 typedef ScalarType ScalarOrVector;
512 static float epsilon() {
return FLT_EPSILON; }
513 static float smallestPositive() {
return FLT_MIN; }
514 static float min() {
return -FLT_MAX; }
515 static float max() {
return FLT_MAX; }
519 struct FloatTraits<double>
521 typedef ScalarType ScalarOrVector;
522 static double epsilon() {
return DBL_EPSILON; }
523 static double smallestPositive() {
return DBL_MIN; }
524 static double min() {
return -DBL_MAX; }
525 static double max() {
return DBL_MAX; }
529 struct FloatTraits<long double>
531 typedef ScalarType ScalarOrVector;
532 static long double epsilon() {
return LDBL_EPSILON; }
533 static long double smallestPositive() {
return LDBL_MIN; }
534 static long double min() {
return -LDBL_MAX; }
535 static long double max() {
return LDBL_MAX; }
540 FPT fpt_abs( FPT
arg )
542 return arg < 0 ? -arg :
arg;
551 FPT safe_fpt_division( FPT f1, FPT f2 )
563 return ((f2 < 1) && (f1 > (f2 * FloatTraits<FPT>::max()))) ?
564 FloatTraits<FPT>::max() :
565 ((((f2 > 1) && (f1 < (f2 * FloatTraits<FPT>::smallestPositive())))
566 || (f1 == 0)) ? 0 : f1/f2 );
575 class close_at_tolerance {
577 explicit close_at_tolerance( FPT tolerance,
bool strong_test =
true )
578 : m_strong_test( strong_test ),
579 m_tolerance( tolerance ) {}
581 explicit close_at_tolerance(
int number_of_rounding_errors,
bool strong_test =
true )
582 : m_strong_test( strong_test ),
583 m_tolerance( FloatTraits<FPT>::epsilon() * number_of_rounding_errors / 2.0 ) {}
585 bool operator()( FPT left, FPT right )
const
587 if (left == 0 && right != 0)
589 return (fpt_abs(right) <= m_tolerance);
591 if (right == 0 && left != 0)
593 return (fpt_abs(left) <= m_tolerance);
595 FPT diff = fpt_abs( left - right );
596 FPT d1 = safe_fpt_division( diff, fpt_abs( right ) );
597 FPT d2 = safe_fpt_division( diff, fpt_abs( left ) );
599 return m_strong_test ? (d1 <= m_tolerance && d2 <= m_tolerance)
600 : (d1 <= m_tolerance || d2 <= m_tolerance);
610 template <
class T1,
class T2,
class T3>
612 tolerance_equal_impl(T1 left, T2 right, T3 epsilon,
613 const char * message,
const char * file,
int line, ScalarType)
615 detail::errstream buf;
616 buf << message <<
" [" << left <<
" != " << right <<
"]";
618 close_at_tolerance<T3> fcomparator( epsilon );
619 bool compare = fcomparator ( (T3)left , (T3)right );
620 should_impl(compare, buf.str().c_str(), file, line);
624 template <
class T1,
class T2,
class T3>
626 tolerance_equal_impl(T1 left, T2 right, T3 epsilon,
627 const char * message,
const char * file,
int line, VectorType)
629 detail::errstream buf;
630 buf << message <<
" [" << left <<
" != " << right <<
"]";
633 for(
unsigned int i=0; i<epsilon.size(); ++i)
635 close_at_tolerance<typename T3::value_type> fcomparator( epsilon[i] );
636 compare = compare && fcomparator ( left[i] , right[i] );
638 should_impl(compare, buf.str().c_str(), file, line);
641 template <
class T1,
class T2,
class T3>
643 tolerance_equal_impl(T1 left, T2 right, T3 epsilon,
const char * message,
const char * file,
int line)
645 tolerance_equal_impl(left, right, epsilon,
646 message, file, line,
typename FloatTraits<T3>::ScalarOrVector());
649 template <
class Iter1,
class Iter2,
class T>
651 sequence_equal_tolerance_impl(Iter1 i1, Iter1 end1, Iter2 i2, T epsilon,
const char * file,
int line)
653 for(
int counter = 0; i1 != end1; ++i1, ++i2, ++counter)
655 detail::errstream buf;
656 buf <<
"Sequence items differ at index " << counter;
657 tolerance_equal_impl(*i1, *i2, epsilon, buf.str().c_str(), file, line,
typename FloatTraits<T>::ScalarOrVector());
661 template <
class Left,
class Right>
663 equal_impl(Left left, Right right,
const char * message,
const char * file,
int line)
665 detail::errstream buf;
666 buf << message <<
" [" << left <<
" != " << right <<
"]";
667 should_impl(left == right, buf.str().c_str(), file, line);
670 template <
class Left,
class Right>
672 equal_impl(Left * left, Right * right,
const char * message,
const char * file,
int line)
674 detail::errstream buf;
675 buf << message <<
" [" << (
void*)left <<
" != " << (
void*)right << "]";
676 should_impl(left == right, buf.str().c_str(), file, line);
680 equal_impl(
double left,
double right, const
char * message, const
char * file,
int line)
682 tolerance_equal_impl(left, right, 1.0e-16, message, file, line);
686 equal_impl(
float left,
float right,
const char * message,
const char * file,
int line)
688 tolerance_equal_impl(left, right, 1.0e-6f, message, file, line);
692 equal_impl(
float left,
double right,
const char * message,
const char * file,
int line)
694 tolerance_equal_impl(left, right, 1.0e-6f, message, file, line);
698 equal_impl(
double left,
float right,
const char * message,
const char * file,
int line)
700 tolerance_equal_impl(left, right, 1.0e-6f, message, file, line);
707 test_case(
char const * name =
"Unnamed")
708 : name_(name), timeout(0)
711 virtual ~test_case() {}
713 virtual int run() {
return run(std::vector<std::string>()); }
714 virtual int run(std::vector<std::string>
const & testsToBeRun) = 0;
715 virtual void do_init() {}
716 virtual void do_run() {}
717 virtual void do_destroy() {}
719 virtual char const * name() {
return name_.c_str(); }
720 virtual int size()
const {
return 1; }
722 virtual int numberOfTestsToRun(std::vector<std::string>
const & testsToBeRun)
const
724 if(testsToBeRun.empty())
726 for(
unsigned int k=0; k<testsToBeRun.size(); ++k)
727 if(this->name_.find(testsToBeRun[k]) != std::string::npos)
740 std::vector<std::string> testsToBeExecuted(
int argc,
char ** argv)
742 std::vector<std::string> res;
743 for(
int i=1; i < argc; ++i)
744 res.push_back(std::string(argv[i]));
749 :
public detail::test_case
752 using detail::test_case::run;
754 test_suite(
char const * name =
"TopLevel")
755 : detail::test_case(name),
759 virtual ~test_suite()
761 for(
unsigned int i=0; i != testcases_.size(); ++i)
762 delete testcases_[i];
765 virtual void add(detail::test_case * t,
int timeout = 0)
767 t->timeout = timeout;
768 testcases_.push_back(t);
772 virtual int run(std::vector<std::string>
const & testsToBeRun)
774 int size = numberOfTestsToRun(testsToBeRun);
776 std::vector<std::string> testsToBeRunRecursive =
779 : std::vector<std::string>();
782 report_ = std::string(
"Entering test suite ") + name() +
"\n";
784 for(
unsigned int i=0; i != testcases_.size(); ++i)
786 int result = testcases_[i]->run(testsToBeRunRecursive);
787 report_ += testcases_[i]->report_;
789 if(detail::critical_error(result))
791 report_ += std::string(
"\nFatal error - aborting test suite ") + name() +
".\n";
794 else if(detail::unexpected_error(result))
802 detail::errstream buf;
803 buf <<
"\n" << failed <<
" of " << size <<
804 " tests failed in test suite " << name() <<
"\n";
805 report_ += buf.str();
809 detail::errstream buf;
810 buf <<
"All (" << size <<
811 ") tests passed in test suite " << name() <<
"\n";
812 report_ += buf.str();
815 report_ += std::string(
"Leaving test suite ") + name() +
"\n";
820 virtual int numberOfTestsToRun(std::vector<std::string>
const & testsToBeRun)
const
822 if(detail::test_case::numberOfTestsToRun(testsToBeRun) > 0)
825 for(
unsigned int i=0; i != testcases_.size(); ++i)
826 size += testcases_[i]->numberOfTestsToRun(testsToBeRun);
830 virtual int size()
const {
return size_; }
831 virtual std::string report() {
return report_; }
833 std::vector<detail::test_case *> testcases_;
839 struct test_case_init_functor
841 detail::errstream & buf_;
842 test_case * test_case_;
844 test_case_init_functor(detail::errstream & b, test_case * tc)
845 : buf_(b), test_case_(tc)
852 test_case_->do_init();
855 catch(unit_test_failed & e)
857 buf_ <<
"Assertion failed: " << e.what() <<
"\n";
863 struct test_case_run_functor
865 detail::errstream & buf_;
866 test_case * test_case_;
868 test_case_run_functor(detail::errstream & b, test_case * tc)
869 : buf_(b), test_case_(tc)
876 test_case_->do_run();
879 catch(unit_test_failed & e)
881 buf_ <<
"Assertion failed: " << e.what() <<
"\n";
887 struct test_case_destroy_functor
889 detail::errstream & buf_;
890 test_case * test_case_;
892 test_case_destroy_functor(detail::errstream & b, test_case * tc)
893 : buf_(b), test_case_(tc)
900 test_case_->do_destroy();
903 catch(unit_test_failed & e)
905 buf_ <<
"Assertion failed: " << e.what() <<
"\n";
911 template <
class TESTCASE>
912 class class_test_case
916 using test_case::run;
918 class_test_case(
void (TESTCASE::*fct)(),
char const * name)
924 virtual ~class_test_case()
929 virtual void do_init()
931 testcase_ =
new TESTCASE;
936 exception_checkpoint() =
"";
940 detail::errstream buf;
941 buf <<
"\nFailure in initialization of " << name() <<
"\n";
944 buf <<
"Test case failed to clean up after previous run.\n";
949 failed = catch_exceptions(
950 detail::test_case_init_functor(buf,
this), buf, timeout);
955 report_ += buf.str();
961 virtual void do_run()
964 (testcase_->*fct_)();
967 virtual int run(std::vector<std::string>
const & testsToBeRun)
969 if(numberOfTestsToRun(testsToBeRun) == 0)
977 detail::errstream buf;
978 buf <<
"\nFailure in " << name() <<
"\n";
980 failed = catch_exceptions(
981 detail::test_case_run_functor(buf,
this), buf, timeout);
983 report_ += buf.str();
985 if(critical_error(failed))
988 int destruction_failed = destroy();
990 return destruction_failed ?
995 virtual void do_destroy()
1003 detail::errstream buf;
1004 buf <<
"\nFailure in destruction of " <<
"\n";
1006 int failed = catch_exceptions(
1007 detail::test_case_destroy_functor(buf,
this), buf, timeout);
1010 report_ += buf.str();
1011 return destructor_failure;
1019 void (TESTCASE::*fct_)();
1020 TESTCASE * testcase_;
1023 class function_test_case
1027 using test_case::run;
1029 function_test_case(
void (*fct)(),
char const * name)
1034 virtual void do_run()
1039 virtual int run(std::vector<std::string>
const & testsToBeRun)
1041 if(numberOfTestsToRun(testsToBeRun) == 0)
1045 exception_checkpoint() =
"";
1047 detail::errstream buf;
1048 buf <<
"\nFailure in " << name() <<
"\n";
1050 int failed = catch_exceptions(
1051 detail::test_case_run_functor(buf,
this), buf, timeout);
1054 report_ += buf.str();
1063 template <
class FCT>
1066 virtual ~test_functor() {}
1067 virtual void operator()() = 0;
1070 {
return FCT(static_cast<FCT const &>(*
this)); }
1073 template <
class FCT>
1074 class functor_test_case
1078 using test_case::run;
1080 functor_test_case(FCT
const & fct,
char const * name)
1085 virtual void do_run()
1090 virtual int run(std::vector<std::string>
const & testsToBeRun)
1092 if(numberOfTestsToRun(testsToBeRun) == 0)
1096 exception_checkpoint() =
"";
1098 detail::errstream buf;
1099 buf <<
"\nFailure in " << name() <<
"\n";
1101 int failed = catch_exceptions(
1102 detail::test_case_run_functor(buf,
this), buf, timeout);
1105 report_ += buf.str();
1116 template <
class TESTCASE>
1119 create_test_case(
void (TESTCASE::*fct)(),
char const * name)
1121 if(*name ==
'&') ++name;
1122 return new detail::class_test_case<TESTCASE>(fct, name);
1127 create_test_case(
void (*fct)(),
char const * name)
1129 if(*name ==
'&') ++name;
1130 return new detail::function_test_case(fct, name);
1133 template <
class FCT>
1136 create_test_case(detail::test_functor<FCT>
const & fct,
char const * name)
1138 if(*name ==
'&') ++name;
1139 return new detail::functor_test_case<FCT>(fct.clone(), name);
1145 #if !defined(__GNUC__) || __GNUC__ >= 3
1149 template <
class E,
class T,
class V>
1151 std::basic_ostream<E,T> & operator,(std::basic_ostream<E,T> & o, V
const & t)
1153 return (o <<
' ' << t);
1156 template <
class E,
class T>
1158 std::basic_ostream<E,T> & operator,(std::basic_ostream<E,T> & o,
1159 std::basic_ostream<E,T> & (*t)(std::basic_ostream<E,T> &))
1168 std::ostream & operator,(std::ostream & o, V
const & t)
1170 return (o <<
' ' << t);
1174 std::ostream & operator,(std::ostream & o,
1175 std::ostream & (*t)(std::ostream &))