#!/bin/sh
# run Dyninst test suite (on current platform) with optional logging, etc.

if [ "$PLATFORM" = "" ]; then
    echo "Abort: PLATFORM undefined!"
    exit;
fi

STD_F90=f90
GNU_CC=gcc
GNU_CXX=g++

# determine the platform-specific standard/native compilers
case "$PLATFORM" in
    alpha-dec-osf*)
	STD_CC=cc
	STD_CXX=cxx
	;;
    rs6000-ibm-aix*)
	STD_CC=xlc
	STD_CXX=xlC
	STD_F90=xlf90
	;;
    i386-unknown-linux*)
	# Linux doesn't have a regular/native "cc", so use PGI compilers instead
	STD_CC=pgcc
	STD_CXX=pgCC
	STD_F90=g77
	;;
    i386-unknown-nt4.0)
	# VisualC++ (actually "cl") handles C and C++, but contrive a distinction
	STD_CC=VC
	STD_CXX=VC++
	;;
    *)
	STD_CC=cc
	STD_CXX=CC
esac

FULL_TEST_LIST="1 2 3 4 5 6 7 8 9 10 11 12 13 14 15"
case "$PLATFORM" in
    i386-unknown-linux*)
	TEST_LIST="1 2 3 4 5 6 7 8 9 12 13 14 15"
	;;
    ia64*)
	TEST_LIST="1 2 3 4 5 6 7 8 12 13 14 15"
	;;
    rs6000-ibm-aix*)
	TEST_LIST="1 2 3 4 5 6 7 8 9 12 13 14 15"
	;;
    mips-sgi-irix6.*)
	TEST_LIST="1 2 3 4 6 7 8"
	;;
    alpha-dec-osf*)
	TEST_LIST="1 2 3 4 6"
	;;
    *)
	TEST_LIST=$FULL_TEST_LIST
	;;
esac

FULL_MC_LIST="$STD_CC $STD_CXX $GNU_CC $GNU_CXX $STD_F90"
case $PLATFORM in
    *alpha*)
	# GNU_CXX behaviour is still too poor to include as default
	echo "Skipping $GNU_CXX test due to its bad behavior."
	MUT_CC_LIST="$STD_CC $GNU_CC $STD_CXX $STD_F90"
	;;
    *irix*)
	# STD_CXX&GNU_CXX behaviour is still too poor to include as default
	echo "Skipping $STD_CXX & $GNU_CXX tests due to their bad behavior!"
	MUT_CC_LIST="$STD_CC $GNU_CC"
	;;
    X-i386*solaris*)
	# STD_CXX behaviour is still too poor to include as default
	echo "Skipping STD_CXX=$STD_CXX tests due to their bad behavior!"
	MUT_CC_LIST="$STD_CC $GNU_CC $GNU_CXX"
	;;
    *)
	MUT_CC_LIST=$FULL_MC_LIST
	;;
esac

USAGE="usage: $0 [-help] [-n] [-i] [-l [logfile]] [-t ($FULL_TEST_LIST)] [-c ($FULL_MC_LIST)]\n\
Runs dyninst test suite (appropriately selected/defined for current platform)\n\
  -help: this usage information\n\
  -n: skips running actual tests\n\
  -i: run subtests individually (rather than as a complete suite)\n\
  -l: performs logging (to logfile if specified)\n\
  -t: select specified test from current test list: $FULL_TEST_LIST\n\
  -c: select specified mutatee compiler from list: $FULL_MC_LIST\n\
"

# Canonical locations
if [ "$PARADYN_BASE" = "" ]; then
    BASE_DIR=$DYNINST_ROOT
    TESTSDIR=$BASE_DIR/core/dyninstAPI/tests/$PLATFORM
else
    BASE_DIR=$PARADYN_BASE
    TESTSDIR=$BASE_DIR/$PLATFORM/bin/testprogs
fi

PARADYN_LIB_API=$BASE_DIR/$PLATFORM/lib
PARADYN_LIB_RTL=$BASE_DIR/$PLATFORM/lib


if [ "$PDTST" = "" ]; then
    TLOG_DIR=$BASE_DIR/log/tests
else
    TLOG_DIR=$PDTST
fi

CWD=`pwd | sed -e 's/\/afs\/cs.wisc.edu//'`
DIR0=`basename $CWD`
DIR1=`dirname $CWD`
DIR2=`basename $DIR1`

if [ "$DIR0" = "testprogs" ]; then
    TESTSDIR=$CWD
    # navigate from $PLATFORM/bin/testprogs
    DIR1=`dirname $DIR1`
    DIR1=`dirname $DIR1`
    PARADYN_LIB_API=$DIR1/$PLATFORM/lib
    PARADYN_LIB_RTL=$DIR1/$PLATFORM/lib
