#!/bin/sh

#####################################
#This script just runs the tests of 
#libcroco, saves their result, diff them
#against a set of reference results and
#displays OK/KO.
#To use it as a tester, the best way is
#just to run 'testctl run' and see the result.
####################################

#the directory that contains the tests
HERE=`dirname $0`

#the list of tests to be run
TEST_PROG_LIST=

#the test input dirs.
TEST_INPUT_DIR=test-inputs

#the reference test output dirs.
TEST_OUT_REF_DIR=test-output-refs

#temporary test result dir
TEST_OUTPUT_DIR=test-outputs

ERROR_REPORT_FILE=tests-error.log
COMMAND_LIST=
COMMAND=
RUN_VALGRIND=no
TEST_PROG=
EGREP=`which egrep`
if test "empty$EGREP" = "empty" ; then
    echo "You don't have the egrep program installed"
    echo "Please, install it first"
fi

DIFF=`which diff`
if test "empty$DIFF" = "empty" ; then
    echo "You don't have the diff program installed"
    echo "Please, install is first"
fi

display_usage ()
{
    echo ""
    echo "usage: $0 [general options] <command> [command option]"
    echo ""
    echo "where general options are:"
    echo "===================="
    echo "-h|--help     displays this help"
    echo ""
    echo "commands are:"
    echo "=============="
    echo "run           run the tests and display their result"
    echo "mkref         run the tests but saves their output as a reference"
    echo "mkcleanup     removes the tmp directories that may have been created"    
    echo ""
    echo "run command options:"
    echo "--valgrind runs the test using valgrind"
    echo "--testprog <test program>"
}

parse_command_line ()
{
    if test "empty$1" = "empty" ; then
	display_usage ;
	exit -1
    fi

    while true ; do
	arg=$1

	if test "empty$arg" = "empty" ; then
	    break ;
	fi

	case "$arg" in
	    -h|--help)
		display_usage $@
		exit 0
		;;

	    -*)
		echo "$0: unknown option: $arg"
		display_usage $@
		exit 0
		;;

	    run|mkref|mkcleanup)		
		COMMAND_LIST=$arg
		REMAINING_ARGS=$@
		echo "REMAINING_ARGS=$REMAINING_ARGS"
		break ;
		;;

	    *)
		display_usage $@
		exit 0
		;;
	esac
    done
}


#builds the list of available test functions.
build_tests_list ()
{
    for TEST_PROG in `ls -1 $HERE | egrep ^test\([0-9]\)+$` ; do
	echo "$un test: $TEST_PROG"
	TEST_PROG_LIST="$TEST_PROG_LIST $TEST_PROG"
    done
}

#runs a test programs.
#usage run_test_prog <test-name> <reference> <display-on-stdout>
#where "test-name" is the name of the test program to run
#"reference" is a boolean value: yes/no. (the string "yes" or the string no)
#if yes, means that the output of the test is to be saved as a reference.
#if no, means that the output of the test is to be saved as a result of a test.
run_test_prog ()
{
    TEST_PROG=$1
    REFERENCE=$2
    DISPLAY_ON_STDOUT=$3

    OUTPUT_DIR=
    OUTPUT_SUFFIX=
    TEST_INPUT_LIST=

    for TEST_INPUT in `ls -1 $HERE/$TEST_INPUT_DIR | egrep ^${TEST_PROG}\([\.0-9]\)+\css\$` ; do
	TEST_INPUT_LIST="$TEST_INPUT_LIST $TEST_INPUT"
    done

    if test "$REFERENCE" = "yes" ; then	
	OUTPUT_DIR=$HERE/$TEST_OUT_REF_DIR
	OUTPUT_SUFFIX=.out

	if test ! -d $HERE/$OUTPUT_DIR ; then
	    mkdir $HERE/$OUTPUT_DIR
	fi
    else
	if test ! -d $HERE/$TEST_OUTPUT_DIR/ ; then
	    echo "creating tmp directory $$HERE/$TEST_OUTPUT_DIR ..."
	    mkdir $HERE/$TEST_OUTPUT_DIR ;
	    echo "done"
	fi
	OUTPUT_DIR=$HERE/$TEST_OUTPUT_DIR
	OUTPUT_SUFFIX=.out
    fi

    if test "empty$TEST_INPUT_LIST" != "empty" ; then
	for TEST_INPUT in $TEST_INPUT_LIST ; do
	    if test "$DISPLAY_ON_STDOUT" = "yes" ; then
		echo "###############################################"
		echo "launching $HERE/$TEST_PROG $HERE/$TEST_INPUT_DIR/$TEST_INPUT"....
		echo "###############################################"
		$HERE/$TEST_PROG $HERE/$TEST_INPUT_DIR/$TEST_INPUT
		echo "###############################################"
		echo  "done"
		echo "###############################################"
		echo ""
	    else
		echo "executing $HERE/$TEST_PROG $HERE/$TEST_INPUT_DIR/$TEST_INPUT > $OUTPUT_DIR/${TEST_INPUT}${OUTPUT_SUFFIX} ..."
		$HERE/$TEST_PROG $HERE/$TEST_INPUT_DIR/$TEST_INPUT > $OUTPUT_DIR/${TEST_INPUT}${OUTPUT_SUFFIX}
		echo "done"
	    fi
	done
    else
	if test "$DISPLAY_ON_STDOUT" = "yes" ; then
	    echo "####################################################"
	    echo "launching $HERE/$TEST_PROG ..."
	    echo "####################################################"
	    $HERE/$TEST_PROG
	    echo "####################################################"
	    echo "done"
	    echo "####################################################"
	    echo ""
	else
	    echo "executing $HERE/$TEST_PROG  > $OUTPUT_DIR/${TEST_INPUT}${OUTPUT_SUFFIX} ..."
	    $HERE/$TEST_PROG > $OUTPUT_DIR/${TEST_PROG}${OUTPUT_SUFFIX}
	    echo "done"
	fi
    fi
}

