Index: trunk/psModules/src/psTest.c
===================================================================
--- trunk/psModules/src/psTest.c	(revision 2126)
+++ trunk/psModules/src/psTest.c	(revision 2126)
@@ -0,0 +1,244 @@
+//
+// C Implementation: psTest
+//
+// Description:
+//
+//
+// Author: Robert DeSonia <robert.desonia@mhpcc.hpc.mil>, (C) 2004
+//
+// Copyright: See COPYING file that comes with this distribution
+//
+//
+
+
+#include <stdlib.h>
+#include <unistd.h>
+#include <sys/wait.h>
+#include <stdbool.h>
+#include <string.h>
+
+#include "psTest.h"
+#include "psMemory.h"
+#include "psError.h"
+#include "psTrace.h"
+
+#define HEADER_TOP    "/***************************** TESTPOINT ******************************************\\\n"
+#define HEADER_LINE_STRING   "* %20s: %-58s *\n"
+#define HEADER_LINE_INT      "* %20s: %-58d *\n"
+#define HEADER_BOTTOM "\\**********************************************************************************/\n\n"
+
+bool p_runTestSuite( FILE *fp, const char* testPointFile, const char* packageName,
+                     testDescription tests[], int argc, char * const argv[] )
+{
+    bool success = true;
+    bool runAll = true;
+    bool useFork = true;
+    bool found;
+    int c;
+    int n;
+    extern char *optarg;
+
+    if ( argc > 0 ) {
+        while ( ( c = getopt( argc, argv, "lhn:dt:" ) ) != -1 ) {
+            switch ( c ) {
+            case 'h':
+                printf( "Usage: %s [-l] [-d] [-h] [-n=Testpoint#] [-t=TestpointName]\n"
+                        "    where:\n"
+                        "           -l  : lists the testpoints contained in this test driver executable\n"
+                        "           -d  : turns on debugger-friendly mode (no forking, aborts/signals are not handled)\n"
+                        "           -h  : prints this help\n"
+                        "           -n  : specifies a particular testpoint by number to run\n"
+                        "           -t  : specifies a particular testpoint by name to run\n"
+                        "    (if no -l, -n or -t options are given, all testpoints are run)\n",
+                        argv[ 0 ] );
+                runAll = false;
+                break;
+            case 'd':
+                useFork = false;
+                break;
+            case 'l':
+                printf( "Test Driver:  %s\n", testPointFile );
+                printf( "Package Name: %s\n", packageName );
+                printf( "Testpoints:\n" );
+                runAll = false;
+                for ( int index = 0; tests[ index ].fcn != NULL; index++ ) {
+                    printf( "    %6d - %s \n", tests[ index ].testPointNumber,
+                            tests[ index ].testPointName );
+                }
+                printf( "\n" );
+                break;
+            case 't':
+                runAll = false;
+                for ( int index = 0; tests[ index ].fcn != NULL; index++ ) {
+                    if ( strcmp( optarg, tests[ index ].testPointName ) == 0 ) {
+                        success = p_runTest( fp,
+                                             testPointFile,
+                                             packageName,
+                                             tests[ index ].testPointName,
+                                             tests[ index ].fcn,
+                                             tests[ index ].expectedReturn,
+                                             useFork ) && success;
+                    }
+                }
+                break;
+            case 'n':
+                runAll = false;
+                if ( sscanf( optarg, "%i", &n ) != 1 ) {
+                    psError( __func__, "Failed to parse the testpoint number (%s).",
+                             optarg );
+                    break;
+                }
+                found = false;
+                for ( int index = 0; tests[ index ].fcn != NULL; index++ ) {
+                    if ( n == tests[ index ].testPointNumber ) {
+                        found = true;
+                        success = p_runTest( fp,
+                                             testPointFile,
+                                             packageName,
+                                             tests[ index ].testPointName,
+                                             tests[ index ].fcn,
+                                             tests[ index ].expectedReturn,
+                                             useFork ) && success;
+                    }
+                }
+                if ( ! found ) {
+                    psError( __func__, "The specified testpoint number (%d) doesn't exist in this test driver.",
+                             n );
+                    break;
+                }
+                break;
+            case '?':
+                psError( __func__, "Option %s is not recognized and is ignored.", optarg );
+                break;
+            }
+        }
+    }
+
+    if ( runAll ) {
+        for ( int index = 0; tests[ index ].fcn != NULL; index++ ) {
+            if ( ! tests[ index ].isDuplicateEntry ) {
+                success = p_runTest( fp,
+                                     testPointFile,
+                                     packageName,
+                                     tests[ index ].testPointName,
+                                     tests[ index ].fcn,
+                                     tests[ index ].expectedReturn,
+                                     useFork ) && success;
+            }
+        }
+    }
+
+    if ( ! success ) {
+        psError( testPointFile, "One or more tests failed" );
+    }
+
+    return success;
+}
+
+bool p_runTest( FILE *fp, const char* testPointFile, const char* packageName, const char* testPointName,
+                testFcn fcn, int expectedReturn, bool useFork )
+{
+    int childReturn = 0;
+    pid_t child;
+
+    p_printPositiveTestHeader( fp, testPointFile, packageName, testPointName );
+
+    if ( useFork ) {
+        child = fork();
+        if ( child == 0 ) {                   // I am the child process, run the test
+            int currentId = psMemGetId();
+            int retVal = fcn();
+            if ( retVal == 0 ) { // only bother checking memory if test executed to end.
+                if ( psMemCheckLeaks( currentId, NULL, stderr ) != 0 ) {
+                    psError( __func__, "Memory Leaks Detected" );
+                    retVal = 64;
+                }
+                psMemCheckCorruption( 1 );
+            }
+            exit( retVal );
+        } else
+            if ( child < 0 ) {
+                fprintf( fp, "Couldn't fork a process to run a negative test (%s|%s)",
+                         packageName, testPointName );
+                abort();
+            }
+
+        waitpid( child, &childReturn, 0 );
+        if ( WIFSIGNALED( childReturn ) ) {
+            childReturn = -WTERMSIG( childReturn );
+        } else {
+            childReturn = WEXITSTATUS( childReturn );
+        }
+    } else {
+        int currentId = psMemGetId();
+        childReturn = fcn();
+        if ( childReturn == 0 ) { // only bother checking memory if test executed to end.
+            if ( psMemCheckLeaks( currentId, NULL, stderr ) != 0 ) {
+                psError( __func__, "Memory Leaks Detected" );
+                childReturn = 64;
+            }
+            psMemCheckCorruption( 1 );
+        }
+    }
+
+
+    if ( childReturn != expectedReturn ) {
+        fprintf( fp, "Return value mismatch: expected %d, got %d",
+                 expectedReturn, childReturn );
+    }
+
+    p_printFooter( fp, testPointFile, packageName, testPointName,
+                   ( childReturn == expectedReturn ) );
+
+    return ( childReturn == expectedReturn );
+}
+
+void p_printPositiveTestHeader( FILE *fp,
+                                const char* testPointFile,
+                                const char* packageName,
+                                const char* testPointName )
+{
+    char TP[ 80 ];
+
+    snprintf( TP, 80, "%s{%s}", packageName, testPointName );
+
+    fprintf( fp, HEADER_TOP );
+    fprintf( fp, HEADER_LINE_STRING, "TestFile", testPointFile );
+    fprintf( fp, HEADER_LINE_STRING, "TestPoint", TP );
+    fprintf( fp, HEADER_LINE_STRING, "TestType", "Positive" );
+    fprintf( fp, HEADER_BOTTOM );
+}
+
+void p_printNegativeTestHeader( FILE *fp,
+                                const char* testPointFile,
+                                const char* packageName,
+                                const char* testPointName,
+                                const char* expectedError,
+                                int exitValue )
+{
+    char TP[ 80 ];
+
+    snprintf( TP, 80, "%s{%s}", packageName, testPointName );
+
+    fprintf( fp, HEADER_TOP );
+    fprintf( fp, HEADER_LINE_STRING, "TestFile", testPointFile );
+    fprintf( fp, HEADER_LINE_STRING, "TestPoint", TP );
+    fprintf( fp, HEADER_LINE_STRING, "TestType", "Negative" );
+    fprintf( fp, HEADER_LINE_STRING, "ExpectedErrorText", expectedError );
+    fprintf( fp, HEADER_LINE_INT, "ExpectedStatusValue", exitValue );
+    fprintf( fp, HEADER_BOTTOM );
+}
+
+
+void p_printFooter( FILE *fp,
+                    const char* testPointFile,
+                    const char* packageName,
+                    const char* testPointName,
+                    bool success )
+{
+    if ( success ) {
+        fprintf( fp, "\n---> TESTPOINT PASSED (%s{%s} | %s)\n\n", packageName, testPointName, testPointFile );
+    } else {
+        fprintf( fp, "\n---> TESTPOINT FAILED (%s{%s} | %s)\n\n", packageName, testPointName, testPointFile );
+    }
+}
Index: trunk/psModules/src/psTest.h
===================================================================
--- trunk/psModules/src/psTest.h	(revision 2126)
+++ trunk/psModules/src/psTest.h	(revision 2126)
@@ -0,0 +1,81 @@
+
+#ifndef PSTEST_H
+#define PSTEST_H
+
+#include <stdio.h>
+#include <stdbool.h>
+
+#define printPositiveTestHeader(filePtr, packageName, testPointName) \
+p_printPositiveTestHeader(filePtr, __FILE__, packageName, testPointName)
+
+#define printNegativeTestHeader(filePtr, packageName, testPointName, expectedError, exitValue) \
+p_printNegativeTestHeader(filePtr, __FILE__, packageName, testPointName, expectedError, exitValue)
+
+#define printFooter(filePtr, packageName, testPointName, success) \
+p_printFooter(filePtr, __FILE__, packageName, testPointName, success)
+
+typedef int (*testFcn)(void);
+
+typedef struct
+{
+    testFcn     fcn;
+    int         testPointNumber;
+    const char* testPointName;
+    int         expectedReturn;
+    bool        isDuplicateEntry;
+}
+testDescription;
+
+#define runTest(filePtr, packageName, testPointName, fcn, expectedReturn, useFork) \
+p_runTest(filePtr, __FILE__, packageName, testPointName, fcn, expectedReturn, useFork)
+
+#define runTestSuite(filePtr, packageName, tests, argc, argv) \
+p_runTestSuite(filePtr, __FILE__, packageName, tests, argc, argv)
+
+
+/////////////////////////// PRIVATE FUNCTIONS //////////////////////////////
+
+bool p_runTest(
+    FILE *fp,
+    const char* testPointFile,
+    const char* packageName,
+    const char* testPointName,
+    testFcn fcn,
+    int expectedReturn,
+    bool useFork
+);
+
+bool p_runTestSuite(
+    FILE *fp,
+    const char* testPointFile,
+    const char* packageName,
+    testDescription tests[],
+    int argc,
+    char * const argv[]
+);
+
+void p_printPositiveTestHeader(
+    FILE *fp,
+    const char* testPointFile,
+    const char* packageName,
+    const char* testPointName
+);
+
+void p_printNegativeTestHeader(
+    FILE *fp,
+    const char* testPointFile,
+    const char* packageName,
+    const char* testPointName,
+    const char* expectedError,
+    int exitValue
+);
+
+void p_printFooter(
+    FILE *fp,
+    const char* testPointFile,
+    const char* packageName,
+    const char* testPointName,
+    bool success
+);
+
+#endif
