]> mj.ucw.cz Git - moe.git/blobdiff - bin/lib
MO_PUBLIC has been replaced by MO_ROOT.
[moe.git] / bin / lib
diff --git a/bin/lib b/bin/lib
index 090e752a6dd5059cc13ce47cfb9fed0501add962..588cf269b5c4ec98522cc59a5bfaf9f36e5ae487 100644 (file)
--- a/bin/lib
+++ b/bin/lib
@@ -1,5 +1,8 @@
 # The Evaluator -- Shell Function Library
 # The Evaluator -- Shell Function Library
-# (c) 2001 Martin Mares <mj@ucw.cz>
+# (c) 2001--2004 Martin Mares <mj@ucw.cz>
+
+# General settings
+shopt -s dotglob
 
 # Logging functions.
 # File handles used: fd1=log, fd2=progress
 
 # Logging functions.
 # File handles used: fd1=log, fd2=progress
@@ -27,6 +30,15 @@ function pend
 
 function die
 {
 
 function die
 {
+       # Report an internal error
+       echo >&2 "$@"
+       [ -n "$HAVE_LOG" ] && echo "Fatal error: $@"
+       exit 2
+}
+
+function fatal
+{
+       # Report a fatal error in the program being tested
        echo >&2 "$@"
        [ -n "$HAVE_LOG" ] && echo "Fatal error: $@"
        exit 1
        echo >&2 "$@"
        [ -n "$HAVE_LOG" ] && echo "Fatal error: $@"
        exit 1
@@ -37,15 +49,15 @@ function die
 function box-init
 {
        pstart "Preparing sandbox... "
 function box-init
 {
        pstart "Preparing sandbox... "
-       [ -n "$TEST_USER" ] || die "TEST_USER not set. Please fix."
-       if [ $TEST_USER == $EVAL_USER ] ; then
+       if [ -z "$TEST_USER" -o "$TEST_USER" == $EVAL_USER ] ; then
                pcont "running locally (INSECURE), "
                pcont "running locally (INSECURE), "
+               TEST_USER=$EVAL_USER
                BOXDIR=box
                BOXCMD=bin/box
                mkdir -p box
        else
                pcont "used account $TEST_USER, "
                BOXDIR=box
                BOXCMD=bin/box
                mkdir -p box
        else
                pcont "used account $TEST_USER, "
-               BOXDIR=$MO_ROOT/$TEST_USER
+               BOXDIR=$MO_ROOT/eval/$TEST_USER
                BOXCMD=bin/box-$TEST_USER
        fi
        [ -d $BOXDIR -a -f $BOXCMD ] || die "Sandbox set up incorrectly"
                BOXCMD=bin/box-$TEST_USER
        fi
        [ -d $BOXDIR -a -f $BOXCMD ] || die "Sandbox set up incorrectly"
@@ -59,7 +71,6 @@ function box-init
 function box-clean
 {
        [ -n "$BOXCMD" ] || die "box-init not called"
 function box-clean
 {
        [ -n "$BOXCMD" ] || die "box-init not called"
-       # FIXME: Dot files
        rm -rf $BOXDIR/*
 }
 
        rm -rf $BOXDIR/*
 }
 
@@ -68,14 +79,16 @@ function box-clean
 function dir-init
 {
        pstart "Initializing... "
 function dir-init
 {
        pstart "Initializing... "
+       HDIR=.
        PDIR=problems/$PROBLEM
        SDIR=solutions/$CONTESTANT/$PROBLEM
        TDIR=testing/$CONTESTANT/$PROBLEM
        PDIR=problems/$PROBLEM
        SDIR=solutions/$CONTESTANT/$PROBLEM
        TDIR=testing/$CONTESTANT/$PROBLEM
+       TMPDIR=tmp
        [ -d $PDIR ] || die "Problem $PROBLEM not known"
        [ -d $PDIR ] || die "Problem $PROBLEM not known"
-       [ -d $SDIR ] || die "Solution of $PROBLEM not found"
-       mkdir -p $TDIR
-       rm -rf $TDIR
-       cp -a $SDIR $TDIR
+       [ -d $SDIR ] || fatal "Solution of $PROBLEM not found"
+       mkdir -p $TDIR $TMPDIR
+       rm -rf $TDIR $TMPDIR
+       mkdir -p $TDIR $TMPDIR
        cat >$TDIR/log <<EOF
 Testing solution of $PROBLEM by $CONTESTANT
 Test started at `date`
        cat >$TDIR/log <<EOF
 Testing solution of $PROBLEM by $CONTESTANT
 Test started at `date`
@@ -83,7 +96,6 @@ Contestant's solution directory: $SDIR
 Problem directory: $PDIR
 Testing directory: $TDIR
 EOF
 Problem directory: $PDIR
 Testing directory: $TDIR
 EOF
-       >$TDIR/points
        pend "OK"
 }
 
        pend "OK"
 }
 
@@ -91,41 +103,44 @@ EOF
 
 function locate-source
 {
 
 function locate-source
 {
-       pstart "Locating source... "
+       pstart "Finding source... "
+       SBASE=${1:-$PROBLEM}
        for a in $EXTENSIONS ; do
        for a in $EXTENSIONS ; do
-               if [ -f $SDIR/$PROBLEM.$a ] ; then
+               if [ -f $SDIR/$SBASE.$a ] ; then
                        [ -z "$SRCN" ] || die "Multiple source files found: $SDIR/$PROBLEM.$a and $SDIR/$SRCN. Please fix."
                        [ -z "$SRCN" ] || die "Multiple source files found: $SDIR/$PROBLEM.$a and $SDIR/$SRCN. Please fix."
-                       SRCN=$PROBLEM.$a
+                       SRCN=$SBASE.$a
                        SRCEXT=$a
                fi
        done
                        SRCEXT=$a
                fi
        done
-       [ -n "$SRCN" ] || die "NOT FOUND"
+       [ -n "$SRCN" ] || fatal "NOT FOUND"
        pend $SRCN
        echo "Found source file: $SDIR/$SRCN"
 }
 
        pend $SRCN
        echo "Found source file: $SDIR/$SRCN"
 }
 
-# Compilation (compile SDIR/SRCN with PDIR/EXTRAS to EXE=TDIR/PROBLEM)
+# Compilation (compile SDIR/SRCN with PDIR/COMP_EXTRAS to EXE=TDIR/PROBLEM)
 
 function compile
 {
        pstart "Compiling... "
        cp -a $SDIR/$SRCN $TDIR/$SRCN
 
 function compile
 {
        pstart "Compiling... "
        cp -a $SDIR/$SRCN $TDIR/$SRCN
-       if [ -n "$EXTRAS" ] ; then
-               echo "Extras: $EXTRAS"
-               for a in $EXTRAS ; do cp $PDIR/$a $TDIR/ ; done
+       if [ -n "$COMP_EXTRAS" ] ; then
+               echo "Extras: $COMP_EXTRAS"
+               for a in $COMP_EXTRAS ; do cp $PDIR/$a $TDIR/ ; done
        fi
        box-clean
        fi
        box-clean
-       for a in $SRCN $EXTRAS ; do cp $TDIR/$a $BOXDIR/ ; done
+       for a in $SRCN $COMP_EXTRAS ; do cp $TDIR/$a $BOXDIR/ ; done
        SRC=$SRCN
        EXE=$PROBLEM
        CCMD=COMP_$SRCEXT
        SRC=$SRCN
        EXE=$PROBLEM
        CCMD=COMP_$SRCEXT
-       CCMD="`eval echo ${!CCMD}`"
-       COMP_SANDBOX_OPTS="`eval echo $COMP_SANDBOX_OPTS`"
+       CCMD=`eval echo ${!CCMD}`
+       COMP_SANDBOX_OPTS=`eval echo $COMP_SANDBOX_OPTS`
        echo "Compiler command: $CCMD"
        echo "Compiler sandbox options: $COMP_SANDBOX_OPTS"
        echo "Compiler command: $CCMD"
        echo "Compiler sandbox options: $COMP_SANDBOX_OPTS"
+       eval $COMP_SANDBOX_INIT
 
        echo "Compiler input files:"
        ls -Al $BOXDIR
 
        echo "Compiler input files:"
        ls -Al $BOXDIR
+       echo "Compiler output:"
        if ! $BOXCMD $COMP_SANDBOX_OPTS -- $CCMD 2>$TDIR/compile.out ; then
                COMPILE_MSG="`cat $TDIR/compile.out`"
                pend "FAILED: $COMPILE_MSG"
        if ! $BOXCMD $COMP_SANDBOX_OPTS -- $CCMD 2>$TDIR/compile.out ; then
                COMPILE_MSG="`cat $TDIR/compile.out`"
                pend "FAILED: $COMPILE_MSG"
@@ -133,6 +148,7 @@ function compile
                return 1
        fi
        cat $TDIR/compile.out
                return 1
        fi
        cat $TDIR/compile.out
+       rm $TDIR/compile.out
        echo "Compiler output files:"
        ls -Al $BOXDIR
        if [ ! -f $BOXDIR/$PROBLEM ] ; then
        echo "Compiler output files:"
        ls -Al $BOXDIR
        if [ ! -f $BOXDIR/$PROBLEM ] ; then
@@ -146,39 +162,188 @@ function compile
        pend "OK"
 }
 
        pend "OK"
 }
 
-# Running of test program with file input/output
+# Running of test program according to current task type (returns exit code and TEST_MSG)
+
+function test-run
+{
+       test-run-$TASK_TYPE
+}
+
+function test-result
+{
+       P=$1
+       M=$2
+       if [ -s $TDIR/$TEST.pts ] ; then
+               P=`cat $TDIR/$TEST.pts`
+               rm $TDIR/$TEST.pts
+       fi
+       echo "Verdict: $M"
+       echo "Points: $P"
+       test-verdict $P "$M"
+}
 
 
-function test-run-with-files
+function test-prolog
 {
        pcont "<init> "
        box-clean
        echo "Executable file: $TDIR/$PROBLEM"
 {
        pcont "<init> "
        box-clean
        echo "Executable file: $TDIR/$PROBLEM"
+       if [ ! -x $TDIR/$PROBLEM ] ; then
+               test-result 0 "Compile error."
+       fi
        cp $TDIR/$PROBLEM $BOXDIR/
        cp $TDIR/$PROBLEM $BOXDIR/
-       echo "Input: $TDIR/$PROBLEM"
-       cp $PDIR/$TEST.in $BOXDIR/$PROBLEM.in
-       echo "Input files:"
+       BOX_EXTRAS=
+       IN_TYPE=${IN_TYPE:-$IO_TYPE}
+       OUT_TYPE=${OUT_TYPE:-$IO_TYPE}
+       case $IN_TYPE in
+               file)   echo "Input file: $PROBLEM.in (from $PDIR/$TEST.in)"
+                       ln $PDIR/$TEST.in $TDIR/$TEST.in
+                       cp $PDIR/$TEST.in $BOXDIR/$PROBLEM.in
+                       BOX_EXTRAS="$BOX_EXTRAS -i/dev/null"
+                       ;;
+               stdio)  echo "Input file: <stdin> (from $PDIR/$TEST.in)"
+                       ln $PDIR/$TEST.in $TDIR/$TEST.in
+                       cp $PDIR/$TEST.in $BOXDIR/.stdin
+                       BOX_EXTRAS="$BOX_EXTRAS -i.stdin"
+                       ;;
+               none)   echo "Input file: <none>"
+                       ;;
+               *)      die "Unknown IN_TYPE $IN_TYPE"
+                       ;;
+       esac
+       case $OUT_TYPE in
+               file)   echo "Output file: $PROBLEM.out"
+                       BOX_EXTRAS="$BOX_EXTRAS -o/dev/null"
+                       ;;
+               stdio)  echo "Output file: <stdout>"
+                       BOX_EXTRAS="$BOX_EXTRAS -o.stdout"
+                       ;;
+               none)   echo "Output file: <none>"
+                       ;;
+               *)      die "Unknown OUT_TYPE $OUT_TYPE"
+                       ;;
+       esac
+       echo "Timeout: $TIME_LIMIT s"
+       echo "Memory: $MEM_LIMIT KB"
+       eval $SANDBOX_INIT
+       echo "Sandbox contents before start:"
+       ls -Al $BOXDIR
+}
+
+function test-epilog
+{
+       echo "Sandbox contents after exit:"
        ls -Al $BOXDIR
        ls -Al $BOXDIR
+       case ${OUT_TYPE:-$IO_TYPE} in
+               file)   [ -f $BOXDIR/$PROBLEM.out ] || test-result 0 "No output file."
+                       cp $BOXDIR/$PROBLEM.out $TDIR/$TEST.out
+                       ;;
+               stdio)  [ -f $BOXDIR/.stdout ] || test-result 0 "No output file."
+                       cp $BOXDIR/.stdout $TDIR/$TEST.out
+                       ;;
+       esac
+}
 
 
+# Running of test program with file input/output
+
+function test-run-file
+{
+       test-prolog
        pcont "<run> "
        pcont "<run> "
-       echo "Timeout: $TIME_LIMIT s"
-       echo "Memory: $MEM_LIMIT KB"
-       BOXOPTS="`eval echo $TEST_SANDBOX_OPTS`"
+       BOXOPTS="`eval echo $TEST_SANDBOX_OPTS`$BOX_EXTRAS"
        echo "Sandbox options: $BOXOPTS"
        echo "Sandbox options: $BOXOPTS"
-       if ! $BOXCMD $BOXOPTS -- ./$PROBLEM 2>$TDIR/exec.out ; then
-               TEST_MSG="`cat $TDIR/exec.out`"
-               pend "$TEST_MSG"
-               echo "$TEST_MSG"
-               # FIXME: Better recognition of run-time errors
-               echo >$PTSFILE "0 RT"
-               return 1
+       if ! $BOXCMD $BOXOPTS -- ./$PROBLEM 2>$TMPDIR/exec.out ; then
+               cat $TMPDIR/exec.out
+               MSG=`tail -1 $TMPDIR/exec.out`
+               test-result 0 "$MSG"
        fi
        fi
-       echo "Output files:"
-       ls -Al $BOXDIR
-       if [ ! -f $BOXDIR/$PROBLEM.out ] ; then
-               pend "No output file."
-               echo "No output file."
-               echo >$PTSFILE "0 NO"
-               return 1
+       cat $TMPDIR/exec.out
+       test-epilog
+}
+
+# Running of interactive test programs
+
+function test-run-interactive
+{
+       test-prolog
+       pcont "<run> "
+       BOXOPTS="`eval echo $TEST_SANDBOX_OPTS`$BOX_EXTRAS"
+       echo "Sandbox options: $BOXOPTS"
+       ICCMD=`eval echo $IA_CHECK`
+       echo "Interactive checker: $ICCMD"
+       if ! $HDIR/bin/iwrapper $BOXCMD $BOXOPTS -- ./$PROBLEM @@ $ICCMD 2>$TMPDIR/exec.out ; then
+               cat $TMPDIR/exec.out
+               MSG="`tail -1 $TMPDIR/exec.out`"
+               test-result 0 "$MSG"
        fi
        fi
-               cp $BOXDIR/$PROBLEM.out $TDIR/$PROBLEM.out
+       cat $TMPDIR/exec.out
+       test-epilog
+}
+
+# Syntax checks
+
+function syntax-check
+{
+       [ -n "$SYNTAX_CHECK" ] || return 0
+       pcont "<syntax> "
+       SCHECK=`eval echo $SYNTAX_CHECK`
+       echo "Syntax check command: $SCHECK"
+       if ! eval $SCHECK 2>$TMPDIR/exec.out ; then
+               cat $TMPDIR/exec.out
+               MSG=`tail -1 $TMPDIR/exec.out`
+               if [ -z "$MSG" ] ; then MSG="Wrong syntax." ; fi
+               test-result 0 "$MSG"
+       fi
+       cat $TMPDIR/exec.out
+}
+
+# Output checks
+
+function output-check
+{
+       [ -n "$OUTPUT_CHECK" ] || return 0
+       pcont "<check> "
+       [ -f $PDIR/$TEST.out ] && ln $PDIR/$TEST.out $TDIR/$TEST.ok
+       OCHECK=`eval echo $OUTPUT_CHECK`
+       echo "Output check command: $OCHECK"
+       if ! eval $OCHECK 2>$TMPDIR/exec.out ; then
+               cat $TMPDIR/exec.out
+               MSG=`tail -1 $TMPDIR/exec.out`
+               if [ -z "$MSG" ] ; then MSG="Wrong answer." ; fi
+               test-result 0 "$MSG"
+       fi
+       cat $TMPDIR/exec.out
+       MSG=`tail -1 $TMPDIR/exec.out`
+       if [ -z "$MSG" ] ; then MSG="OK" ; fi
+       test-result $POINTS_PER_TEST "$MSG"
+}
+
+# Setup of public commands
+
+function public-setup
+{
+       HDIR=$MO_ROOT
+       PDIR=$MO_ROOT/problems/$PROBLEM
+       SDIR=.
+       TDIR=~/.test
+       TMPDIR=~/.test
+       [ -d $PDIR ] || die "Unknown problem $PROBLEM"
+
+       pstart "Initializing... "
+       mkdir -p $TDIR
+       rm -rf $TDIR/*
+       BOXDIR=~/.box
+       mkdir -p $BOXDIR
+       rm -rf $BOXDIR/*
+       BOXCMD="$MO_ROOT/bin/box -c$BOXDIR"
+       exec >log
+       pend "OK  (see 'log' for details)"
+}
+
+# Locate output of open data problem, test case TEST
+
+function open-locate
+{
+       [ -f $PDIR/$TEST.in ] || die "Unknown test $TEST"
+       SRCN=$SDIR/$PROBLEM$TEST.out
+       [ -f $SRCN ] || fatal "Output file $SRCN not found"
 }
 }