lasso
|
00001 #ifndef TEST_UTIL_HPP 00002 #define TEST_UTIL_HPP 00003 00004 /* Define these here because they are used by many tests 00005 * to find the add directory for input files */ 00006 #define STRINGIFY_(X) #X 00007 #define STRINGIFY(X) STRINGIFY_(X) 00008 00009 /* How to use this test suite utility: 00010 * 1) Write tests that use the CHECK and CHECK_* macros defined below to assert test conditions. 00011 * 2) Write a main routine that invokes each test through the RUN_TEST macro 00012 * 3) RUN_TEST evaluates to 1 if test failed, zero otherwize. Count failures and print summary. 00013 */ 00014 00016 #define CHECK_ERR( A ) check_equal( iBase_SUCCESS, (A), "iBase_SUCCESS", #A, __LINE__, __FILE__ ) 00017 00018 #define CHECK( A ) check_true( (A), #A, __LINE__, __FILE__ ) 00019 00020 #define CHECK_EQUAL( EXP, ACT ) check_equal( (EXP), (ACT), #EXP, #ACT, __LINE__, __FILE__ ) 00021 00022 #define CHECK_REAL_EQUAL( EXP, ACT, EPS ) check_equal( (EXP), (ACT), (EPS), #EXP, #ACT, __LINE__, __FILE__ ) 00023 00024 #define CHECK_ARRAYS_EQUAL( EXP, EXP_LEN, ACT, ACT_LEN ) check_array_equal( (EXP), (EXP_LEN), (ACT), (ACT_LEN), #EXP, #ACT, __LINE__, __FILE__ ) 00025 00029 #define RUN_TEST( FUNC ) run_test( &FUNC, #FUNC ) 00030 00031 00032 // Use C++ exceptions to return error state to test runner 00033 // Portable, but whole test suite stops if any test segfaults, asserts, etc. 00034 #define EXCEPTION_MODE 1 00035 00036 // Test runner forks separate process for each test. 00037 // Difficult to debug tests (with debugger). Not portable to Windows. 00038 // Very robust (no test can distrub test running code) 00039 #define FORK_MODE 2 00040 00041 // Use signal handler and long jumps to return error state to test runner. 00042 // Might be portable to Windows (not sure). Possibly undefined behavior (e.g. continuing 00043 // with next test after catching segfault is technically undefined behavior.) 00044 // Also, tests can corrupt heap memory management, interferring with later tests. 00045 // Leaks memory on test failure (no stack unwind). This is actually a feature, as 00046 // we don't care too much about tests leaking memory and trying to reconver memory 00047 // might make things worse, depending on why the test failed. 00048 #define LONGJMP_MODE 3 00049 00050 // If test application hasn't set MODE, set to default 00051 #ifndef MODE 00052 #if defined(_MSC_VER) || defined(__MINGW32__) 00053 # define MODE EXCEPTION_MODE 00054 # else 00055 # define MODE LONGJMP_MODE 00056 # endif 00057 #endif 00058 00059 00060 00061 /*************************************************************************************** 00062 * NOTE: The remainder of this file contains the implementation of the above macros. 00063 * The above macros constitute the entire intended API. 00064 ***************************************************************************************/ 00065 00066 #include <math.h> 00067 #include <stdio.h> 00068 #include <stdlib.h> 00069 #include <string.h> 00070 #include <string> 00071 #ifdef __cplusplus 00072 #include <iostream> 00073 #include <vector> 00074 #endif 00075 00076 /*************************************************************************************** 00077 * Define What to do when a test fails. 00078 ***************************************************************************************/ 00079 00080 // For EXCEPTION_MODE, throw an exception when a test fails. 00081 // This will unwind stack, recover memory, etc. 00082 #if MODE == EXCEPTION_MODE 00083 struct ErrorExcept{}; 00084 # define FLAG_ERROR throw ErrorExcept() 00085 // For FORK_MODE, the test is running in its own processs. Just 00086 // terminate the process with a non-zero exit code when the test 00087 // fails. 00088 #elif MODE == FORK_MODE 00089 # include <sys/types.h> 00090 # include <sys/wait.h> 00091 # include <unistd.h> 00092 # include <errno.h> 00093 # define FLAG_ERROR exit(1) 00094 // For LONGJMP_MODE, we do a long jump to just before the test is 00095 // run, with a return value of -1 to indicate failures (positive 00096 // return codes are used if the test caused a segfault or other 00097 // signal.) 00098 #elif MODE == LONGJMP_MODE 00099 # include <signal.h> 00100 # include <setjmp.h> 00101 # define FLAG_ERROR siglongjmp( jmpenv, -1 ) 00102 #else 00103 # error "MODE not set" 00104 #endif 00105 00106 /*************************************************************************************** 00107 * Setup for LONGJMP_MODE 00108 ***************************************************************************************/ 00109 00110 #if MODE == LONGJMP_MODE 00111 00112 // Variable to hold stack state for longjmp 00113 sigjmp_buf jmpenv; 00114 00115 // Define signal handler used to catch errors such as segfaults. 00116 // Signal handler does longjmp with the signal number as the 00117 // return value. 00118 extern "C" { 00119 void sighandler( int sig ) { 00120 signal( sig, sighandler ); 00121 siglongjmp(jmpenv, sig); 00122 // should never return from longjmp 00123 exit(1); 00124 } 00125 typedef void (*sigfunc_t)(int); 00126 } // extern "C" 00127 00128 // Helper function to register signal handlers. 00129 int sethandler( int sig ) { 00130 sigfunc_t h = signal( sig, &sighandler ); 00131 if (h == SIG_ERR) 00132 return 1; 00133 // If user-defined signal handler (or signal is ignored), 00134 // than unregister our handler. 00135 else if (h != SIG_DFL) 00136 signal( sig, h ); 00137 return 0; 00138 } 00139 00140 // Register signal handlers for all defined signals that typicall result 00141 // in process termination. 00142 int init_signal_handlers() 00143 { 00144 int result = 0; 00145 /* Don't trap these. It is unlikely that a test would ever generate such 00146 a signal on its own and trapping them interfers with a user's ability 00147 to stop a test. SIGHUP implies that the controlling terminal was closed. 00148 If the user does ctrl-C or ctrl-\ (SIGINT and SIGQUIT, respectively) and 00149 we trap these then just the current test stops. If we leave the default 00150 behavior for them then the whole test suite stops. The latter is likely 00151 the desired behavior. SIGTERM is the default signal sent by the 'kill' 00152 command. 00153 #ifdef SIGHUP 00154 result += sethandler( SIGHUP ); 00155 #endif 00156 #ifdef SIGINT 00157 result += sethandler( SIGINT ); 00158 #endif 00159 #ifdef SIGQUIT 00160 result += sethandler( SIGQUIT ); 00161 #endif 00162 #ifdef SIGTERM 00163 result += sethandler( SIGTERM ); 00164 #endif 00165 */ 00166 00167 #ifdef SIGILL 00168 result += sethandler( SIGILL ); 00169 #endif 00170 #ifdef SIGTRAP 00171 result += sethandler( SIGTRAP ); 00172 #endif 00173 #ifdef SIGABRT 00174 result += sethandler( SIGABRT ); 00175 #endif 00176 #ifdef SIGBUS 00177 result += sethandler( SIGBUS ); 00178 #endif 00179 #ifdef SIGFPE 00180 result += sethandler( SIGFPE ); 00181 #endif 00182 #ifdef SIGSEGV 00183 result += sethandler( SIGSEGV ); 00184 #endif 00185 00186 /* Catching these causes problems with mpich2 1.3.1p1 and a 00187 test should never receive such a signal anyway. 00188 #ifdef SIGUSR1 00189 result += sethandler( SIGUSR1 ); 00190 #endif 00191 #ifdef SIGUSR2 00192 result += sethandler( SIGUSR2 ); 00193 #endif 00194 */ 00195 00196 /* Don't trap SIGCHLD. The only way a test should receive 00197 such a signal is if it actually forked a child process. 00198 That is unlikely, but if it does happen the test probably 00199 wants to handle the signal itself. 00200 #ifdef SIGCHLD 00201 result += sethandler( SIGCHLD ); 00202 #endif 00203 */ 00204 00205 #ifdef SIGPIPE 00206 result += sethandler( SIGPIPE ); 00207 #endif 00208 #ifdef SIGIO 00209 result += sethandler( SIGIO ); 00210 #endif 00211 #ifdef SIGSYS 00212 result += sethandler( SIGSYS ); 00213 #endif 00214 return result; 00215 } 00216 00217 // Declare a garbage global variable. Use variable initialization to 00218 // force call to init_signal_handlers(). 00219 int junk_init_var = init_signal_handlers(); 00220 00221 #endif // LONGJMP_MODE 00222 00223 00224 /*************************************************************************************** 00225 * Function to handle failed tests 00226 ***************************************************************************************/ 00227 00228 // use a function rather than substituting FLAG_ERROR directly 00229 // so we have a convenient place to set a break point 00230 inline void flag_error() 00231 { FLAG_ERROR; } 00232 00233 00234 /*************************************************************************************** 00235 * The Code to Run Tests 00236 ***************************************************************************************/ 00237 00238 00239 typedef void (*test_func)(void); 00240 int run_test( test_func test, const char* func_name ) 00241 { 00242 printf("Running %s ...\n", func_name ); 00243 00244 #if MODE == EXCEPTION_MODE 00245 /* On Windows, run all tests in same process. 00246 Flag errors by throwing an exception. 00247 */ 00248 try { 00249 (*test)(); 00250 return 0; 00251 } 00252 catch (ErrorExcept) { 00253 printf( " %s: FAILED\n", func_name ); 00254 return 1; 00255 } 00256 catch (...) { 00257 printf( " %s: UNCAUGHT EXCEPTION\n", func_name ); 00258 return 1; 00259 } 00260 00261 #elif MODE == FORK_MODE 00262 /* For non-Windows OSs, fork() and run test in child process. */ 00263 pid_t pid = fork(); 00264 int status; 00265 00266 /* Fork failed? */ 00267 if (pid == -1) { 00268 perror( "fork()" ); 00269 abort(); /* abort all tests (can't fork child processes) */ 00270 } 00271 00272 /* If child process*/ 00273 if (pid == 0) { 00274 (*test)(); /* call test function */ 00275 exit(0); /* if function returned, then it succeeded */ 00276 } 00277 00278 /* If here, then parent process */ 00279 00280 /* Wait until child process exits */ 00281 waitpid( pid, &status, 0 ); 00282 00283 /* Check child exit status */ 00284 if (WIFSIGNALED(status)) { 00285 if (WTERMSIG(status)) 00286 printf(" %s: TERMINATED (signal %d)\n", func_name, (int)WTERMSIG(status) ); 00287 if (WCOREDUMP(status)) 00288 printf(" %s: CORE DUMP\n", func_name); 00289 return 1; 00290 } 00291 else if(WEXITSTATUS(status)) { 00292 printf( " %s: FAILED\n", func_name ); 00293 return 1; 00294 } 00295 else { 00296 return 0; 00297 } 00298 00299 #elif MODE == LONGJMP_MODE 00300 // Save stack state at this location. 00301 int rval = sigsetjmp( jmpenv, 1 ); 00302 // If rval is zero, then we haven't run the test yet. 00303 // If rval is non-zero then 00304 // a) we ran the test 00305 // b) the test failed 00306 // c) we did a longjmp back to the location where we called setsigjmp. 00307 00308 // run test 00309 if (!rval) { 00310 (*test)(); 00311 return 0; 00312 } 00313 // some check failed 00314 else if (rval == -1) { 00315 printf( " %s: FAILED\n", func_name ); 00316 return 1; 00317 } 00318 // a signal was raised (e.g. segfault) 00319 else { 00320 printf( " %s: TERMINATED (signal %d)\n", func_name, rval ); 00321 return 1; 00322 } 00323 #else 00324 #error "MODE not set" 00325 #endif // MODE 00326 } 00327 00328 00329 00330 /*************************************************************************************** 00331 * CHECK_EQUAL implementations 00332 ***************************************************************************************/ 00333 00334 // Common implementatation for most types 00335 #define EQUAL_TEST_IMPL( TEST, TYPE ) if( !(TEST) ) { \ 00336 printf( "Equality Test Failed: %s == %s\n", sA, sB ); \ 00337 printf( " at line %d of '%s'\n", line, file ); \ 00338 printf( " Expected value: %" #TYPE "\n", A ); \ 00339 printf( " Actual value: %" #TYPE "\n", B ); \ 00340 printf( "\n" ); \ 00341 flag_error(); \ 00342 } 00343 00344 void check_equal( int A, int B, const char* sA, const char* sB, int line, const char* file ) 00345 { EQUAL_TEST_IMPL( A == B, d ) } 00346 00347 void check_equal( unsigned A, unsigned B, const char* sA, const char* sB, int line, const char* file ) 00348 { EQUAL_TEST_IMPL( A == B, u ) } 00349 00350 void check_equal( long A, long B, const char* sA, const char* sB, int line, const char* file ) 00351 { EQUAL_TEST_IMPL( A == B, ld ) } 00352 00353 void check_equal( unsigned long A, unsigned long B, const char* sA, const char* sB, int line, const char* file ) 00354 { EQUAL_TEST_IMPL( A == B, lu ) } 00355 00356 void check_equal( void* A, void* B, const char* sA, const char* sB, int line, const char* file ) 00357 { EQUAL_TEST_IMPL( A == B, p ) } 00358 00359 void check_equal( const char* A, const char* B, const char* sA, const char* sB, int line, const char* file ) 00360 { EQUAL_TEST_IMPL( !strcmp((A),(B)), s ) } 00361 00362 void check_equal( const std::string& A, const std::string& B, const char* sA, const char* sB, int line, const char* file ) 00363 { check_equal( A.c_str(), B.c_str(), sA, sB, line, file); } 00364 00365 void check_equal( float A, float B, float eps, const char* sA, const char* sB, int line, const char* file ) 00366 { EQUAL_TEST_IMPL( fabsf(A - B) <= eps, f ) } 00367 00368 void check_equal( double A, double B, float eps, const char* sA, const char* sB, int line, const char* file ) 00369 { EQUAL_TEST_IMPL( fabs(A - B) <= eps, f ) } 00370 00371 void check_true( bool cond, const char* str, int line, const char* file ) 00372 { 00373 if( !cond ) { 00374 printf( "Test Failed: %s\n", str ); 00375 printf( " at line %d of '%s'\n", line, file ); 00376 printf( "\n" ); 00377 flag_error(); 00378 } 00379 } 00380 00381 #ifdef __cplusplus 00382 00383 template <typename T> 00384 void check_array_equal( const T* A, size_t A_size, 00385 const T* B, size_t B_size, 00386 const char* sA, const char* sB, 00387 int line, const char* file ) 00388 { 00389 size_t i = 0; 00390 for (;;) { 00391 if (i == A_size && i == B_size) 00392 return; // equal 00393 else if (i == A_size || i == B_size) 00394 break; // differene lengths 00395 else if (A[i] != B[i]) 00396 break; 00397 ++i; 00398 } 00399 00400 std::cout << "Equality Test Failed: " << sA << " == " << sB << std::endl; 00401 std::cout << " at line " << line << " of '" << file << "'" << std::endl; 00402 std::cout << " Vectors differ at position " << i << std::endl; 00403 00404 // print at most 10 values, roughly centered on the unequal one 00405 size_t count = 10, num_front_values = std::min(count/2,i); 00406 size_t max_len = std::max(A_size,B_size); 00407 if (i + count - num_front_values > max_len) { 00408 if (count > max_len) { 00409 num_front_values = i; 00410 count = max_len; 00411 } 00412 else { 00413 num_front_values = count - (max_len - i); 00414 } 00415 } 00416 00417 std::cout << " Expected: "; 00418 if (!A_size) { 00419 std::cout << "(empty)" << std::endl; 00420 } 00421 else { 00422 size_t j = i - num_front_values; 00423 size_t end = std::min(j + count, A_size); 00424 if (j) 00425 std::cout << "... "; 00426 for (; j < end; ++j) { 00427 if (j == i) 00428 std::cout << '>' << A[j] << "< "; 00429 else 00430 std::cout << A[j] << " "; 00431 } 00432 if (end != A_size) 00433 std::cout << "..."; 00434 std::cout << std::endl; 00435 } 00436 00437 std::cout << " Actual: "; 00438 if (!B_size) { 00439 std::cout << "(empty)" << std::endl; 00440 } 00441 else { 00442 size_t j = i - num_front_values; 00443 size_t end = std::min(j + count, B_size); 00444 if (j) 00445 std::cout << "... "; 00446 for (; j < end; ++j) { 00447 if (j == i) 00448 std::cout << '>' << B[j] << "< "; 00449 else 00450 std::cout << B[j] << " "; 00451 } 00452 if (end != B_size) 00453 std::cout << ", ..."; 00454 std::cout << std::endl; 00455 } 00456 00457 flag_error(); 00458 } 00459 00460 00461 template <typename T> 00462 void check_equal( const std::vector<T>& A, const std::vector<T>& B, 00463 const char* sA, const char* sB, 00464 int line, const char* file ) 00465 { 00466 check_array_equal( &A[0], A.size(), &B[0], B.size(), sA, sB, line, file ); 00467 } 00468 00469 #endif /* ifdef __cplusplus */ 00470 00471 #endif