cleanup_tests ()
{
    if test -d $HERE/$TEST_OUTPUT_DIR ; then
	echo "removing $HERE/$TEST_OUTPUT_DIR"
	rm -rf $HERE/$TEST_OUTPUT_DIR/*
    fi
}

run_test_report ()
{
    diff -ur --exclude=*CVS* --exclude=*cvs* --exclude=Makefile* $HERE/$TEST_OUT_REF_DIR $HERE/$TEST_OUTPUT_DIR > /tmp/toto$$
    NB_DIFF=`cat /tmp/toto$$ | wc -l`

    if test "$NB_DIFF" -eq 0 ; then
	echo "/////////////ALL THE TESTS ARE OK :) //////////////////"
	rm /tmp/toto$$
    else
	echo "SOME TESTS ARE KO :("
	mv /tmp/toto$$ $HERE/$ERROR_REPORT_FILE
	echo "See $HERE/$ERROR_REPORT_FILE to see what's going on"
    fi
}

############################
#Executes the "run" command along with
#it's command options.
#For the sake of safety checking
############################
execute_run_cmd ()
{
    args=$@

    if test "$1" != "run" ; then
	echo "internal error: first argument should be \'run\'"
	return
    fi
    shift

    while true ; do
	cur_arg=$1
	echo "cur_arg=$cur_arg"

	case $cur_arg in
	    --valgrind)
		RUN_VALGRIND=yes
		shift
		;;

	    "--testprog")
		shift
		if test "empty$1" = "empty" ; then
		    echo "--testprog should be followed by a prog name"
		    display_usage
		    exit
		fi
		TEST_PROG=$1
		echo "TEST_PROG=$TEST_PROG"
		shift
		;;

	    *)
		break 
		;;
	esac
    done

    if test "empty$TEST_PROG" = "empty"; then
	build_tests_list ;
	if test "empty$TEST_PROG_LIST" = "empty" ; then
	    echo "could not find any test to run"
	    exit
	fi

	for TEST in $TEST_PROG_LIST ; do
	    run_test_prog $TEST no no;
	done
	run_test_report ;
    else
	#run the test and display result on stdout
	run_test_prog $TEST_PROG no yes ;
    fi
}

##############################
#Analyzes a command string "<command> [command option]"
#and runs the necessary commands.
#
#Must be called with the command line
#starting with a command name.
#all the previous general argument must
#have been stripped away.
#############################
execute_command ()
{
    arg=$1 ;

    case "$arg" in

	run)
	    execute_run_cmd $@
	    ;;

	mkref)
	    build_tests_list ;
	    if test "empty$TEST_PROG_LIST" = "empty" ; then
		echo "could not find any test to run"
		exit
	    fi

	    for TEST in $TEST_PROG_LIST ; do
		run_test_prog $TEST yes no;
	    done
	    ;;

	mkcleanup)
	    rm -f $HERE/$TEST_OUTPUT_DIR/*

	    if test -f $HERE/$ERROR_REPORT_FILE ; then
		rm $HERE/$ERROR_REPORT_FILE
	    fi
	    ;;

	*)
	    echo "unknown command"
	    exit ;
    esac
    
}

main ()
{
    parse_command_line $@

    if test "empty$COMMAND_LIST" = "empty" ; then
	echo "no test command to execute"
	exit
    fi

    execute_command $REMAINING_ARGS
}

main $@
