#!/usr/bin/perl
#
#  This is a perl script to execute a single test driver program.  The script
#  will examine the return value of the test driver and capture STDOUT, STDERR
#  to files.  If the return value of the test driver is not zero, the test is
#  deemed a failure.  STDOUT and STDERR files will be place in a subdirectory
#  named temp and the files will be compared with verified STDOUT, STDERR files
#  in a subdirectory named verified.  If there are no STDOUT, STDERR files in 
#  the verified directory, the captured STDOUT, STDERR files will be scanned
#  for words which indicate a failure.
#
#  Assumptions:  A verified subdirectory with STDOUT, STDERR files exists for 
#                the test driver specified in the arguements if an exact
#                match of the streams STDOUT, STDERR is necessary.
#
#  Return values:
#                 Bit mapped values
#                 0    Test run successfull and all tests passed
#                 1    Verified directory did not exist
#                 2    Verified STDOUT file did not exist
#                 4    Verified STDERR file did not exist
#                 8    STDOUT files did not compare
#                16    STDERR files did not compare
#                32    Test driver doesn't exist or is not executable
#                64    STDOUT captured contains error strings
#               128    STDERR captured contains error strings
#               256    Test driver did not return zero
#
#  SYNOSIS:  runTest testDriverName
#
#  $Revison:  $  $Name: not supported by cvs2svn $
#  $Date: 2004-05-06 00:45:10 $
#
#  Copyright 2004 Maui High Performance Computering Center, University of Hawaii
#
################################################################################

# Initialize exit value
$exitValue = 0;

# Set up the PSLIB_ROOT environment variable if the user doesn't have it set
if ( ! $ENV{'PSLIB_ROOT'}) {
    # Use the directory directly above test
    $PSLIB_ROOT = `cd ..;pwd`;
    # Remove newline for the end of path returned
    chomp($PSLIB_ROOT);
    # Set the environment variable
    $ENV{'PSLIB_ROOT'} = $PSLIB_ROOT;
    # Display message that PSLIB_ROOT not found and set to 
    print("PSLIB_ROOT not found: set to $PSLIB_ROOT\n");
}

# Add PSLIB_ROOT/lib to LD_LIBRARY_PATH and DYLD_LIBRARY_PATH environment vars
$ENV{'LD_LIBRARY_PATH'} = "$ENV{'PSLIB_ROOT'}/lib:$ENV{'LD_LIBRARY_PATH'}";
$ENV{'DYLD_LIBRARY_PATH'} = "$ENV{'PSLIB_ROOT'}/lib:$ENV{'DYLD_LIBRARY_PATH'}";

# Get test driver name from arguement list
$testFile = $ARGV[0];

# Check if a temp directory already exists in the current work directory
if ( !( -e "temp" )) {
   # Create temp directory to store STDOUT, STDERR files during test run
   `mkdir temp`;
   # Display message of new directory created
   print("Creating temp directory\n");
}

# Check if a verified directory exists in the current work directory
if ( !( -e "verified" )) {
    # Display message that verified subdirectory doesn't exist
    print("        Verified directory doesn't exist.\n");
    # Exit script since the test cannot be run with verified files
    $exitValue = 1;
}

# Check if the test driver file exists and is executable
if ( (-e $testFile) && (-x $testFile) ) {

    # Display message the test driver is being executed
    print("--- Executing test driver: $testFile\n");

    # Invoke the test driver
    system("./$testFile 1> temp/$testFile.stdout 2> temp/$testFile.stderr");

    # Check the return value of the test driver.  A value other than 0
    # indicates failure of the test driver unless the test driver is name
    # with a leading 'a' which indicates the test driver is expecting an
    # abort condition to terminate the driver.
    if ( ( $? != 0  && ( $testFile !~ /^A/i)) || 
         ( $? == 0  && ( $testFile =~ /^A/i)) ) {

        # Display failure message with return value to user
        if ( $? != 0 && ( $testFile !~ /^A/i) ) {
            print("        Failed - Test Driver expected 0 return value (Return value $?)\n");
        } elsif ( $? == 0 && ( $testFile =~ /^A/i) ) {
            print("        Failed - Test Driver expected abort (Return value $?)\n");
        }
        $exitValue |= 256;
    } else {
  
        # Test driver succeeded.
  
        # Create filtered version of stdout and stderr
      
        # Open the STDOUT file for reading
        open(OUTFILE, "< temp/$testFile.stdout");
        # Open mod file to place filtered STDOUT
        open(MODFILE, ">temp/$testFile.stdout.mod");
        # Replace the variable date, time and host information with constants
        while( <OUTFILE> ) {
            s/\d+:\d+:\d+/ <DATE> /;
            s/\s+\d+:\d+:\d+\w/ <TIME> /;
            s/\|[\w\.]+\|/<HOST> |/;
            print MODFILE ($_);
        }
        # Close mod file
        close(MODFILE);
        # Close STDERR file
        close(OUTFILE);

        # Open the STDERR file for reading 
        open(OUTFILE, "< temp/$testFile.stderr");
        # Open mod file to place filtered STDERR
        open(MODFILE, "> temp/$testFile.stderr.mod");
        # Replace the variable date, time and host information with constants
        while( <OUTFILE> ) {
            s/\d+:\d+:\d+/ <DATE> /;
            s/\s+\d+:\d+:\d+\w/ <TIME> /;
            s/\|[\w\.]+\|/<HOST> |/;
            print MODFILE ($_);
        }
        # Close mod file
        close(MODFILE);
        # Close STDERR file
        close(OUTFILE);

        # Compare STDOUT capture with verified file
        $exitValue |= &compareStream("verified/$testFile.stdout");

        # Check exit value to determine if verified file doesn't exist
        if ( $exitValue & 2 ) {

            # STDOUT verified doesn't exist.  Search STDOUT capture
            # for strings indicating error or failure
            $exitValue |= &errorStrSearch("$testFile.stdout");
        }

        # Compare STDERR capture with verified file
        $exitValue |= &compareStream("verified/$testFile.stderr");

        # Check exit value to determine if verified file doesn't exist
        if ( $exitValue & 4 ) {

            # STDERR verified doesn't exist.  Search STDERR capture
            # for strings indicating error or failure
            $exitValue |= &errorStrSearch("$testFile.stderr");
        }
    }
} else {
    # Since test driver doesn't exist or is not executable then display 
    # message to user.
    print("        Need to specify an executable test file within directory.\n");
    
    # Exit value set to indicate test driver doesn't exist or not executable
    $exitValue |= 32;
}

