From: Martin Mares Date: Thu, 15 May 2008 09:45:24 +0000 (+0200) Subject: Moved the evaluator scripts to eval/. X-Git-Tag: python-dummy-working~202 X-Git-Url: http://mj.ucw.cz/gitweb/?a=commitdiff_plain;h=ac79334eceb1fd9b0b663b75eac5e72fcf5618e4;p=moe.git Moved the evaluator scripts to eval/. --- diff --git a/Makefile b/Makefile index 17ea270..af3658a 100644 --- a/Makefile +++ b/Makefile @@ -4,7 +4,7 @@ VERSION=1.0.99-20080220 # The default target -all: runtree programs +all: runtree programs datafiles # Include configuration s=. diff --git a/bin/ev b/bin/ev deleted file mode 100755 index 7d5ecc3..0000000 --- a/bin/ev +++ /dev/null @@ -1,58 +0,0 @@ -#!/bin/bash -# The Evaluator -- Master Control Script -# (c) 2001--2008 Martin Mares - -set -e -if [ ! -f config -o ! -f bin/lib ] ; then - echo "Unable to find evaluator files!" - exit 1 -fi -. bin/lib -. config -while parse-cmdline "$1" ; do - shift -done - -[ -n "$2" -a -z "$4" ] || die "Usage: ev [=] []" -CONTESTANT=$1 -PROBLEM=$2 -dir-init -log-init -. $PDIR/config -box-init - -# Compile the program -if [ $TASK_TYPE != open-data ] ; then - locate-source `if [ -n "$3" ] ; then echo $SDIR/$3 ; fi` - compile || true -fi - -# Initialize the points file -PTSFILE=$TDIR/points ->$PTSFILE - -function test-verdict -{ - if [ $1 == 0 ] ; then - pend "$2" - else - pend "$2 ($1 points)" - fi - echo >>$PTSFILE "$TEST $1 $2" - exit 0 -} - -# Perform the tests -[ -z "$EV_SAMPLE" ] || TESTS="$SAMPLE_TESTS $TESTS" -for TEST in $TESTS ; do - ( - exec >$TDIR/$TEST.log - test-config - pstart "Test $TEST... " - echo "Test $TEST ($POINTS_PER_TEST points)" - test-run - syntax-check - output-check - die "You must never see this message." - ) -done diff --git a/bin/lib b/bin/lib deleted file mode 100644 index 8bda3e6..0000000 --- a/bin/lib +++ /dev/null @@ -1,518 +0,0 @@ -# The Evaluator -- Shell Function Library -# (c) 2001--2008 Martin Mares - -# General settings -shopt -s dotglob - -# Logging functions. -# File handles used: fd1=log, fd2=progress - -function log-init -{ - exec >>$TDIR/log - HAVE_LOG=1 -} - -function pstart -{ - echo >&2 -n "$@" -} - -function pcont -{ - echo >&2 -n "$@" -} - -function pend -{ - echo >&2 "$@" -} - -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 -} - -function try-ln -{ - ln $1 $2 2>/dev/null || cp $1 $2 -} - -# Expand occurrences of `$var' in a given variable - -function expand-var -{ - eval echo ${!1} -} - -# Given a , override each variable by _ - -function override-vars -{ - local OR V W - declare -a OR - # `${!${1}_@}' does not work, so we have to use eval - OR=($(eval echo '${!'$1'_@}')) - for V in "${OR[@]}" ; do - W=${V##$1_} - eval $W='"$'$V'"' - done -} - -# Sandbox subroutines - -function box-init -{ - pstart "Preparing sandbox... " - if [ -z "$TEST_USER" -o "$TEST_USER" == $EVAL_USER ] ; then - pcont "running locally (INSECURE), " - TEST_USER=$EVAL_USER - BOXDIR=`pwd`/box - BOXCMD=bin/box - mkdir -p box - else - pcont "used account $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="$BOXCMD -c$BOXDIR" - echo "Sandbox directory: $BOXDIR" - echo "Sandbox command: $BOXCMD" - box-clean - pend "OK" -} - -function box-clean -{ - [ -n "$BOXCMD" ] || die "box-init not called" - rm -rf $BOXDIR/* -} - -# Initialization of testing directories - -function dir-init -{ - pstart "Initializing... " - HDIR=. - PDIR=problems/$PROBLEM - SDIR=solutions/$CONTESTANT/$PROBLEM - TDIR=testing/$CONTESTANT/$PROBLEM - TMPDIR=tmp - [ -d $PDIR ] || die "Problem $PROBLEM not known" - [ -d $SDIR ] || fatal "Solution of $PROBLEM not found" - mkdir -p $TDIR $TMPDIR - rm -rf $TDIR $TMPDIR - mkdir -p $TDIR $TMPDIR - cat >$TDIR/log <$TDIR/compile.out ; then - COMPILE_MSG="`cat $TDIR/compile.out`" - pend "FAILED: $COMPILE_MSG" - echo "$COMPILE_MSG" - return 1 - fi - cat $TDIR/compile.out - rm $TDIR/compile.out - if [ -n "$POST_COMPILE_HOOK" ] ; then - echo "Post-compile hook: $POST_COMPILE_HOOK" - eval $POST_COMPILE_HOOK - fi - echo "Compiler output files:" - ls -Al $BOXDIR - if [ ! -f $BOXDIR/$PROBLEM ] ; then - pend "FAILED: Missing executable file" - echo "Missing executable file" - return 1 - fi - EXE=$TDIR/$PROBLEM - cp -a $BOXDIR/$PROBLEM $EXE - echo "Compiled OK, result copied to $EXE" - pend "OK" -} - -# Running of test program according to current task type (returns exit code and TEST_MSG) - -function test-config -{ - [ -f $PDIR/$TEST.config ] && . $PDIR/$TEST.config - override-vars "TEST_$TEST" -} - -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 - - # Translate signal numbers to readable strings - SG=${M#Caught fatal signal } - SG=${SG#Committed suicide by signal } - if [ "$SG" != "$M" ] ; then - SG=`perl -MConfig -e '@s=split / /,$Config{sig_name}; print $s[$ARGV[0]]' $SG` - [ -z "$SG" ] || M="$M (SIG$SG)" - fi - - # Translate runtime errors to readable strings - RE=${M#Exited with error status } - if [ -n "$EXIT_CODE_HOOK" -a "$RE" != "$M" ] ; then - NEWMSG=`$EXIT_CODE_HOOK $RE` - if [ -n "$NEWMSG" ] ; then - M="Runtime error $RE: $NEWMSG" - fi - fi - - echo "Verdict: $M" - echo "Points: $P" - test-verdict $P "$M" -} - -function test-prolog -{ - pcont " " - box-clean - echo "Executable file: $TDIR/$PROBLEM" - if [ ! -x $TDIR/$PROBLEM ] ; then - test-result 0 "Compile error" - fi - cp $TDIR/$PROBLEM $BOXDIR/ - 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)" - try-ln $PDIR/$TEST.in $TDIR/$TEST.in - cp $PDIR/$TEST.in $BOXDIR/$PROBLEM.in - [ $TASK_TYPE == interactive ] || BOX_EXTRAS="$BOX_EXTRAS -i/dev/null" - ;; - stdio) echo "Input file: (from $PDIR/$TEST.in)" - try-ln $PDIR/$TEST.in $TDIR/$TEST.in - cp $PDIR/$TEST.in $BOXDIR/.stdin - BOX_EXTRAS="$BOX_EXTRAS -i.stdin" - ;; - none) echo "Input file: " - ;; - *) die "Unknown IN_TYPE $IN_TYPE" - ;; - esac - if [ -n "$EV_PEDANT" -a $IN_TYPE != none ] ; then - pcont " " - if [ "$EV_PEDANT" = 1 ] ; then - EV_PEDANT=" " - fi - bin/pedant <$TDIR/$TEST.in >$TDIR/$TEST.pedant $EV_PEDANT - if [ -s $TDIR/$TEST.pedant ] ; then - pend - sed 's/^/\t/' <$TDIR/$TEST.pedant >&2 - pstart -e '\t' - fi - fi - case $OUT_TYPE in - file) echo "Output file: $PROBLEM.out" - [ $TASK_TYPE == interactive ] || BOX_EXTRAS="$BOX_EXTRAS -o/dev/null" - ;; - stdio) echo "Output file: " - BOX_EXTRAS="$BOX_EXTRAS -o.stdout" - ;; - none) echo "Output file: " - ;; - *) die "Unknown OUT_TYPE $OUT_TYPE" - ;; - esac - echo "Timeout: $TIME_LIMIT s" - echo "Memory: $MEM_LIMIT KB" - if [ -n "$PRE_RUN_HOOK" ] ; then - echo "Pre-run hook: $PRE_RUN_HOOK" - eval $PRE_RUN_HOOK - fi - echo "Sandbox contents before start:" - ls -Al $BOXDIR -} - -function test-epilog -{ - if [ -n "$POST_RUN_HOOK" ] ; then - echo "Post-run hook: $POST_RUN_HOOK" - eval $POST_RUN_HOOK - fi - echo "Sandbox contents after exit:" - 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 - - if [ -n "$OUTPUT_FILTER" -a "$OUT_TYPE" != none -a -z "$EV_NOFILTER" ] ; then - pcont " " - FILTER=$(expand-var OUTPUT_FILTER) - echo "Output filter command: $FILTER" - mv $TDIR/$TEST.out $TDIR/$TEST.raw - if ! eval $FILTER 2>$TMPDIR/exec.out ; then - cat $TMPDIR/exec.out - MSG=`tail -1 $TMPDIR/exec.out` - if [ -z "$MSG" ] ; then MSG="Filter failed" ; fi - test-result 0 "$MSG" - fi - cat $TMPDIR/exec.out - fi -} - -# Running of test program with file input/output - -function test-run-file -{ - test-prolog - pcont " " - BOXOPTS=$(expand-var TEST_SANDBOX_OPTS) - echo "Sandbox options: $BOXOPTS" - if ! $BOXCMD $BOXOPTS -- ./$PROBLEM 2>$TMPDIR/exec.out ; then - cat $TMPDIR/exec.out - MSG=`tail -1 $TMPDIR/exec.out` - test-result 0 "$MSG" - fi - cat $TMPDIR/exec.out - test-epilog -} - -# Running of interactive test programs - -function test-run-interactive -{ - test-prolog - pcont " " - BOXOPTS=$(expand-var TEST_SANDBOX_OPTS) - echo "Sandbox options: $BOXOPTS" - ICCMD=$(expand-var IA_CHECK) - echo "Interactive checker: $ICCMD" - if ! $HDIR/bin/iwrapper $BOXCMD $BOXOPTS -- ./$PROBLEM @@ $ICCMD 2>$TMPDIR/exec.out ; then - cat $TMPDIR/exec.out - MSG="`head -1 $TMPDIR/exec.out`" - test-result 0 "$MSG" - fi - cat $TMPDIR/exec.out - test-epilog -} - -# "Running" of open-data problems - -function test-run-open-data -{ - [ -f $SDIR/$TEST.out ] || test-result 0 "No solution" - ln $SDIR/$TEST.out $TDIR/$TEST.out -} - -# Syntax checks - -function syntax-check -{ - [ -n "$SYNTAX_CHECK" ] || return 0 - [ -z "$EV_NOCHECK" ] || return 0 - pcont " " - SCHECK=$(expand-var 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 -{ - MSG= - if [ -n "$OUTPUT_CHECK" -a "$OUT_TYPE" != none -a -z "$EV_NOCHECK" ] ; then - pcont " " - [ -f $PDIR/$TEST.out ] && ln $PDIR/$TEST.out $TDIR/$TEST.ok - OCHECK=$(expand-var 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` - fi - 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 >check-log - pend "OK (see 'check-log' for details)" -} - -# Locate output of open data problem, test case TEST -# Beware, SDIR and SRCN can contain spaces and other strange user-supplied characters. - -function open-locate -{ - [ -f $PDIR/$TEST.in ] || die "Unknown test $TEST" - if [ -n "$1" ] ; then - SDIR=`dirname "$1"` - SRCN=`basename "$1"` - else - SRCN=$SDIR/$PROBLEM$TEST.out - fi - [ -f "$SDIR/$SRCN" ] || fatal "Output file $SRCN not found" -} - -# Translation of runtime error codes for various compilers - -function fpc-exit-code -{ - case "$1" in - 200) echo -n "Division by zero" ;; - 201) echo -n "Range check error" ;; - 202) echo -n "Stack overflow" ;; - 203) echo -n "Heap overflow" ;; - 205) echo -n "Floating point overflow" ;; - 215) echo -n "Arithmetic overflow" ;; - 216) echo -n "Segmentation fault" ;; - esac -} - -# A helper function for parsing of command-line overrides of variables - -function parse-cmdline -{ - if [ "${1#*=}" != "$1" ] ; then - local var=${1%%=*} - local val=${1#*=} - eval $var="'$val'" - return 0 - else - return 1 - fi -} diff --git a/eval/Makefile b/eval/Makefile new file mode 100644 index 0000000..23dc796 --- /dev/null +++ b/eval/Makefile @@ -0,0 +1,9 @@ +# Makefile for MO-Eval evaluator +# (c) 2008 Martin Mares + +DIRS+=eval +PROGS+=$(addprefix $(o)/eval/,iwrapper ev) +DATAFILES+=$(o)/eval/libeval.sh + +$(o)/eval/iwrapper: $(o)/eval/iwrapper.o +$(o)/eval/ev: $(s)/eval/ev.sh diff --git a/eval/ev.sh b/eval/ev.sh new file mode 100755 index 0000000..5750f0b --- /dev/null +++ b/eval/ev.sh @@ -0,0 +1,58 @@ +#!/bin/bash +# The Evaluator -- Master Control Script +# (c) 2001--2008 Martin Mares + +set -e +if [ ! -f config -o ! -f lib/libeval.sh ] ; then + echo "Unable to find evaluator files!" + exit 1 +fi +. lib/libeval.sh +. config +while parse-cmdline "$1" ; do + shift +done + +[ -n "$2" -a -z "$4" ] || die "Usage: ev [=] []" +CONTESTANT=$1 +PROBLEM=$2 +dir-init +log-init +. $PDIR/config +box-init + +# Compile the program +if [ $TASK_TYPE != open-data ] ; then + locate-source `if [ -n "$3" ] ; then echo $SDIR/$3 ; fi` + compile || true +fi + +# Initialize the points file +PTSFILE=$TDIR/points +>$PTSFILE + +function test-verdict +{ + if [ $1 == 0 ] ; then + pend "$2" + else + pend "$2 ($1 points)" + fi + echo >>$PTSFILE "$TEST $1 $2" + exit 0 +} + +# Perform the tests +[ -z "$EV_SAMPLE" ] || TESTS="$SAMPLE_TESTS $TESTS" +for TEST in $TESTS ; do + ( + exec >$TDIR/$TEST.log + test-config + pstart "Test $TEST... " + echo "Test $TEST ($POINTS_PER_TEST points)" + test-run + syntax-check + output-check + die "You must never see this message." + ) +done diff --git a/eval/libeval.sh b/eval/libeval.sh new file mode 100644 index 0000000..8bda3e6 --- /dev/null +++ b/eval/libeval.sh @@ -0,0 +1,518 @@ +# The Evaluator -- Shell Function Library +# (c) 2001--2008 Martin Mares + +# General settings +shopt -s dotglob + +# Logging functions. +# File handles used: fd1=log, fd2=progress + +function log-init +{ + exec >>$TDIR/log + HAVE_LOG=1 +} + +function pstart +{ + echo >&2 -n "$@" +} + +function pcont +{ + echo >&2 -n "$@" +} + +function pend +{ + echo >&2 "$@" +} + +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 +} + +function try-ln +{ + ln $1 $2 2>/dev/null || cp $1 $2 +} + +# Expand occurrences of `$var' in a given variable + +function expand-var +{ + eval echo ${!1} +} + +# Given a , override each variable by _ + +function override-vars +{ + local OR V W + declare -a OR + # `${!${1}_@}' does not work, so we have to use eval + OR=($(eval echo '${!'$1'_@}')) + for V in "${OR[@]}" ; do + W=${V##$1_} + eval $W='"$'$V'"' + done +} + +# Sandbox subroutines + +function box-init +{ + pstart "Preparing sandbox... " + if [ -z "$TEST_USER" -o "$TEST_USER" == $EVAL_USER ] ; then + pcont "running locally (INSECURE), " + TEST_USER=$EVAL_USER + BOXDIR=`pwd`/box + BOXCMD=bin/box + mkdir -p box + else + pcont "used account $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="$BOXCMD -c$BOXDIR" + echo "Sandbox directory: $BOXDIR" + echo "Sandbox command: $BOXCMD" + box-clean + pend "OK" +} + +function box-clean +{ + [ -n "$BOXCMD" ] || die "box-init not called" + rm -rf $BOXDIR/* +} + +# Initialization of testing directories + +function dir-init +{ + pstart "Initializing... " + HDIR=. + PDIR=problems/$PROBLEM + SDIR=solutions/$CONTESTANT/$PROBLEM + TDIR=testing/$CONTESTANT/$PROBLEM + TMPDIR=tmp + [ -d $PDIR ] || die "Problem $PROBLEM not known" + [ -d $SDIR ] || fatal "Solution of $PROBLEM not found" + mkdir -p $TDIR $TMPDIR + rm -rf $TDIR $TMPDIR + mkdir -p $TDIR $TMPDIR + cat >$TDIR/log <$TDIR/compile.out ; then + COMPILE_MSG="`cat $TDIR/compile.out`" + pend "FAILED: $COMPILE_MSG" + echo "$COMPILE_MSG" + return 1 + fi + cat $TDIR/compile.out + rm $TDIR/compile.out + if [ -n "$POST_COMPILE_HOOK" ] ; then + echo "Post-compile hook: $POST_COMPILE_HOOK" + eval $POST_COMPILE_HOOK + fi + echo "Compiler output files:" + ls -Al $BOXDIR + if [ ! -f $BOXDIR/$PROBLEM ] ; then + pend "FAILED: Missing executable file" + echo "Missing executable file" + return 1 + fi + EXE=$TDIR/$PROBLEM + cp -a $BOXDIR/$PROBLEM $EXE + echo "Compiled OK, result copied to $EXE" + pend "OK" +} + +# Running of test program according to current task type (returns exit code and TEST_MSG) + +function test-config +{ + [ -f $PDIR/$TEST.config ] && . $PDIR/$TEST.config + override-vars "TEST_$TEST" +} + +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 + + # Translate signal numbers to readable strings + SG=${M#Caught fatal signal } + SG=${SG#Committed suicide by signal } + if [ "$SG" != "$M" ] ; then + SG=`perl -MConfig -e '@s=split / /,$Config{sig_name}; print $s[$ARGV[0]]' $SG` + [ -z "$SG" ] || M="$M (SIG$SG)" + fi + + # Translate runtime errors to readable strings + RE=${M#Exited with error status } + if [ -n "$EXIT_CODE_HOOK" -a "$RE" != "$M" ] ; then + NEWMSG=`$EXIT_CODE_HOOK $RE` + if [ -n "$NEWMSG" ] ; then + M="Runtime error $RE: $NEWMSG" + fi + fi + + echo "Verdict: $M" + echo "Points: $P" + test-verdict $P "$M" +} + +function test-prolog +{ + pcont " " + box-clean + echo "Executable file: $TDIR/$PROBLEM" + if [ ! -x $TDIR/$PROBLEM ] ; then + test-result 0 "Compile error" + fi + cp $TDIR/$PROBLEM $BOXDIR/ + 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)" + try-ln $PDIR/$TEST.in $TDIR/$TEST.in + cp $PDIR/$TEST.in $BOXDIR/$PROBLEM.in + [ $TASK_TYPE == interactive ] || BOX_EXTRAS="$BOX_EXTRAS -i/dev/null" + ;; + stdio) echo "Input file: (from $PDIR/$TEST.in)" + try-ln $PDIR/$TEST.in $TDIR/$TEST.in + cp $PDIR/$TEST.in $BOXDIR/.stdin + BOX_EXTRAS="$BOX_EXTRAS -i.stdin" + ;; + none) echo "Input file: " + ;; + *) die "Unknown IN_TYPE $IN_TYPE" + ;; + esac + if [ -n "$EV_PEDANT" -a $IN_TYPE != none ] ; then + pcont " " + if [ "$EV_PEDANT" = 1 ] ; then + EV_PEDANT=" " + fi + bin/pedant <$TDIR/$TEST.in >$TDIR/$TEST.pedant $EV_PEDANT + if [ -s $TDIR/$TEST.pedant ] ; then + pend + sed 's/^/\t/' <$TDIR/$TEST.pedant >&2 + pstart -e '\t' + fi + fi + case $OUT_TYPE in + file) echo "Output file: $PROBLEM.out" + [ $TASK_TYPE == interactive ] || BOX_EXTRAS="$BOX_EXTRAS -o/dev/null" + ;; + stdio) echo "Output file: " + BOX_EXTRAS="$BOX_EXTRAS -o.stdout" + ;; + none) echo "Output file: " + ;; + *) die "Unknown OUT_TYPE $OUT_TYPE" + ;; + esac + echo "Timeout: $TIME_LIMIT s" + echo "Memory: $MEM_LIMIT KB" + if [ -n "$PRE_RUN_HOOK" ] ; then + echo "Pre-run hook: $PRE_RUN_HOOK" + eval $PRE_RUN_HOOK + fi + echo "Sandbox contents before start:" + ls -Al $BOXDIR +} + +function test-epilog +{ + if [ -n "$POST_RUN_HOOK" ] ; then + echo "Post-run hook: $POST_RUN_HOOK" + eval $POST_RUN_HOOK + fi + echo "Sandbox contents after exit:" + 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 + + if [ -n "$OUTPUT_FILTER" -a "$OUT_TYPE" != none -a -z "$EV_NOFILTER" ] ; then + pcont " " + FILTER=$(expand-var OUTPUT_FILTER) + echo "Output filter command: $FILTER" + mv $TDIR/$TEST.out $TDIR/$TEST.raw + if ! eval $FILTER 2>$TMPDIR/exec.out ; then + cat $TMPDIR/exec.out + MSG=`tail -1 $TMPDIR/exec.out` + if [ -z "$MSG" ] ; then MSG="Filter failed" ; fi + test-result 0 "$MSG" + fi + cat $TMPDIR/exec.out + fi +} + +# Running of test program with file input/output + +function test-run-file +{ + test-prolog + pcont " " + BOXOPTS=$(expand-var TEST_SANDBOX_OPTS) + echo "Sandbox options: $BOXOPTS" + if ! $BOXCMD $BOXOPTS -- ./$PROBLEM 2>$TMPDIR/exec.out ; then + cat $TMPDIR/exec.out + MSG=`tail -1 $TMPDIR/exec.out` + test-result 0 "$MSG" + fi + cat $TMPDIR/exec.out + test-epilog +} + +# Running of interactive test programs + +function test-run-interactive +{ + test-prolog + pcont " " + BOXOPTS=$(expand-var TEST_SANDBOX_OPTS) + echo "Sandbox options: $BOXOPTS" + ICCMD=$(expand-var IA_CHECK) + echo "Interactive checker: $ICCMD" + if ! $HDIR/bin/iwrapper $BOXCMD $BOXOPTS -- ./$PROBLEM @@ $ICCMD 2>$TMPDIR/exec.out ; then + cat $TMPDIR/exec.out + MSG="`head -1 $TMPDIR/exec.out`" + test-result 0 "$MSG" + fi + cat $TMPDIR/exec.out + test-epilog +} + +# "Running" of open-data problems + +function test-run-open-data +{ + [ -f $SDIR/$TEST.out ] || test-result 0 "No solution" + ln $SDIR/$TEST.out $TDIR/$TEST.out +} + +# Syntax checks + +function syntax-check +{ + [ -n "$SYNTAX_CHECK" ] || return 0 + [ -z "$EV_NOCHECK" ] || return 0 + pcont " " + SCHECK=$(expand-var 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 +{ + MSG= + if [ -n "$OUTPUT_CHECK" -a "$OUT_TYPE" != none -a -z "$EV_NOCHECK" ] ; then + pcont " " + [ -f $PDIR/$TEST.out ] && ln $PDIR/$TEST.out $TDIR/$TEST.ok + OCHECK=$(expand-var 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` + fi + 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 >check-log + pend "OK (see 'check-log' for details)" +} + +# Locate output of open data problem, test case TEST +# Beware, SDIR and SRCN can contain spaces and other strange user-supplied characters. + +function open-locate +{ + [ -f $PDIR/$TEST.in ] || die "Unknown test $TEST" + if [ -n "$1" ] ; then + SDIR=`dirname "$1"` + SRCN=`basename "$1"` + else + SRCN=$SDIR/$PROBLEM$TEST.out + fi + [ -f "$SDIR/$SRCN" ] || fatal "Output file $SRCN not found" +} + +# Translation of runtime error codes for various compilers + +function fpc-exit-code +{ + case "$1" in + 200) echo -n "Division by zero" ;; + 201) echo -n "Range check error" ;; + 202) echo -n "Stack overflow" ;; + 203) echo -n "Heap overflow" ;; + 205) echo -n "Floating point overflow" ;; + 215) echo -n "Arithmetic overflow" ;; + 216) echo -n "Segmentation fault" ;; + esac +} + +# A helper function for parsing of command-line overrides of variables + +function parse-cmdline +{ + if [ "${1#*=}" != "$1" ] ; then + local var=${1%%=*} + local val=${1#*=} + eval $var="'$val'" + return 0 + else + return 1 + fi +}