[MOAB-dev] r1416 - MOAB/trunk

kraftche at mcs.anl.gov kraftche at mcs.anl.gov
Tue Nov 20 16:15:11 CST 2007


Author: kraftche
Date: 2007-11-20 16:15:01 -0600 (Tue, 20 Nov 2007)
New Revision: 1416

Modified:
   MOAB/trunk/TestUtil.hpp
Log:
clean up, document, add longjmp-based test running mode

Modified: MOAB/trunk/TestUtil.hpp
===================================================================
--- MOAB/trunk/TestUtil.hpp	2007-11-20 08:55:48 UTC (rev 1415)
+++ MOAB/trunk/TestUtil.hpp	2007-11-20 22:15:01 UTC (rev 1416)
@@ -1,10 +1,12 @@
 #ifndef TEST_UTIL_HPP
 #define TEST_UTIL_HPP
 
-#define NOFORK
+/* How to use this test suite utility:
+ * 1) Write tests that use the CHECK and CHECK_* macros defined below to assert test conditions.
+ * 2) Write a main routine that invokes each test through the RUN_TEST macro
+ * 3) RUN_TEST evaluates to 1 if test failed, zero otherwize.  Count failures and print summary.
+ */
 
-#include <math.h>
-
 /** Check that A is MB_SUCCESS */
 #define CHECK_ERR( A )                    check_equal( MB_SUCCESS, (A), "MB_SUCCESS", #A, __LINE__, __FILE__ )
 /**  Ensure that A is true */
@@ -18,21 +20,143 @@
  */
 #define RUN_TEST( FUNC )           run_test( &FUNC, #FUNC )
 
+
+// Use C++ exceptions to return error state to test runner
+// Portable, but whole test suite stops if any test segfaults, asserts, etc.
+#define EXCEPTION_MODE 1   
+
+// Test runner forks separate process for each test.
+// Difficult to debug tests (with debugger).  Not portable to Windows.  
+// Very robust (no test can distrub test running code)
+#define FORK_MODE 2
+
+// Use signal handler and long jumps to return error state to test runner.
+// Might be portable to Windows (not sure).  Possibly undefined behavior (e.g. continuing 
+// with next test after catching segfault is technically undefined behavior.)
+#define LONGJMP_MODE 3      
+
+// If test application hasn't set MODE, set to default
+#ifndef MODE
+#  ifdef _MSC_VER
+#    define MODE EXCEPTION_MODE
+#  else
+#    define MODE LONGJMP_MODE
+#  endif
+#endif
+
+
+/***************************************************************************************
+ * NOTE: The remainder of this file contains the implementation of the above macros.
+ *       The above macros constitute the entire intended API.
+ ***************************************************************************************/
+
+#include <math.h>
 #include <stdio.h>
 #include <stdlib.h>
 
-#if defined(_MSC_VER) || defined(NOFORK)
+#if MODE == EXCEPTION_MODE
    struct ErrorExcept{};
 #  define FLAG_ERROR throw ErrorExcept()
-#else
+#elif MODE == FORK_MODE
 #  include <sys/types.h>
 #  include <sys/wait.h>
 #  include <unistd.h>
 #  include <errno.h>
 #  define FLAG_ERROR exit(1)
+#elif MODE == LONGJMP_MODE
+#  include <signal.h>
+#  include <setjmp.h>
+#  ifdef SIGUSR2
+#    define FLAG_ERROR raise(SIGUSR2)
+#  else
+#    define FLAG_ERROR abort()
+#  endif
+#else
+#  error "MODE not set"
 #endif
 
+#if MODE == LONGJMP_MODE
 
+jmp_buf jmpenv;
+extern "C" {
+  void sighandler( int sig ) {
+    signal( sig, sighandler );
+    longjmp(jmpenv, sig);
+    // should never return from longjmp
+    exit(1);
+  }
+  typedef void (*sigfunc_t)(int);
+} // extern "C"
+int sethandler( int sig ) {
+  sigfunc_t h = signal( sig, &sighandler );
+  if (h == SIG_ERR)
+    return  1;
+  else if (h != SIG_DFL)
+    signal( sig, h );
+  return 0;
+}
+
+int init_signal_handlers()
+{
+  int result = 0;
+#ifdef SIGHUP
+  result += sethandler( SIGHUP );
+#endif
+#ifdef SIGINT
+  result += sethandler( SIGINT );
+#endif
+#ifdef SIGQUIT
+  result += sethandler( SIGQUIT );
+#endif
+#ifdef SIGILL
+  result += sethandler( SIGILL );
+#endif
+#ifdef SIGTRAP
+  result += sethandler( SIGTRAP );
+#endif
+#ifdef SIGABRT
+  result += sethandler( SIGABRT );
+#endif
+#ifdef SIGBUS
+  result += sethandler( SIGBUS );
+#endif
+#ifdef SIGFPE
+  result += sethandler( SIGFPE );
+#endif
+#ifdef SIGUSR1
+  result += sethandler( SIGUSR1 );
+#endif
+#ifdef SIGSEGV
+  result += sethandler( SIGSEGV );
+#endif
+#ifdef SIGUSR2
+  result += sethandler( SIGUSR2 );
+#endif
+#ifdef SIGPIPE
+  result += sethandler( SIGPIPE );
+#endif
+#ifdef SIGTERM
+  result += sethandler( SIGTERM );
+#endif
+#ifdef SIGCHLD
+  result += sethandler( SIGCHLD );
+#endif
+#ifdef SIGIO
+  result += sethandler( SIGIO );
+#endif
+#ifdef SIGSYS
+  result += sethandler( SIGSYS );
+#endif
+  return result;
+}
+
+// initialize global to force call to init_signal_handlers
+int junk_init_var = init_signal_handlers();
+
+#endif // LONGJMP_MODE
+
+
+
 /* Make sure IS_BUILDING_MB is defined so we can include MBInternals.hpp */
 #include "MBTypes.h"
 #ifndef IS_BUILDING_MB
@@ -48,7 +172,7 @@
 {
   printf("Running %s ...\n", func_name );
   
-#if defined(_MSC_VER) || defined(NOFORK) 
+#if MODE == EXCEPTION_MODE
   /* On Windows, run all tests in same process.
      Flag errors by throwing an exception.
    */
@@ -65,7 +189,7 @@
     return 1;
   }
     
-#else
+#elif MODE == FORK_MODE
     /* For non-Windows OSs, fork() and run test in child process. */
   pid_t pid = fork();
   int status;
@@ -102,7 +226,26 @@
   else {
     return 0;
   }
+  
+#elif MODE == LONGJMP_MODE
+  int sig = setjmp( jmpenv );
+  if (!sig) {
+    (*test)();
+    return 0;
+  }
+#ifdef SIGUSR2
+  else if(sig == SIGUSR2) {
+    printf( "  %s: FAILED\n", func_name );
+    return 1;
+  }
 #endif
+  else {
+    printf( "  %s: TERMINATED (signal %d)\n", func_name, sig );
+    return 1;
+  }
+#else
+  #error "MODE not set"
+#endif // MODE
 }
 
 




More information about the moab-dev mailing list