wibble  0.1.28
test.h
Go to the documentation of this file.
00001 // -*- C++ -*-
00002 
00003 #include <wibble/string.h>
00004 #include <iostream>
00005 #include <cstdlib>
00006 
00007 #ifndef WIBBLE_TEST_H
00008 #define WIBBLE_TEST_H
00009 
00010 // TODO use TLS
00011 extern int assertFailure;
00012 
00013 struct Location {
00014     const char *file;
00015     int line, iteration;
00016     const char *stmt;
00017     Location( const char *f, int l, const char *st, int iter = -1 )
00018         : file( f ), line( l ), iteration( iter ), stmt( st ) {}
00019 };
00020 
00021 #define LOCATION(stmt) Location( __FILE__, __LINE__, stmt )
00022 
00023 #ifndef NDEBUG
00024 #define LOCATION_I(stmt, i) Location( __FILE__, __LINE__, stmt, i )
00025 #define assert(x) assert_fn( LOCATION( #x ), x )
00026 #define assert_pred(p, x) assert_pred_fn( \
00027         LOCATION( #p "( " #x " )" ), x, p( x ) )
00028 #define assert_eq(x, y) assert_eq_fn( LOCATION( #x " == " #y ), x, y )
00029 #define assert_leq(x, y) assert_leq_fn( LOCATION( #x " <= " #y ), x, y )
00030 #define assert_eq_l(i, x, y) assert_eq_fn( LOCATION_I( #x " == " #y, i ), x, y )
00031 #define assert_neq(x, y) assert_neq_fn( LOCATION( #x " != " #y ), x, y )
00032 #define assert_list_eq(x, y) \
00033     assert_list_eq_fn( LOCATION( #x " == " #y ), \
00034                        sizeof( y ) / sizeof( y[0] ), x, y )
00035 #else
00036 #define assert(x) ((void)0)
00037 #define assert_pred(p, x) ((void)0)
00038 #define assert_eq(x, y) ((void)0)
00039 #define assert_leq(x, y) ((void)0)
00040 #define assert_eq_l(i, x, y) ((void)0)
00041 #define assert_neq(x, y) ((void)0)
00042 #define assert_list_eq(x, y) ((void)0)
00043 #endif
00044 
00045 #define assert_die() assert_die_fn( LOCATION( "forbidden code path tripped" ) )
00046 
00047 struct AssertFailed {
00048     std::ostream &stream;
00049     std::ostringstream str;
00050     bool expect;
00051     AssertFailed( Location l, std::ostream &s = std::cerr )
00052         : stream( s )
00053     {
00054         expect = assertFailure > 0;
00055         str << l.file << ": " << l.line;
00056         if ( l.iteration != -1 )
00057             str << " (iteration " << l.iteration << ")";
00058         str << ": assertion `" << l.stmt << "' failed;";
00059     }
00060 
00061     ~AssertFailed() {
00062         if ( expect )
00063             ++assertFailure;
00064         else {
00065             stream << str.str() << std::endl;
00066             abort();
00067         }
00068     }
00069 };
00070 
00071 template< typename X >
00072 inline AssertFailed &operator<<( AssertFailed &f, X x )
00073 {
00074     f.str << x;
00075     return f;
00076 }
00077 
00078 template< typename X >
00079 void assert_fn( Location l, X x )
00080 {
00081     if ( !x ) {
00082         AssertFailed f( l );
00083     }
00084 }
00085 
00086 void assert_die_fn( Location l ) __attribute__((noreturn));
00087 
00088 template< typename X, typename Y >
00089 void assert_eq_fn( Location l, X x, Y y )
00090 {
00091     if ( !( x == y ) ) {
00092         AssertFailed f( l );
00093         f << " got ["
00094           << x << "] != [" << y
00095           << "] instead";
00096     }
00097 }
00098 
00099 template< typename X, typename Y >
00100 void assert_leq_fn( Location l, X x, Y y )
00101 {
00102     if ( !( x <= y ) ) {
00103         AssertFailed f( l );
00104         f << " got ["
00105           << x << "] > [" << y
00106           << "] instead";
00107     }
00108 }
00109 
00110 template< typename X >
00111 void assert_pred_fn( Location l, X x, bool p )
00112 {
00113     if ( !p ) {
00114         AssertFailed f( l );
00115         f << " for " << x;
00116     }
00117 }
00118 
00119 template< typename X >
00120 void assert_list_eq_fn(
00121     Location loc, int c, X l, const typename X::Type check[] )
00122 {
00123     int i = 0;
00124     while ( !l.empty() ) {
00125         if ( l.head() != check[ i ] ) {
00126             AssertFailed f( loc );
00127             f << " list disagrees at position "
00128               << i << ": [" << wibble::str::fmt( l.head() )
00129               << "] != [" << wibble::str::fmt( check[ i ] )
00130               << "]";
00131         }
00132         l = l.tail();
00133         ++ i;
00134     }
00135     if ( i != c ) {
00136         AssertFailed f( loc );
00137         f << " got ["
00138           << i << "] != [" << c << "] instead";
00139     }
00140 }
00141 
00142 template< typename X, typename Y >
00143 void assert_neq_fn( Location l, X x, Y y )
00144 {
00145     if ( x != y )
00146         return;
00147     AssertFailed f( l );
00148     f << " got ["
00149       << x << "] == [" << y << "] instead";
00150 }
00151 
00152 inline void beginAssertFailure() {
00153     assertFailure = 1;
00154 }
00155 
00156 inline void endAssertFailure() {
00157     int f = assertFailure;
00158     assertFailure = 0;
00159     assert( f > 1 );
00160 }
00161 
00162 struct ExpectFailure {
00163     ExpectFailure() { beginAssertFailure(); }
00164     ~ExpectFailure() { endAssertFailure(); }
00165 };
00166 
00167 typedef void Test;
00168 
00169 #endif