lasso
TestUtil.hpp
Go to the documentation of this file.
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
 All Classes Files Functions Variables Typedefs Enumerations Enumerator Friends Defines