# Exit for the script with exit value
# Ignore the first three bit flags in exitValue since there are not indicators
# of a failed test
if ( ($exitValue >> 3) != 0 ) {
    print("Test failed - return status = $exitValue\n\n");
} else {
    print("Test successful\n\n");
}
exit($exitValue);

################################################################################
#
#  SUBROUTINE: errorStrSearch
#
#      Description:  This subroutine will search the file specified in its
#                    parameter for error strings and if they do exists
#                    the appropriate value will be returned.
#
#      Parameter(s): fileName - input file to search for strings
#
#      Return:   0  -  No error strings found
#               64  -  Error strings found in STDOUT
#              128  -  Error strings found in STDERR
#
###############################################################################

sub errorStrSearch {
    local($fileName) = @_;
    local($returnVal) = 0;

    # Open the captured file
    open(CAPT_FILE, "<temp/$fileName");

    # Scan through all the lines of the file searching for error strings
    while ( <CAPT_FILE> ) {
        if ( m/FAIL/i || m/FAULT/i || m/ERROR/i || m/Not Found/i
                      || m/SIGNAL/i || m/NO SUCH FILE/i || m/|E|/i
                      || m/|A|/i ) {
            if ( $fileName =~ m/out/ ) {
                print("        Failed - File $fileName contains error strings.\n");
                $returnVal = 64;
            } elsif ( $fileName =~ m/err/ ) {
                print("        Failed - File $fileName contains error strings.\n");
                $returnVal = 128;
            }
            last;
        }
    }
    # Close the capture file
    close(CAPT_FILE);
    # Return the return value
    return($returnVal);
}

################################################################################
#
#  SUBROUTINE: compareStream
#
#      Description:  This subroutine will compare the captured stream file with
#                    a file in the verified directory if one exists.
#
#      Parameter(s): streamFile - input file to compare
#
#      Return:   0  -  Compare successful
#                2  -  STDOUT verified file doesn't exist
#                4  -  STDERR verified file doesn't exist
#                8  -  STDOUT verified file doesn't compare
#               16  -  STDERR verified file doesn't compare
#
###############################################################################

sub compareStream {
    local($streamFile) = @_;
    local($returnVal) = 0;
    local($tempFile) = "";

    # Check for existence of verified STD stream files
    if ( !( -e $streamFile) ) {
            
        # Display message to user that verified STDOUT file doesn't exist
        print("        File $streamFile doesn't exist.\n");
            
        # Set exit value bit 1 to indicate proper failure
        if ( $streamFile =~ /out$/ ) {
            $returnVal |= 2;
        } elsif ( $streamFile =~ /err$/ ) {
            $returnVal |= 4;
        }
    } else {

        # Verified STD stream file exists

        # Create name of the temp file to compare
        $tempFile = $streamFile; 
        $tempFile =~ s/verified/temp/;
        $tempFile = $tempFile . ".mod";
   
        # Perform difference on the STD stream files
        $diffstdout = `diff $streamFile $tempFile`;

        # Check the return value of the difference
        if ( $? != 0 ) {
   
            # Difference of STD stream files failed

            # Check for STDOUT in file name to convey appropirate return value
            if ( $streamFile =~ /out$/ ) {
               # Display message of the failure of difference to user
               print("        Failed - STDOUT difference\n$diffstdout\n");
  
               # Exit value to indicate STDOUT did not compare
               $returnVal |= 8;
            } elsif ( $streamFile =~ /err$/ ) {
               # Display message of the failure of difference to user
               print("        Failed - STDERR difference\n$diffsdout\n");

               # Exit value to indicate STDERR did not compare
               $returnVal |= 16;
            }
        }
    }
    
    # Return the result of the compare
    return($returnVal);
}

