#!/bin/bash
#
# Copyright (C) 2005-2006 Heiko Appel
#
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation; either version 2, or (at your option)
# any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
# 02110-1301, USA.
#


# Paths.
prefix=/opt/local
# we do not care about datarootdir, but without it we get a warning from configure.
# NOTE: datarootdir line must precede pkgdatadir since ${datarootdir} may be substituted as ${datarootdir}
datarootdir=${prefix}/share
pkgdatadir=${datarootdir}/ape
testsuite="$pkgdatadir/testsuite"

# Architecture.
arch=`echo "$MACHTYPE" | awk -F- '{print $1}'`

# Failure reporting.
failed_tests=0
skipped_tests=0
passed_tests=0
total_tests=0
failure_report=""


# Usage.
function usage() {
    cat <<EOF

 Copyright (C) 2005-2007 by Heiko Appel, M. Oliveira, and F. Nogueira

Usage: ape-run_testsuite [options]
    
     -h            this message
     -n            dry run mode (show what would be executed)
     -g LIST       comma separated list of test groups to run
     -q            query testfiles for the given groups (no tests are run)
     -d DIR        directory where to look for the testsuite
     -l            local run
     -e SUFFIX     exec suffix for ape executable
     -p PREFIX     installation prefix
     -c            delete all .log files and work directories after the run
     -m ADDRESS    mail report to address
     -u            update reference values
     -t            update tolerance values

Report bugs to <micael@teor.fis.uc.pt>.
EOF
 exit 0;
}


# Dry run...
function CMD {
    [ "$dry_run" -o "$verbose" ] && echo -e "$@";
    [ ! "$dry_run" ] && eval "$@";
}


# Find tests to run. Takes as argument the string passed to the
# -g command line option.
function find_tests() {
    groups="$1"
    if [ -n "$groups" ]; then
	groups_pat=`echo "$groups" | sed 's/ *, */|/'`
	groups_pat="^TestGroups *:.*($groups_pat)"
    else # No groups given defaults to all tests.
	groups_pat="."
    fi
    testfiles=`find $testsuite -name "*.test" | \
	xargs /usr/bin/grep -E "$groups_pat" | \
	awk -F: '{print $1}' | sort -u`
    echo "$testfiles"
}


# Run all tests. Takes as first argument a list of testfile names.
function run_testsuite() {

tests="$1"

# Check for preserve working directories flag.
if [ "$cleanup" == "yes" ]; then
    preserve_opt=""
else
    preserve_opt="-p"
fi

for y in $tests; do
    total_tests=$((total_tests + 1))
    ybase=`basename $y`
    xybase=${ybase%.test}
    if [ "${local_run}" == "yes" ]; then
	bin_directory=`pwd`/../src
	runtest_directory=$testsuite
    else
	bin_directory=$prefix/bin
	runtest_directory=$bin_directory
    fi
    if [ -n "${exec_suffix}" ]; then
	suffix_opt="-s ${exec_suffix}"
    else
	suffix_opt=""
    fi
    if [ -d "${bin_directory}" ]; then
	CMD $runtest_directory/ape-run_regression_test.pl -l \
	    $preserve_opt $suffix_opt -D $bin_directory -f $y $ref_update $tol_update | \
	    tee ${xybase}.log
	# Look for failed/passed/skipped testcases and add
	# to failure summary.
	failures=${PIPESTATUS[0]}
	if [ "${failures}" -eq 0 ]; then
	    passed_tests=$((passed_tests + 1))
	elif [ ${failures} -eq 255 ]; then
	    skipped_tests=$((skipped_tests + 1))
	else
	    failed_tests=$((failed_tests + 1))
	    test_name=`echo $y | sed "s|$testsuite/||"`
	    name_length=`echo -n $test_name | wc -m`
	    space_length=$((50 - name_length))
	    spaces=`for((i = 1; i <= space_length; i++)); do echo -n ' '; done`
	    failure_report="$failure_report    $test_name$spaces$failures\n"
	fi
    fi
    [ -e out.log ] && mv out.log ${xybase}.out.log
done
}


