#!/bin/sh

# testing framework for /bin/sh

# if run from "make check", use pid and time to name TMPDIR, 
# which will automatically be deleted.

# if run from command line, use testname and date for TMPDIR,
# and suppress directory deletion.

set -e

exec </dev/null

: ${srcdir=.}
: ${relpath=..}
: ${BF_TESTDIR=.}

# suck in EXE_EXT and DB_TYPE, export the latter.
. ./t.config
export DB_TYPE
DB_EXT=${DB_EXT#.}
export DB_EXT

BOGOFILTER="$VAL ${relpath}/bogofilter$EXE_EXT"
BOGOLEXER="$VAL ${relpath}/bogolexer$EXE_EXT"
BOGOTUNE="$VAL ${relpath}/bogotune$EXE_EXT"
BOGOUTIL="$VAL ${relpath}/bogoutil$EXE_EXT"

export BOGOFILTER
export BOGOLEXER
export BOGOUTIL

# Cater for GNU coreutils "compatibility"
_POSIX2_VERSION=199209
export _POSIX2_VERSION

# Obtain data base file suffix
DB_NAME=`$BOGOFILTER -C -V 2>&1 | sed -n '2p;'`
case $DB_NAME in
    *BerkeleyDB*|*"Berkeley DB"*)
	case $DB_NAME in
	    *" TRANSACTIONAL"*|*" AUTO-XA"*) DB_TXN=true ;;
	    *)                               DB_TXN=false ;;
	esac ;;
    *QDBM*)	     DB_TXN=false ;;
    *SQLite*)	     DB_TXN=true  ;;
    *TrivialDB*)     DB_TXN=false ;;
    *)		    echo >&2 "Unknown data base type in bogofilter -V: $DB_NAME"
		    exit 1 ;;
esac
export DB_EXT DB_TXN
if [ "x$BF_TESTVERBOSE" != x ] ; then
    echo "detected database type \"$DB_TYPE\", extension: \"$DB_EXT\", transactions: $DB_TXN"
fi

# Cater for Solaris "compatibility"
case $PATH in
*/usr/xpg4/bin:*) ;;
*)
    if test -d /usr/xpg4/bin ; then
	PATH=/usr/xpg4/bin:$PATH
	export PATH
    fi
    ;;
esac

# However, Solaris' /usr/xpg4/bin/grep doesn't support long lines, so we
# need to use /usr/bin/grep instead

GREP=/bin/grep
test -x $GREP || GREP=/usr/bin/grep
test -x $GREP || { echo >&2 'Cannot find grep!' ; exit 1 ; }
export GREP

# Linux has md5sum; BSD has md5

MD5SUM=`which md5sum 2>/dev/null` || :
test -x "$MD5SUM" || MD5SUM=`which md5 2>/dev/null`
test -x "$MD5SUM" || { echo >&2 'Cannot find md5sum!' ; exit 1 ; }
export MD5SUM

: ${AWK=awk}
export AWK

LANG=
LC_COLLATE=
LC_ALL=
unset LANG || :
unset LC_COLLATE || :
unset LC_ALL || :
i=0
INSERT=.
while [ $i -lt 3 ] ; do
    PRINTCORE=${srcdir}/$INSERT/printcore
    if [ -f $PRINTCORE ] ; then break ; fi
    i=`expr $i + 1`
    INSERT=$INSERT/..
done

SYSTEST="${srcdir}"
OUTPUTS=${SYSTEST}/outputs

if [ -z "$RUN_FROM_MAKE" ] || [ "$SUPPRESS_DELETE" = YES ] ; then
# standalone, from shell directly
# THIS IS PRONE TO RACES
   NAME=`basename $0 | sed -e 's/^t\.//'`
   DATE=`date +"%Y%m%d"`
   TMPDIR="${BF_TESTDIR}/$NAME.$DATE"
   SUPPRESS_DELETE="NO"
else
# automated, from make
    while : ; do
	TMPDIR=${BF_TESTDIR}/checks.$$.`date +"%Y%m%dT%H%M%S"`
	if test x$SUPPRESS_DELETE = xNO ; then TMPDIR=${BF_TESTDIR}/outputs.`date +"%m%d"` ; fi
        mkdir $TMPDIR && break || :
	sleep 1
    done