fi
if [ "$DIR2" = "tests" ]; then
    TESTSDIR=$CWD
    # navigate from core/dyninstAPI/tests/$PLATFORM
    DIR1=`dirname $DIR1`
    DIR1=`dirname $DIR1`
    DIR1=`dirname $DIR1`
    PARADYN_LIB_API=$DIR1/core/dyninstAPI/$PLATFORM:$DIR1/$PLATFORM/lib
    PARADYN_LIB_RTL=$DIR1/core/dyninstAPI_RT/$PLATFORM
fi

case "$PLATFORM" in
    rs6000-ibm-aix*)
	# no dynamic libraries supported yet!
	;;
    i386-unknown-nt4.0)
	# no dynamic loading of libdyninstAPI yet!
	DYNINSTAPI_RT_LIB=${PARADYN_LIB_RTL}/libdyninstAPI_RT.dll
	export DYNINSTAPI_RT_LIB
	;;
    mips-sgi-irix6.*)
	LD_LIBRARY64_PATH=${PARADYN_LIB_API}:${LD_LIBRARY64_PATH}
	DYNINSTAPI_RT_LIB=${PARADYN_LIB_RTL}/libdyninstAPI_RT.so.1
	export LD_LIBRARY64_PATH DYNINSTAPI_RT_LIB
	;;
    *)
	LD_LIBRARY_PATH=${PARADYN_LIB_API}:${LD_LIBRARY_PATH}
	DYNINSTAPI_RT_LIB=${PARADYN_LIB_RTL}/libdyninstAPI_RT.so.1
	export LD_LIBRARY_PATH DYNINSTAPI_RT_LIB
	;;
esac

case "$PLATFORM" in
    rs6000-ibm-aix*)
	# no dynamic libraries supported yet!
	;;
    *)
	if [ -n "$DYNINSTAPI_RT_LIB" -a ! -r "$DYNINSTAPI_RT_LIB" ]; then
	    echo DYNINSTAPI_RT_LIB=$DYNINSTAPI_RT_LIB
	    echo "Abort: file is not readable or does not exist!"
	    exit
	fi
esac

PDSCRDIR=$BASE_DIR/scripts
BUILDNUM=$PDSCRDIR/buildnum
TERMNULL=/dev/null
LOGGING=

while [ ! -z "$1" ]; do
    case "$1" in
	-h|-help)
	    BAILOUT=1
	    break
	    ;;
	-l)
	    echo "Tests logging..."
	    LOGGING=1
	    case "$2" in
		"") #echo "Null logfile name"
		    ;;
		-*) #echo "Invalid logfile name: $2"
		    ;;
		*)  #echo "Logfile name: $2"
		    FILE=$2
		    shift
	    esac
	    ;;
	-n)
	    echo "Skipping actual tests..."
	    SKIPTESTS=1
	    ;;
	-i)
	    echo "Running (sub)tests individually..."
	    INDITESTS=1
	    ;;
	-t)
	    #echo "Test selection..."
	    case "$2" in
		[1-9])
		    echo "Selected test$2"
		    USER_TEST_LIST="$USER_TEST_LIST $2"
		    shift
		    ;;
		[1-9][0-9]*)
		    echo "Selected test$2"
		    USER_TEST_LIST="$USER_TEST_LIST $2"
		    shift
		    ;;
		*)
		    echo "Invalid test selection: $2"
		    BAILOUT=1
		    break
	    esac
	    ;;
	-c)
	    #echo "Mutatee compiler selection..."
	    case "$2" in
		$STD_CC|$STD_CXX|$GNU_CC|$GNU_CXX)
		    echo "Selected mutatee compiler $2"
		    USER_MUT_LIST="$USER_MUT_LIST $2 "
		    shift
		    ;;
		*)
		    echo "Invalid mutatee compiler selection: $2"
		    BAILOUT=1
		    break
	    esac
	    ;;
	-x)
	    echo "Skipping extra tests (and bells & whistles)..."
	    EXTRA_LEAN=1
	    ;;
	-*)
	    echo "Unrecognized flag: $1"
	    BAILOUT=1
	    break
	    ;;
	*)
	    echo "Unexpected argument: $1"
	    BAILOUT=1
	    break
	    ;;
    esac
    shift
done

# bail-point for unrecognized flags/selections
if [ -n "$BAILOUT" ]; then
    printf "$USAGE"
    exit 1
fi