# Send report via mail.
# Arguments:
# $1 : list of testfile names that have been run,
# $2 : e-mail address to send report to.
function mail_report() {

tests="$1"
datestamp=$(date +"%Y-%m-%d")

for y in $tests; do
    ybase=`basename $y`
    xybase=${ybase%.test}
    failed_tests=$(grep FAIL ${xybase}.log | wc -l) 
    echo "Checking for failed tests: ${xybase}.log"
    if [ $failed_tests -gt 0 ]; then
	echo "Found: $failed_tests"
	echo "Mailing report to: $mailaddr"
	cat ape-header ${xybase}.log ${xybase}.out.log | \
	    mutt -s "[ape-run_testsuite on $arch] daily report - $datestamp" $mailaddr
    fi
done
}


# Show usage info if no args at all.
[ "$#" -eq 0 ] && usage;


# Parse command line.

# Some defaults settings.
query="no"
send_mail="no"
cleanup="no"
test_groups=""
ref_update=""
tol_update=""

while getopts "hnp:e:lg:qm:d:cut" opt ; do
    case "$opt" in
        h) usage;;
        n) echo="echo"; dry_run="yes";; 
        p) prefix="$OPTARG"; testsuite=$prefix/share/ape/testsuite;;
        e) exec_suffix="$OPTARG";;
        l) local_run="yes";;
	g) test_groups="$OPTARG";;
	q) query="yes";;
        m) mailaddr="$OPTARG"; send_mail="yes";;
	d) directory="$OPTARG";;
	c) cleanup="yes";;
	u) ref_update="-u";;
	t) tol_update="-t";;
        ?) echo "Error parsing arguments"; exit 1;;
    esac
done
shift $[ OPTIND - 1 ]


# Find testfiles.
if [ -n "$directory" ]; then
    testsuite="$directory"
else
    [ "$local_run" == "yes" ] && testsuite=$(pwd)
fi

testfiles=`find_tests "$test_groups"`


# Query mode? If so, list files and exit.
if [ "$query" == "yes" ]; then
    echo "Testfiles for groups $test_groups:"
    echo ""
    for f in $testfiles; do
	echo ${f##$testsuite/}
    done
    exit 0
fi


# No testfiles found, abort.
if [ -z "$testfiles" ]; then
    echo "No testfiles for group(s) $test_groups found."
    # This is also mailed, if -m is present (this is to prevent
    # errorneous cron-jobs and the like).
    if [ "$send_mail" == "yes" ]; then
	datestamp=`date +"%Y-%m-%d"`
	echo "No testfiles for group(s) $test_groups found." | \
	    mutt -s "[ape-run_testsuite on $arch] daily report - $datestamp" $mailaddr
    fi

# Otherwise, start the whole machinery.
else
    # Get epoch seconds at testsuite start.
    testsuite_start=$(date +%s) 

    # Run testsuite.
    run_testsuite "$testfiles"

    # Failure reporting to STDOUT.
    echo -e "    Passed:  $passed_tests / $total_tests"
    echo -e "    Skipped: $skipped_tests / $total_tests"
    if [ $failed_tests -gt 0 ]; then
	echo "    Failed:  $failed_tests / $total_tests"
	echo
	echo "    testfile                                          # failed testcases"
	echo "    --------------------------------------------------------------------"
	echo -e "$failure_report"
    else
	echo -e "\nEverything seems to be OK"
    fi
    echo


    # Get epoch seconds after we are done and compute time difference.
    testsuite_end=$(date +%s)
    timediff_sec=$[ testsuite_end - testsuite_start ]

    rm -rf ape-header
    RUNTIME="Total run-time of the testsuite: \
    $(printf '%02d:%02d:%02d' $[timediff_sec / 3600] \
    $[(timediff_sec % 3600) / 60 ] $[timediff_sec % 60])"

    # Save runtime for mail header.
    echo $RUNTIME > ape-header
    echo "" >> ape-header

    # And print also to the screen.
    echo $RUNTIME
    echo ""

        
    # Should we send a mail report?
    [ "${send_mail}" == "yes" ] && mail_report "$testfiles" "$mailaddr"


    # Clean up.
    [ "$cleanup" == "yes" ] && rm -f *.log ape-header stamp build-stamp
fi

exit $failed_tests


# Local Variables:
# mode: shell-script
# coding: utf-8
# End:
