From c64674add29caf7d49806e2fc39152ecc3168443 Mon Sep 17 00:00:00 2001 From: Martin Mares Date: Sun, 18 Nov 2007 19:36:12 +0100 Subject: [PATCH] Imported the unit-test module from libucw. --- judge/tester | 142 +++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 142 insertions(+) create mode 100755 judge/tester diff --git a/judge/tester b/judge/tester new file mode 100755 index 0000000..fd6cce3 --- /dev/null +++ b/judge/tester @@ -0,0 +1,142 @@ +#!/usr/bin/perl +# A simple unit testing script +# (c) 2004--2007 Martin Mares +# (c) 2007 Pavel Charvat + +# Tests in the test file have a syntax similar to mail headers, +# individual test case are separated by blank lines and they can contain +# the following fields: +# +# Name: name of the case (default: sequence number since start of file) +# Run: command to run (default: command from the previous test case) +# This can be an arbitrary shell pipeline, sequences $0 to $9 are +# replaced by file names of In or Out files (see below). +# In: lines to pass to the program as standard input +# Out: lines to expect at the program's standard output +# In: lines to pass to the program as input file +# Out: lines to expect from the program in output file +# Both In and Out can be specified simultaneously if we +# are testing a program which modifies some of its input files. +# Exit: expected exit code of the program (default: 0) + +use Getopt::Long; + +my $verbose = 0; +my $rundir = "."; +GetOptions("verbose!" => \$verbose, + "rundir=s" => \$rundir) + or die "Usage: tester [--verbose] [--rundir=] \n"; + +my @tests = (); +my $tt; +my $append_to; + +while (<>) { + /^#/ && next; + if (/^\s*$/) { + $tt = undef; + $append_to = undef; + } elsif (defined($append_to) && /^\s+(.*)$/) { + $$append_to .= "\n$1"; + } elsif (my ($n,$v) = /^(\w+):\s+(.*)$/) { + if (!$tt) { + $tt = {}; + push @tests, $tt; + } + ($tt->{$n}) && die "$n already defined"; + $tt->{$n} = $v; + $append_to = \($tt->{$n}); + } else { + die "Test script syntax error"; + } +} + +my $i = 0; +my $errors = 0; +my $prev_run = undef; +TEST: foreach $tt (@tests) { + $i++; + my $name = $tt->{'Name'} || $i; + print "Test $name: "; + $run = ($tt->{'Run'} || $prev_run) or die "Don't know what to run"; + $prev_run = $run; + + my @out_files = (); + my @out_checks = (); + my @temps = (); + my $redirs = ""; + + if (defined $tt->{'In'}) { + my $ifi = "tmp/test$i.in"; + open X, ">$rundir/$ifi" or die "Unable to create $ifi"; + print X $tt->{'In'}, "\n"; + close X; + $redirs .= " <$ifi"; + push @temps, $ifi; + } else { + $redirs .= " {'Out'}) { + my $ofi = "tmp/test$i.out"; + unlink "$rundir/$ofi"; + $redirs .= " >$ofi"; + push @temps, $ofi; + push @out_files, $ofi; + push @out_checks, $tt->{'Out'}; + } else { + $redirs .= " >/dev/null"; + } + foreach my $arg (0..9) { + my $f = "tmp/test$i.$arg"; + if (defined $tt->{"Out$arg"}) { + unlink "$rundir/$f"; + push @temps, $f; + push @out_files, $f; + push @out_checks, $tt->{"Out$arg"}; + } + if (defined $tt->{"In$arg"}) { + open X, ">$rundir/$f" or die "Unable to create $f"; + print X $tt->{"In$arg"}, "\n"; + close X; + push @temps, $f; + } + } + $run =~ s/\$(\d)/tmp\/test$i.$1/g; + print "(running $run) " if $verbose; + system "cd $rundir && ( $run ) $redirs"; + if ($? % 256) { + print "FAILED with status code $?\n"; + $errors++; + next; + } + my $ec = $? / 256; + my $expect_ec = $tt->{'Exit'} || 0; + if ($ec != $expect_ec) { + print "FAILED: unexpected exit code $ec\n"; + $errors++; + next; + } + + for (my $i=0; $i<=$#out_files; $i++) { + my $ofi = $out_files[$i]; + open X, "<$rundir/$ofi" or die "Unable to read $ofi"; + my $out; + { + local $/ = undef; + $out = ; + } + close X; + if ($out ne $out_checks[$i] . "\n") { + print "FAILED (see $ofi)\n"; + $errors++; + next TEST; + } + } + + foreach my $f (@temps) { + unlink "$rundir/$f"; + } + print "OK\n"; +} + +exit !!$errors; -- 2.39.5