if [ -n "$LOGGING" ]; then
    if [ -n "$FILE" ]; then
	# Use specified filename for log
	TESTSLOG=$FILE
    else
	# Get a build identifier for log file in default directory
	if [ -n "$PARADYN_BASE" -a -f "$BUILDNUM" ]; then
	    BUILD_ID=`$BUILDNUM`
	else
	    BUILD_ID=`date '+%Y-%m-%d'`
	fi

	TESTSLOG=$TLOG_DIR/$PLATFORM/$BUILD_ID
    fi
    echo "   ... output to $TESTSLOG"
    TESTSLOGDIR=`dirname $TESTSLOG`
    if [ ! -d "$TESTSLOGDIR" ]; then
	echo "$TESTSLOGDIR does not exist (yet)!"
	mkdir -p $TESTSLOGDIR
	if [ ! -d "$TESTSLOGDIR" ]; then
	    echo "$TESTSLOGDIR creation failed - aborting!"
	    exit
	else
	    echo "$TESTSLOGDIR created for test logs!"
	fi
    fi
    if [ -f "$TESTSLOG" ]; then
	echo "File exists!"
    else
	touch $TESTSLOG
    fi
    if [ -f "$TESTSLOG".gz ]; then
	echo "File.gz exists!"
    fi
else
    TESTSLOG=$TERMNULL
fi

# Sort out the test and mutatee lists
if [ -n "$USER_TEST_LIST" ]; then
    TEST_LIST=$USER_TEST_LIST
fi

if [ -n "$USER_MUT_LIST" ]; then
    MUT_CC_LIST=$USER_MUT_LIST
fi

# WindowsNT executables have ".exe" extensions
if [ $PLATFORM = "i386-unknown-nt4.0" ]; then
  EXT=.exe
else
  EXT=
fi

# Some systems (currently only Irix) support multiple ABIs
ABILIST="."

# Hijack PATH and LD_LIBRARY_PATH to ensure that we have the "old" mutatees and libs
# (some of our testing env's specify the new testdirs)
PATH=$TESTDIR:$PATH
LD_LIBRARY_PATH=$TESTDIR:$LD_LIBRARY_PATH
LIBPATH=$LD_LIBRARY_PATH

# Go to it!
cd $TESTSDIR
CWD=`pwd | sed -e 's/\/afs\/cs.wisc.edu//'`

echo ""                                                   2>&1 | $PDSCRDIR/uniq.pl | tee -a $TESTSLOG
echo "Commencing DyninstAPI test(s) $TEST_LIST ..."       2>&1 | $PDSCRDIR/uniq.pl | tee -a $TESTSLOG
date                                                      2>&1 | $PDSCRDIR/uniq.pl | tee -a $TESTSLOG
uname -a                                                  2>&1 | $PDSCRDIR/uniq.pl | tee -a $TESTSLOG
echo "TESTSDIR=$TESTSDIR"                                 2>&1 | $PDSCRDIR/uniq.pl | tee -a $TESTSLOG

if [ ! -n "$EXTRA_LEAN" ]; then
    case "$PLATFORM" in
	rs6000-ibm-aix*)
	    # no dynamic libraries supported yet!
	    ;;
	mips-sgi-irix6.*)
	    ABILIST=". n32"
	    echo "LD_LIBRARY64_PATH=$LD_LIBRARY64_PATH"   2>&1 | $PDSCRDIR/uniq.pl | tee -a $TESTSLOG
	    ;;
	*)
	    echo "LD_LIBRARY_PATH=$LD_LIBRARY_PATH"       2>&1 | $PDSCRDIR/uniq.pl | tee -a $TESTSLOG
	    ;;
    esac
    case "$PLATFORM" in
	rs6000-ibm-aix*)
	    # No dynamic libraries supported yet!
	    ;;
	*)
	    echo "DYNINSTAPI_RT_LIB=$DYNINSTAPI_RT_LIB"   2>&1 | $PDSCRDIR/uniq.pl | tee -a $TESTSLOG
	    $PDSCRDIR/ident_PD $DYNINSTAPI_RT_LIB         2>&1 | $PDSCRDIR/uniq.pl | tee -a $TESTSLOG
	    ;;
    esac
fi

# The corefile preservation feature is useless unless we run the nightly
# scripts with debugging information.  Disabling for now.

# Date string for 7 days ago.
#OLDCORE=`perl -e '$offset=7*(60*60*24);' \
#	      -e '@d=localtime(time - $offset);' \
#	      -e 'printf("%d-%02d-%02d", $d[5]+1900, $d[4]+1, $d[3]);'`
#JUNKFILES="imagefile test?.out.* _dyninstsaved* *core.${OLDCORE}*"
JUNKFILES="imagefile test?.out.* _dyninstsaved* core core.*"

