wibble  1.1
test.h
Go to the documentation of this file.
1 // -*- C++ -*-
2 
3 #include <wibble/string.h>
4 #include <iostream>
5 #include <cstdlib>
6 
7 #ifndef WIBBLE_TEST_H
8 #define WIBBLE_TEST_H
9 
10 namespace wibble {
11 
12 // TODO use TLS
13 extern int assertFailure;
14 
15 struct Location {
16  const char *file;
18  std::string stmt;
19  Location( const char *f, int l, std::string st, int iter = -1 )
20  : file( f ), line( l ), iteration( iter ), stmt( st ) {}
21 };
22 
23 #define LOCATION(stmt) ::wibble::Location( __FILE__, __LINE__, stmt )
24 
25 #undef assert // silence a gcc warning if we had assert.h included
26 
27 #ifndef NDEBUG
28 #define LOCATION_I(stmt, i) ::wibble::Location( __FILE__, __LINE__, stmt, i )
29 
30 #define assert(x) assert_fn( LOCATION( #x ), x )
31 #define assert_pred(p, x) assert_pred_fn( \
32  LOCATION( #p "( " #x " )" ), x, p( x ) )
33 #define assert_eq(x, y) assert_eq_fn( LOCATION( #x " == " #y ), x, y )
34 #define assert_leq(x, y) assert_leq_fn( LOCATION( #x " <= " #y ), x, y )
35 #define assert_eq_l(i, x, y) assert_eq_fn( LOCATION_I( #x " == " #y, i ), x, y )
36 #define assert_neq(x, y) assert_neq_fn( LOCATION( #x " != " #y ), x, y )
37 #define assert_list_eq(x, y) \
38  assert_list_eq_fn( LOCATION( #x " == " #y ), \
39  sizeof( y ) / sizeof( y[0] ), x, y )
40 #else
41 #define assert(x) ((void)0)
42 #define assert_pred(p, x) ((void)0)
43 #define assert_eq(x, y) ((void)0)
44 #define assert_leq(x, y) ((void)0)
45 #define assert_eq_l(i, x, y) ((void)0)
46 #define assert_neq(x, y) ((void)0)
47 #define assert_list_eq(x, y) ((void)0)
48 #endif
49 
50 #define assert_unreachable(...) assert_die_fn( LOCATION( wibble::str::fmtf(__VA_ARGS__) ) )
51 #define assert_unimplemented() assert_die_fn( LOCATION( "not imlemented" ) )
52 #define assert_die() assert_die_fn( LOCATION( "forbidden code path tripped" ) )
53 
54 struct AssertFailed {
55  std::ostream &stream;
56  std::ostringstream str;
57  bool expect;
58  AssertFailed( Location l, std::ostream &s = std::cerr )
59  : stream( s )
60  {
61  expect = assertFailure > 0;
62  str << l.file << ": " << l.line;
63  if ( l.iteration != -1 )
64  str << " (iteration " << l.iteration << ")";
65  str << ": assertion `" << l.stmt << "' failed;";
66  }
67 
69  if ( expect )
70  ++assertFailure;
71  else {
72  stream << str.str() << std::endl;
73  abort();
74  }
75  }
76 };
77 
78 template< typename X >
80 {
81  f.str << x;
82  return f;
83 }
84 
85 template< typename X >
86 void assert_fn( Location l, X x )
87 {
88  if ( !x ) {
89  AssertFailed f( l );
90  }
91 }
92 
93 void assert_die_fn( Location l ) __attribute__((noreturn));
94 
95 template< typename X, typename Y >
96 void assert_eq_fn( Location l, X x, Y y )
97 {
98  if ( !( x == y ) ) {
99  AssertFailed f( l );
100  f << " got ["
101  << x << "] != [" << y
102  << "] instead";
103  }
104 }
105 
106 template< typename X, typename Y >
107 void assert_leq_fn( Location l, X x, Y y )
108 {
109  if ( !( x <= y ) ) {
110  AssertFailed f( l );
111  f << " got ["
112  << x << "] > [" << y
113  << "] instead";
114  }
115 }
116 
117 template< typename X >
118 void assert_pred_fn( Location l, X x, bool p )
119 {
120  if ( !p ) {
121  AssertFailed f( l );
122  f << " for " << x;
123  }
124 }
125 
126 template< typename X >
128  Location loc, int c, X l, const typename X::Type check[] )
129 {
130  int i = 0;
131  while ( !l.empty() ) {
132  if ( l.head() != check[ i ] ) {
133  AssertFailed f( loc );
134  f << " list disagrees at position "
135  << i << ": [" << wibble::str::fmt( l.head() )
136  << "] != [" << wibble::str::fmt( check[ i ] )
137  << "]";
138  }
139  l = l.tail();
140  ++ i;
141  }
142  if ( i != c ) {
143  AssertFailed f( loc );
144  f << " got ["
145  << i << "] != [" << c << "] instead";
146  }
147 }
148 
149 template< typename X, typename Y >
150 void assert_neq_fn( Location l, X x, Y y )
151 {
152  if ( x != y )
153  return;
154  AssertFailed f( l );
155  f << " got ["
156  << x << "] == [" << y << "] instead";
157 }
158 
159 inline void beginAssertFailure() {
160  assertFailure = 1;
161 }
162 
163 inline void endAssertFailure() {
164 #ifndef NDEBUG
165  const int f = assertFailure;
166  assertFailure = 0;
167 #endif
168  assert( f > 1 );
169 }
170 
174 };
175 
176 }
177 
178 typedef void Test;
179 
180 #endif