]> mj.ucw.cz Git - eval.git/blob - bin/lib
588cf269b5c4ec98522cc59a5bfaf9f36e5ae487
[eval.git] / bin / lib
1 # The Evaluator -- Shell Function Library
2 # (c) 2001--2004 Martin Mares <mj@ucw.cz>
3
4 # General settings
5 shopt -s dotglob
6
7 # Logging functions.
8 # File handles used: fd1=log, fd2=progress
9
10 function log-init
11 {
12         exec >>$TDIR/log
13         HAVE_LOG=1
14 }
15
16 function pstart
17 {
18         echo >&2 -n "$@"
19 }
20
21 function pcont
22 {
23         echo >&2 -n "$@"
24 }
25
26 function pend
27 {
28         echo >&2 "$@"
29 }
30
31 function die
32 {
33         # Report an internal error
34         echo >&2 "$@"
35         [ -n "$HAVE_LOG" ] && echo "Fatal error: $@"
36         exit 2
37 }
38
39 function fatal
40 {
41         # Report a fatal error in the program being tested
42         echo >&2 "$@"
43         [ -n "$HAVE_LOG" ] && echo "Fatal error: $@"
44         exit 1
45 }
46
47 # Sandbox subroutines
48
49 function box-init
50 {
51         pstart "Preparing sandbox... "
52         if [ -z "$TEST_USER" -o "$TEST_USER" == $EVAL_USER ] ; then
53                 pcont "running locally (INSECURE), "
54                 TEST_USER=$EVAL_USER
55                 BOXDIR=box
56                 BOXCMD=bin/box
57                 mkdir -p box
58         else
59                 pcont "used account $TEST_USER, "
60                 BOXDIR=$MO_ROOT/eval/$TEST_USER
61                 BOXCMD=bin/box-$TEST_USER
62         fi
63         [ -d $BOXDIR -a -f $BOXCMD ] || die "Sandbox set up incorrectly"
64         BOXCMD="$BOXCMD -c$BOXDIR"
65         echo "Sandbox directory: $BOXDIR"
66         echo "Sandbox command: $BOXCMD"
67         box-clean
68         pend "OK"
69 }
70
71 function box-clean
72 {
73         [ -n "$BOXCMD" ] || die "box-init not called"
74         rm -rf $BOXDIR/*
75 }
76
77 # Initialization of testing directories
78
79 function dir-init
80 {
81         pstart "Initializing... "
82         HDIR=.
83         PDIR=problems/$PROBLEM
84         SDIR=solutions/$CONTESTANT/$PROBLEM
85         TDIR=testing/$CONTESTANT/$PROBLEM
86         TMPDIR=tmp
87         [ -d $PDIR ] || die "Problem $PROBLEM not known"
88         [ -d $SDIR ] || fatal "Solution of $PROBLEM not found"
89         mkdir -p $TDIR $TMPDIR
90         rm -rf $TDIR $TMPDIR
91         mkdir -p $TDIR $TMPDIR
92         cat >$TDIR/log <<EOF
93 Testing solution of $PROBLEM by $CONTESTANT
94 Test started at `date`
95 Contestant's solution directory: $SDIR
96 Problem directory: $PDIR
97 Testing directory: $TDIR
98 EOF
99         pend "OK"
100 }
101
102 # Locating source file in SDIR, pass name in SRCN (without path) and extension in SRCEXT
103
104 function locate-source
105 {
106         pstart "Finding source... "
107         SBASE=${1:-$PROBLEM}
108         for a in $EXTENSIONS ; do
109                 if [ -f $SDIR/$SBASE.$a ] ; then
110                         [ -z "$SRCN" ] || die "Multiple source files found: $SDIR/$PROBLEM.$a and $SDIR/$SRCN. Please fix."
111                         SRCN=$SBASE.$a
112                         SRCEXT=$a
113                 fi
114         done
115         [ -n "$SRCN" ] || fatal "NOT FOUND"
116         pend $SRCN
117         echo "Found source file: $SDIR/$SRCN"
118 }
119
120 # Compilation (compile SDIR/SRCN with PDIR/COMP_EXTRAS to EXE=TDIR/PROBLEM)
121
122 function compile
123 {
124         pstart "Compiling... "
125         cp -a $SDIR/$SRCN $TDIR/$SRCN
126         if [ -n "$COMP_EXTRAS" ] ; then
127                 echo "Extras: $COMP_EXTRAS"
128                 for a in $COMP_EXTRAS ; do cp $PDIR/$a $TDIR/ ; done
129         fi
130         box-clean
131         for a in $SRCN $COMP_EXTRAS ; do cp $TDIR/$a $BOXDIR/ ; done
132         SRC=$SRCN
133         EXE=$PROBLEM
134         CCMD=COMP_$SRCEXT
135         CCMD=`eval echo ${!CCMD}`
136         COMP_SANDBOX_OPTS=`eval echo $COMP_SANDBOX_OPTS`
137         echo "Compiler command: $CCMD"
138         echo "Compiler sandbox options: $COMP_SANDBOX_OPTS"
139         eval $COMP_SANDBOX_INIT
140
141         echo "Compiler input files:"
142         ls -Al $BOXDIR
143         echo "Compiler output:"
144         if ! $BOXCMD $COMP_SANDBOX_OPTS -- $CCMD 2>$TDIR/compile.out ; then
145                 COMPILE_MSG="`cat $TDIR/compile.out`"
146                 pend "FAILED: $COMPILE_MSG"
147                 echo "$COMPILE_MSG"
148                 return 1
149         fi
150         cat $TDIR/compile.out
151         rm $TDIR/compile.out
152         echo "Compiler output files:"
153         ls -Al $BOXDIR
154         if [ ! -f $BOXDIR/$PROBLEM ] ; then
155                 pend "FAILED: Missing executable file"
156                 echo "Missing executable file"
157                 return 1
158         fi
159         EXE=$TDIR/$PROBLEM
160         cp -a $BOXDIR/$PROBLEM $EXE
161         echo "Compiled OK, result copied to $EXE"
162         pend "OK"
163 }
164
165 # Running of test program according to current task type (returns exit code and TEST_MSG)
166
167 function test-run
168 {
169         test-run-$TASK_TYPE
170 }
171
172 function test-result
173 {
174         P=$1
175         M=$2
176         if [ -s $TDIR/$TEST.pts ] ; then
177                 P=`cat $TDIR/$TEST.pts`
178                 rm $TDIR/$TEST.pts
179         fi
180         echo "Verdict: $M"
181         echo "Points: $P"
182         test-verdict $P "$M"
183 }
184
185 function test-prolog
186 {
187         pcont "<init> "
188         box-clean
189         echo "Executable file: $TDIR/$PROBLEM"
190         if [ ! -x $TDIR/$PROBLEM ] ; then
191                 test-result 0 "Compile error."
192         fi
193         cp $TDIR/$PROBLEM $BOXDIR/
194         BOX_EXTRAS=
195         IN_TYPE=${IN_TYPE:-$IO_TYPE}
196         OUT_TYPE=${OUT_TYPE:-$IO_TYPE}
197         case $IN_TYPE in
198                 file)   echo "Input file: $PROBLEM.in (from $PDIR/$TEST.in)"
199                         ln $PDIR/$TEST.in $TDIR/$TEST.in
200                         cp $PDIR/$TEST.in $BOXDIR/$PROBLEM.in
201                         BOX_EXTRAS="$BOX_EXTRAS -i/dev/null"
202                         ;;
203                 stdio)  echo "Input file: <stdin> (from $PDIR/$TEST.in)"
204                         ln $PDIR/$TEST.in $TDIR/$TEST.in
205                         cp $PDIR/$TEST.in $BOXDIR/.stdin
206                         BOX_EXTRAS="$BOX_EXTRAS -i.stdin"
207                         ;;
208                 none)   echo "Input file: <none>"
209                         ;;
210                 *)      die "Unknown IN_TYPE $IN_TYPE"
211                         ;;
212         esac
213         case $OUT_TYPE in
214                 file)   echo "Output file: $PROBLEM.out"
215                         BOX_EXTRAS="$BOX_EXTRAS -o/dev/null"
216                         ;;
217                 stdio)  echo "Output file: <stdout>"
218                         BOX_EXTRAS="$BOX_EXTRAS -o.stdout"
219                         ;;
220                 none)   echo "Output file: <none>"
221                         ;;
222                 *)      die "Unknown OUT_TYPE $OUT_TYPE"
223                         ;;
224         esac
225         echo "Timeout: $TIME_LIMIT s"
226         echo "Memory: $MEM_LIMIT KB"
227         eval $SANDBOX_INIT
228         echo "Sandbox contents before start:"
229         ls -Al $BOXDIR
230 }
231
232 function test-epilog
233 {
234         echo "Sandbox contents after exit:"
235         ls -Al $BOXDIR
236         case ${OUT_TYPE:-$IO_TYPE} in
237                 file)   [ -f $BOXDIR/$PROBLEM.out ] || test-result 0 "No output file."
238                         cp $BOXDIR/$PROBLEM.out $TDIR/$TEST.out
239                         ;;
240                 stdio)  [ -f $BOXDIR/.stdout ] || test-result 0 "No output file."
241                         cp $BOXDIR/.stdout $TDIR/$TEST.out
242                         ;;
243         esac
244 }
245
246 # Running of test program with file input/output
247
248 function test-run-file
249 {
250         test-prolog
251         pcont "<run> "
252         BOXOPTS="`eval echo $TEST_SANDBOX_OPTS`$BOX_EXTRAS"
253         echo "Sandbox options: $BOXOPTS"
254         if ! $BOXCMD $BOXOPTS -- ./$PROBLEM 2>$TMPDIR/exec.out ; then
255                 cat $TMPDIR/exec.out
256                 MSG=`tail -1 $TMPDIR/exec.out`
257                 test-result 0 "$MSG"
258         fi
259         cat $TMPDIR/exec.out
260         test-epilog
261 }
262
263 # Running of interactive test programs
264
265 function test-run-interactive
266 {
267         test-prolog
268         pcont "<run> "
269         BOXOPTS="`eval echo $TEST_SANDBOX_OPTS`$BOX_EXTRAS"
270         echo "Sandbox options: $BOXOPTS"
271         ICCMD=`eval echo $IA_CHECK`
272         echo "Interactive checker: $ICCMD"
273         if ! $HDIR/bin/iwrapper $BOXCMD $BOXOPTS -- ./$PROBLEM @@ $ICCMD 2>$TMPDIR/exec.out ; then
274                 cat $TMPDIR/exec.out
275                 MSG="`tail -1 $TMPDIR/exec.out`"
276                 test-result 0 "$MSG"
277         fi
278         cat $TMPDIR/exec.out
279         test-epilog
280 }
281
282 # Syntax checks
283
284 function syntax-check
285 {
286         [ -n "$SYNTAX_CHECK" ] || return 0
287         pcont "<syntax> "
288         SCHECK=`eval echo $SYNTAX_CHECK`
289         echo "Syntax check command: $SCHECK"
290         if ! eval $SCHECK 2>$TMPDIR/exec.out ; then
291                 cat $TMPDIR/exec.out
292                 MSG=`tail -1 $TMPDIR/exec.out`
293                 if [ -z "$MSG" ] ; then MSG="Wrong syntax." ; fi
294                 test-result 0 "$MSG"
295         fi
296         cat $TMPDIR/exec.out
297 }
298
299 # Output checks
300
301 function output-check
302 {
303         [ -n "$OUTPUT_CHECK" ] || return 0
304         pcont "<check> "
305         [ -f $PDIR/$TEST.out ] && ln $PDIR/$TEST.out $TDIR/$TEST.ok
306         OCHECK=`eval echo $OUTPUT_CHECK`
307         echo "Output check command: $OCHECK"
308         if ! eval $OCHECK 2>$TMPDIR/exec.out ; then
309                 cat $TMPDIR/exec.out
310                 MSG=`tail -1 $TMPDIR/exec.out`
311                 if [ -z "$MSG" ] ; then MSG="Wrong answer." ; fi
312                 test-result 0 "$MSG"
313         fi
314         cat $TMPDIR/exec.out
315         MSG=`tail -1 $TMPDIR/exec.out`
316         if [ -z "$MSG" ] ; then MSG="OK" ; fi
317         test-result $POINTS_PER_TEST "$MSG"
318 }
319
320 # Setup of public commands
321
322 function public-setup
323 {
324         HDIR=$MO_ROOT
325         PDIR=$MO_ROOT/problems/$PROBLEM
326         SDIR=.
327         TDIR=~/.test
328         TMPDIR=~/.test
329         [ -d $PDIR ] || die "Unknown problem $PROBLEM"
330
331         pstart "Initializing... "
332         mkdir -p $TDIR
333         rm -rf $TDIR/*
334         BOXDIR=~/.box
335         mkdir -p $BOXDIR
336         rm -rf $BOXDIR/*
337         BOXCMD="$MO_ROOT/bin/box -c$BOXDIR"
338         exec >log
339         pend "OK  (see 'log' for details)"
340 }
341
342 # Locate output of open data problem, test case TEST
343
344 function open-locate
345 {
346         [ -f $PDIR/$TEST.in ] || die "Unknown test $TEST"
347         SRCN=$SDIR/$PROBLEM$TEST.out
348         [ -f $SRCN ] || fatal "Output file $SRCN not found"
349 }