JunkCheck ()
{
#    TEST_ID=test${TESTNUM}.core.`date '+%Y-%m-%d'`
    # Special for core files.
    # Keep them around for later debugging.
#    for COREFILE in core*
#    do
#	if [ -f ${COREFILE} ]; then
#	    UNIQ_ID=1
#	    while [ -f ${TEST_ID}.${UNIQ_ID} ]; do
#		UNIQ_ID=`expr ${UNIQ_ID} + 1`
#	    done
#	    echo "Saving ${COREFILE} as ${TEST_ID}.${UNIQ_ID} for later debugging."
#	    /bin/mv ${COREFILE} ${TEST_ID}.${UNIQ_ID}
#	fi
#    done

    for JUNK in $JUNKFILES
    do
        if [ -f $JUNK ]; then
            printf "Deleting test junk: "
            /bin/ls -l $JUNK
            /bin/rm -f $JUNK
        fi

	if [ -d $JUNK ]; then
	    echo "Deleting junk directory $JUNK"
	    /bin/rm -rf $JUNK
	fi
    done
}

RunTest ()
{
    echo \"$TEST\"
    if [ ! "$SKIPTESTS" ]; then
        $PDSCRDIR/timer.pl -t 1200 ./$TEST -V
        EXITCODE=$?
        if [ $EXITCODE -ne 0 ]; then
            printf "=========================================================\n"
            printf "=== Exit code 0x%02x: %s\n" $EXITCODE "$TEST"
            printf "=========================================================\n"
#       else
#           printf "=== Exit code 0x%02x: %s\n" $EXITCODE "$TEST"
        fi
        JunkCheck
        $PDSCRDIR/reap -a -q test$TESTNUM
        echo ""                                       
    fi
}

RunTestIndi ()
{
    # the number of subtests should be acquired by running "test? -usage"
    case $TESTNUM in
	1)
	    SUBTESTS=34 ;;
	2)
	    SUBTESTS=13 ;;
	3)
	    SUBTESTS=5 ;;
	4)
	    SUBTESTS=4 ;;
	5)
	    SUBTESTS=12 ;;
	6)
	    SUBTESTS=6 ;;
	7)
	    SUBTESTS=9 ;;
	8)
	    SUBTESTS=2 ;;
	9)
	    SUBTESTS=6 ;;
	10)
	    SUBTESTS=4 ;;
	11)
	    SUBTESTS=8 ;;
	12)
	    SUBTESTS=4 ;;
	*)
	    printf "Unexpected TESTNUM %d\n" $TESTNUM
    esac
    printf "Individual subtests for %s (%d)\n" $MUTATEE $SUBTESTS 

    TESTSTUB=$TEST
    n=1
    while [ $n -le $SUBTESTS ]
    do
	TEST="$TESTSTUB -run $n"
	RunTest
	n=`expr $n + 1`
    done
}

RUNAWAYS="'test[1-9][0-9]*'"
$PDSCRDIR/reap -a -q $RUNAWAYS                            2>&1 | $PDSCRDIR/uniq.pl | tee -a $TESTSLOG

JunkCheck                                                 2>&1 | $PDSCRDIR/uniq.pl | tee -a $TESTSLOG

# architecture
ARCH=`echo $PLATFORM | cut -f1 -d'-'`

