#!/usr/bin/env zsh

usage() {
    echo "Usage: $0 [test-options] -- [beluga-options]"
    echo
    echo "Synopsis: test harness for Beluga."
    echo
    echo "Options:"
    echo "  -h,--help        Display this usage information."
    echo "  -c,--color       Force colorized output even when piped."
    echo "  --noexamples     Do not also test $EXAMPLEDIR."
    echo "  --examples       Only test $EXAMPLEDIR."
    echo "  --reset          Replace all .out files with new output (use with caution!)."
    echo
    echo "Notes:"
    echo "  - If any .cfg files are found in a subdirectory, only them will be tested."
    echo "  - If no .cfg file is found, all .bel files in the subdirectory"
    echo "    will be tested."
    echo "  - To inhibit testing .bel files, put an empty test.cfg in that directory."
}

echo "Parameters for this run (override as necessary using environment variables):"
echo

# Path to the Beluga source distribution.
echo -e "\t" BELUGADIR: ${BELUGADIR:=$(dirname $0)}

# Set $EXE to the executable to test.
echo -e "\t" EXE: ${EXE:=$BELUGADIR/bin/beluga}

# Test cases.
echo -e "\t" TESTDIR: ${TESTDIR:=$BELUGADIR/t}

# Test cases.
echo -e "\t" EXAMPLEDIR: ${EXAMPLEDIR:=$BELUGADIR/examples}

# Time limit.
echo -e "\t" TIMEOUT: ${TIMEOUT:=10} seconds

echo

# Allow file globs to match nothing.
setopt null_glob

# Find test cases.
test_cases() {
    for dir in $TESTDIR/**/ $EXAMPLEDIR/**/
    do
	cfgs=(${dir}*.cfg)
	if (( ${#cfgs[@]} > 0 ))
	then
	    print -C1 ${dir}*.cfg
	else
	    print -C1 ${dir}*.bel
	fi
    done
}

sort_cases() {
    cases=($(</dev/stdin))
    for i in ${(M)cases#*.bel}; do wc -c $i; done | sort -n | awk '{print $2}'
    print -C1 ${(M)cases#*.cfg}
}

do_testing() {
    local n=0 success=0 fail=0 timeout=0

    # Limit runtime of each test case, in seconds.
    ulimit -t $TIMEOUT

    for i in $(test_cases | sort_cases)
    do
	n=$((n+1))
	echo -ne "$C[start]**$CEND TEST $n: $i ... "

	result=$($EXE +test $* $i 2>&1)
	exit_code=$?
	diff_result=$(echo "$result" | diff -u $i.out - 2>/dev/null)
	# diff responds 0 if same, 1 if different, 2 if couldn't compare.
	diff_code=$?

	if [[ $exit_code -eq 152 ]]
	then
	    echo -e "$C[timeout]TIMEOUT$CEND"
	    timeout=$((timeout+1))
	elif [[ $diff_code -eq 0 || (exit_code -eq 0 && $diff_code -eq 2) ]]
	then
	    echo -e "$C[done]DONE$CEND"
	    success=$((success+1))
	else
	    echo -e "$C[fail]FAIL$CEND"
	    [[ -z "$diff_result" ]] && echo "$result" || (echo "$diff_result" | colorize_diff)
	    fail=$((fail+1))
	fi

	[[ -n $RESET && -f $i.out ]] && echo "$result" > $i.out
    done

    echo
    echo Successes: $success
    echo Failures: $fail
    echo Timeouts: $timeout
    echo Total: $n

    echo
    times

    # If not all tests succeeded then exit with non-zero status.
    [[ $success -eq $n ]] || exit 1
    exit 0
}

typeset -A C

colorize_diff() {
    sed "s/^+/${fg[green]}+/
         s/^-/${fg[red]}-/
         s/\$/$reset_color/"
}

set_colors() {
    autoload colors
    colors
    C=(start ${fg[blue]} done ${fg_bold[green]} timeout ${fg_bold[magenta]} fail ${fg_bold[red]})
    CEND=$reset_color
}

# By default, use colors only when connected to a terminal.
[[ -t 1 ]] && set_colors

while true
do
    case "$1" in
	-h|--help)
	    usage
	    exit 0
	    ;;
	-c|--colour|--color)
	    set_colors
	    shift
	    ;;
	--noexamples)
	    EXAMPLEDIR=/dev/null
	    shift
	    ;;
	--examples)
	    TESTDIR=/dev/null
	    shift
	    ;;
	--reset)
	    RESET=true
	    shift
	    ;;
	--)
	    shift
	    break
	    ;;
        "")
            break
            ;;
	*)
            echo "Unrecognized option $1."
	    echo "Make sure to write -- before any argument that should be passed to Beluga."
	    exit 2
    esac
done

do_testing $*