fi
rm -rf $TMPDIR
mkdir $TMPDIR

BOGOFILTER_DIR=$TMPDIR
export BOGOFILTER_DIR

WORDLIST="${TMPDIR}/wordlist.${DB_EXT}"

verbose=0
if [ "$1" = "-v" ]; then
    verbose=1
    $BOGOFILTER -V 2> ${TMPDIR}/version.out
fi

if [ "$1" = "-vv" ]; then
    v="-x l -vv -D"
    verbose=2
fi

if test "x$BF_TESTVERBOSE" != "x" ; then
    verbose=$BF_TESTVERBOSE
fi

if test "x$SUPPRESS_DELETE" = "x" ; then
    trap '$SHELL $PRINTCORE ; rm -r -f core ${TMPDIR}' 0
else
    echo "Results are in ${TMPDIR}.  Remove it after testing."
fi

create_empty_wordlist()
{
    rm -f $BOGOFILTER_DIR/*.${DB_EXT}
    rm -f $BOGOFILTER_DIR/__db.* $BOGOFILTER_DIR/log.*
    $BOGOUTIL -l $BOGOFILTER_DIR/wordlist.${DB_EXT} < /dev/null
}

if [ -z "$NODB" ]; then
    create_empty_wordlist
fi

# check valgrind version
case `(valgrind --version) 2>/dev/null` in
    valgrind-2.[123].*) VALGRIND="valgrind --tool=memcheck" ;;
    valgrind-*) VALGRIND="valgrind" ;;
    *) VALGRIND= ;;
esac
if [ "x$VALGRIND" != x ] ; then
    VALGRIND="$VALGRIND -q --num-callers=20"
fi
export VALGRIND

# parse BF_CHECKTOOL
BF_CHECKTOOL=${BF_CHECKTOOL-glibc}
case ${BF_CHECKTOOL} in
glibc)
    # make GNU libc nasty and abort on memory allocation issues:
    MALLOC_CHECK_=2
    export MALLOC_CHECK_
    ;;
boehm-gc)
    # use the Boehm-Demers-Weiser Garbage Collector in find-leak mode,
    # only supported on Linux:
    for p in /usr/local/lib /usr/lib /lib ; do
	if test -f $p/libgc.so ; then
	    VAL="env LD_PRELOAD=$p/libgc.so GC_FIND_LEAK=1"
	    export VAL
	    break
	fi
    done
    ;;
valgrind)
    # use valgrind
    if test "x$VALGRIND" != x ; then
	VAL="$VALGRIND --leak-check=yes"
	export VAL
    else
	echo >&2 "WARNING: valgrind not found or unsupported version, ignored."
    fi
    ;;
efence)
    # use Electric Fence
    VAL="env LD_PRELOAD=libefence.so.0.0"
    EF_PROTECT_FREE=1
    EF_FILL=85
    EF_ALLOW_MALLOC_0=1
    EF_PROTECT_BELOW=0
    EF_ALIGNMENT=0
    export LD_PRELOAD EF_PROTECT_FREE EF_FILL EF_ALLOW_MALLOC_0 EF_PROTECT_BELOW
    export EF_ALIGNMENT VAL
    ;;
"")
    ;;
*)
    echo >&2 "WARNING: unsupported BF_CHECKTOOL=\"${BF_CHECKTOOL}\" ignored."
    echo >&2 "         supported BF_CHECKTOOL values: glibc, boehm-gc, valgrind, efence"
    ;;
esac

# check diff options
case `uname -s` in
    Linux)  case $verbose in 
	    1) DIFF_BRIEF="--brief -s" ;;
	    2) DIFF_BRIEF="-u" ;;
	esac
	;;
esac

# ## HELPER FUNCTIONS ---------------------------------------------
# split file on stdin into files 1, 2, 3, 4... at "From " lines.
splitmbox() {
      $AWK 'BEGIN { f=0; } /^From / { close(f); f++; } { print $0 > f }'
}