for TESTNUM in $TEST_LIST
do
    if [ $TESTNUM = 11 ]; then
	if [ $ARCH = "sparc" ]; then
	    # Test11 is a special case.  Simply running it
	    # produces the correct output.
	    ($PDSCRDIR/timer.pl -t 10800 test11)          2>&1 | $PDSCRDIR/uniq.pl | tee -a $TESTSLOG
	fi
	continue
    fi

    printf "\n*** dyninstAPI test$TESTNUM...\n"           2>&1 | $PDSCRDIR/uniq.pl | tee -a $TESTSLOG
    if [ ! -n "$EXTRA_LEAN" ]; then
	$PDSCRDIR/ident_PD test$TESTNUM$EXT               2>&1 | $PDSCRDIR/uniq.pl | tee -a $TESTSLOG
	$PDSCRDIR/ldd_PD test$TESTNUM$EXT                 2>&1 | $PDSCRDIR/uniq.pl | tee -a $TESTSLOG
    fi

    if [ $TESTNUM = 10 -a $ARCH != "sparc" ]; then
	continue
    fi

    for ABI in $ABILIST
    do
	if [ $ABI = "." ]; then
	    FLAGS=""; ABIX=""
	else
	    FLAGS="-$ABI"; ABIX="_$ABI"
	    printf "\n[Test series with ABI=$ABI]\n"      2>&1 | $PDSCRDIR/uniq.pl | tee -a $TESTSLOG
	fi

	if [ $TESTNUM = 9 ]; then
	    FLAGS="$FLAGS -rmdirs"
	fi

	for MUT_CC in $MUT_CC_LIST
	do
	    if [ $TESTNUM = 4 ]; then
		TESTNUMOPT="a"
	    else
		TESTNUMOPT=""
	    fi
	    if [ $TESTNUM = 5 -a \( $MUT_CC = $STD_CC -o $MUT_CC = $GNU_CC \) ]; then
		# Only C++ tests for these
		continue
	    fi

	    MUTATEE="test$TESTNUM$TESTNUMOPT.mutatee_$MUT_CC$ABIX$EXT"
	    printf "\n[Tests with $MUTATEE]\n"                2>&1 | $PDSCRDIR/uniq.pl | tee -a $TESTSLOG
	    if [ ! -x $MUTATEE ]; then
		printf "\n[$MUTATEE unavailable for tests]\n" 2>&1 | $PDSCRDIR/uniq.pl | tee -a $TESTSLOG
		continue
	    fi
	    if [ ! -n "$EXTRA_LEAN" ]; then
		for MUTATEX in test$TESTNUM.mutatee_$MUT_CC$ABIX$EXT test${TESTNUM}[ab].mutatee_$MUT_CC$ABIX$EXT
		do
		    if [ -x $MUTATEX ]; then
			ls -lLF $MUTATEX                          2>&1 | $PDSCRDIR/uniq.pl | tee -a $TESTSLOG
			$PDSCRDIR/ldd_PD $MUTATEX                 2>&1 | $PDSCRDIR/uniq.pl | tee -a $TESTSLOG
			$PDSCRDIR/timer.pl -t 120 ./$MUTATEX      2>&1 | $PDSCRDIR/uniq.pl | tee -a $TESTSLOG
		    fi
		done
	    fi
	    echo ""                                           2>&1 | $PDSCRDIR/uniq.pl | tee -a $TESTSLOG
	    TEST="test$TESTNUM $FLAGS -mutatee $MUTATEE"
	    if [ -n "$INDITESTS" ]; then
		RunTestIndi                                   2>&1 | $PDSCRDIR/uniq.pl | tee -a $TESTSLOG
	    else
		RunTest                                       2>&1 | $PDSCRDIR/uniq.pl | tee -a $TESTSLOG
	    fi

	    if [ -n "$EXTRA_LEAN" ]; then
		continue
	    fi

	    #
	    # Attach Test Cases
	    #
	    if [ $TESTNUM = 1 -o $TESTNUM = 2 ]; then
		# Only use -attach with tests #1 and #2

		TEST="test$TESTNUM $FLAGS -mutatee $MUTATEE -attach"
		if [ -n "$INDITESTS" ]; then
		    RunTestIndi                               2>&1 | $PDSCRDIR/uniq.pl | tee -a $TESTSLOG
		else
		    RunTest                                   2>&1 | $PDSCRDIR/uniq.pl | tee -a $TESTSLOG
		fi
	    fi

	    #
	    # If x86 or sparc run extra test with relocation
	    #
	    if [ $ARCH = "i386" -o $ARCH = "sparc" ]; then
	    if [ $TESTNUM != 9 -a $TESTNUM != 10 -a $TESTNUM != 12 -a $TESTNUM != 13 -a $TESTNUM != 14 -a $TESTNUM != 15 ]; then
		# No -relocate tests for #9, 10, 12-15

		TEST="test$TESTNUM -relocate $FLAGS -mutatee $MUTATEE"
		if [ -n "$INDITESTS" ]; then
		    RunTestIndi                           2>&1 | $PDSCRDIR/uniq.pl | tee -a $TESTSLOG
		else
		    RunTest                               2>&1 | $PDSCRDIR/uniq.pl | tee -a $TESTSLOG
		fi
	    fi
	    fi

	done
    done
done

$PDSCRDIR/reap -a -q $RUNAWAYS                            2>&1 | $PDSCRDIR/uniq.pl | tee -a $TESTSLOG

printf "\nTests complete.\n"                              2>&1 | $PDSCRDIR/uniq.pl | tee -a $TESTSLOG
date                                                      2>&1 | $PDSCRDIR/uniq.pl | tee -a $TESTSLOG

if [ -n "$LOGGING" ]; then
    gzip $TESTSLOG
    printf "Test log %s.gz written.\n" $TESTSLOG
fi

exit 0
