blob: a45ce1a94f63168024f47f98d1589972cf3119f9 [file] [log] [blame]
njn25e49d8e72002-09-23 09:36:25 +00001#! /usr/bin/perl -w
njna217f3d2002-09-27 08:26:27 +00002##--------------------------------------------------------------------##
3##--- Valgrind regression testing script vg_regtest ---##
4##--------------------------------------------------------------------##
5# usage: vg_regtest [options] <dirs | files>
njn25e49d8e72002-09-23 09:36:25 +00006#
njna217f3d2002-09-27 08:26:27 +00007# Options:
8# --stable: use stable-branch stderr results (*.stderr.exp.hd)
9# --dev: use dev-branch stderr results (*.stderr.exp - default)
10# --all: run tests in all subdirs
11# --valgrind: valgrind to use. Default is in ./inst/bin/valgrind
12#
13# You can specify individual files to test, or whole directories, or both.
14# The stable-branch/dev-branch distinction allows slight differences in stderr
15# results.
njn25e49d8e72002-09-23 09:36:25 +000016#
17# Each test is defined in a file <test>.vgtest, containing one or more of the
njna217f3d2002-09-27 08:26:27 +000018# following lines, in any order:
njn25e49d8e72002-09-23 09:36:25 +000019# - prog: <prog to run> (compulsory)
20# - args: <args for prog> (default: none)
21# - vgopts: <Valgrind options> (default: none)
njna217f3d2002-09-27 08:26:27 +000022# - vgopts.st: <options, --stable only> (default: none)
23# - vgopts.dev: <options, --dev only> (default: none)
njn25e49d8e72002-09-23 09:36:25 +000024# - stdout_filter: <filter to run stdout through> (default: none)
njna217f3d2002-09-27 08:26:27 +000025# - stderr_filter: <filter to run stderr through> (default: ./filter_stderr)
njn25e49d8e72002-09-23 09:36:25 +000026#
njna217f3d2002-09-27 08:26:27 +000027# Note that filters are necessary for stderr results to filter out things that
28# always change, eg. process id numbers.
njn25e49d8e72002-09-23 09:36:25 +000029#
njna217f3d2002-09-27 08:26:27 +000030# Expected stdout (filtered) is kept in <test>.stdout.exp. It can be missing
31# if it would be empty.
32#
33# Expected stderr (filtered) is kept in <test>.stderr.exp for --dev, and
34# <test>.stderr.exp.hd for --stable (silly ".hd" extension for historical
35# reasons).
njn25e49d8e72002-09-23 09:36:25 +000036#
37# If results don't match, the output can be found in <test>.std<strm>.out,
38# and the diff between expected and actual in <test>.std<strm>.diff.
39#
njna217f3d2002-09-27 08:26:27 +000040# Notes on adding regression tests for a new skin are in
41# coregrind/docs/skins.html.
njn25e49d8e72002-09-23 09:36:25 +000042#----------------------------------------------------------------------------
43
44use strict;
45
46#----------------------------------------------------------------------------
47# Global vars
48#----------------------------------------------------------------------------
njna217f3d2002-09-27 08:26:27 +000049my $usage="vg_regtest [--stable|--dev, --all, --valgrind]\n";
njn25e49d8e72002-09-23 09:36:25 +000050
51my $tmp="vg_regtest.tmp.$$";
52
53# Test variables
54my $vgopts; # valgrind options
55my $prog; # test prog
56my $args; # test prog args
57my $stdout_filter; # filter program to run stdout results file through
58my $stderr_filter; # filter program to run stderr results file through
59
60my @failures; # List of failed tests
61
njna217f3d2002-09-27 08:26:27 +000062my $exp = ""; # --dev is default
njn25e49d8e72002-09-23 09:36:25 +000063
njn25cac76cb2002-09-23 11:21:57 +000064# Assumes we're in valgrind/
njna217f3d2002-09-27 08:26:27 +000065my $valgrind = "inst/bin/valgrind";
njn25e49d8e72002-09-23 09:36:25 +000066
67chomp(my $tests_dir = `pwd`);
68
69# default filter is the one named "filter_stderr" in the test's directory
70my $default_stderr_filter = "filter_stderr";
71
72
73#----------------------------------------------------------------------------
74# Process command line, setup
75#----------------------------------------------------------------------------
76
77# If $prog is a relative path, it prepends $dir to it. Useful for two reasons:
78#
79# 1. Can prepend "." onto programs to avoid trouble with users who don't have
80# "." in their path (by making $dir = ".")
81# 2. Can prepend the current dir to make the command absolute to avoid
82# subsequent trouble when we change directories.
83#
84# Also checks the program exists and is executable.
85sub validate_program ($$)
86{
87 my ($dir, $prog) = @_;
88
89 # If absolute path, leave it alone. If relative, make it
90 # absolute -- by prepending current dir -- so we can change
91 # dirs and still use it.
92 $prog = "$dir/$prog" if ($prog !~ /^\//);
93 (-f $prog) or die "`$prog' not found or not a file ($dir)\n";
94 (-x $prog) or die "`$prog' not found or not executable ($dir)\n";
95
96 return $prog;
97}
98
99sub process_command_line()
100{
101 my $alldirs = 0;
102 my @fs;
103
104 for my $arg (@ARGV) {
105 if ($arg =~ /^-/) {
njna217f3d2002-09-27 08:26:27 +0000106 if ($arg =~ /^--stable$/) {
njn25e49d8e72002-09-23 09:36:25 +0000107 $exp = ".hd";
njna217f3d2002-09-27 08:26:27 +0000108 } elsif ($arg =~ /^--dev$/) {
njn25e49d8e72002-09-23 09:36:25 +0000109 $exp = "";
110 } elsif ($arg =~ /^--all$/) {
111 $alldirs = 1;
112 } elsif ($arg =~ /^--valgrind=(.*)$/) {
113 $valgrind = $1;
114 } else {
115 die $usage;
116 }
117 } else {
118 push(@fs, $arg);
119 }
120 }
121 $valgrind = validate_program($tests_dir, $valgrind);
122
123 if ($alldirs) {
124 @fs = ();
125 foreach my $f (glob "*") {
126 push(@fs, $f) if (-d $f);
127 }
128 }
129
130 (0 != @fs) or die "No test files or directories specified\n";
131
132 return @fs;
133}
134
135#----------------------------------------------------------------------------
136# Read a .vgtest file
137#----------------------------------------------------------------------------
138sub read_vgtest_file($)
139{
140 my ($f) = @_;
141
142 # Defaults.
143 ($vgopts, $prog, $args, $stdout_filter, $stderr_filter) =
144 ("", undef, "", undef, undef);
145
146 # Every test directory must have a "filter_stderr"
147 $stderr_filter = validate_program(".", $default_stderr_filter);
148
149 open(INPUTFILE, "< $f") || die "File $f not openable\n";
150
151 while (my $line = <INPUTFILE>) {
152 if ($line =~ /^\s*vgopts:\s*(.*)$/) {
153 $vgopts = $1;
154 } elsif ($line =~ /^\s*prog:\s*(.*)$/) {
155 $prog = validate_program(".", $1);
156 } elsif ($line =~ /^\s*args:\s*(.*)$/) {
157 $args = $1;
njna217f3d2002-09-27 08:26:27 +0000158 } elsif ($line =~ /^\s*vgopts\.st:\s*(.*)$/) {
njn25e49d8e72002-09-23 09:36:25 +0000159 $vgopts = $1 if ($exp eq ".hd");
njna217f3d2002-09-27 08:26:27 +0000160 } elsif ($line =~ /^\s*vgopts\.dev:\s*(.*)$/) {
njn25e49d8e72002-09-23 09:36:25 +0000161 $vgopts = $1 if ($exp eq "");
162 } elsif ($line =~ /^\s*stdout_filter:\s*(.*)$/) {
163 $stdout_filter = validate_program(".", $1);
164 } elsif ($line =~ /^\s*stderr_filter:\s*(.*)$/) {
165 $stderr_filter = validate_program(".", $1);
166 } else {
167 die "Bad line in $f: $line\n";
168 }
169 }
170 close(INPUTFILE);
171
172 if (!defined $prog) {
173 die "no `prog:' line in `$f'\n";
174 }
175}
176
177#----------------------------------------------------------------------------
178# Do one test
179#----------------------------------------------------------------------------
180# Since most of the program time is spent in system() calls, need this to
181# propagate a Ctrl-C enabling us to quit.
182sub mysystem($)
183{
184 (system($_[0]) != 2) or exit 1; # 2 is SIGINT
185}
186
njn25cac76cb2002-09-23 11:21:57 +0000187# from a directory name like "/foo/cachesim/tests/" determine the skin name
188sub determine_skin()
189{
190 my $dir = `pwd`;
191 $dir =~ /.*\/([^\/]+)\/tests.*/; # foo/skin_name/tests/foo
192 return $1;
193}
194
njn25e49d8e72002-09-23 09:36:25 +0000195sub do_one_test($$)
196{
197 my ($dir, $vgtest) = @_;
198 $vgtest =~ /^(.*)\.vgtest/;
199 my $name = $1;
200 my $fullname = "$dir/$name";
201
202 read_vgtest_file($vgtest);
203
204 printf("%-30s valgrind $vgopts $prog $args\n", "$fullname:");
205
njna217f3d2002-09-27 08:26:27 +0000206 # If --dev, pass the appropriate --skin option for the directory (can be
207 # overridden by an "args:" or "args.dev:" line, though)
njn25e49d8e72002-09-23 09:36:25 +0000208 if ($exp eq ".hd") {
209 mysystem("$valgrind $vgopts $prog $args > $name.stdout.out 2> $name.stderr.out");
210 } else {
njn25cac76cb2002-09-23 11:21:57 +0000211 my $skin=determine_skin();
212 mysystem("$valgrind --skin=$skin $vgopts $prog $args > $name.stdout.out 2> $name.stderr.out");
njn25e49d8e72002-09-23 09:36:25 +0000213 }
214
215 if (defined $stdout_filter) {
216 mysystem("$stdout_filter < $name.stdout.out > $tmp");
217 rename($tmp, "$name.stdout.out");
218 }
219
220 mysystem("$stderr_filter < $name.stderr.out > $tmp");
221 rename($tmp, "$name.stderr.out");
222
223 # If stdout expected empty, .exp file might be missing so diff with
224 # /dev/null
225 my $stdout_exp = ( -r "$name.stdout.exp"
226 ? "$name.stdout.exp"
227 : "/dev/null" );
228
njna217f3d2002-09-27 08:26:27 +0000229 # If stable-branch and dev-branch have the same expected stderr output,
njn25e49d8e72002-09-23 09:36:25 +0000230 # foo.stderr.exp.hd might be missing, so use foo.stderr.exp instead if
njna217f3d2002-09-27 08:26:27 +0000231 # --stable is true.
njn25e49d8e72002-09-23 09:36:25 +0000232 my $stderr_exp = "$name.stderr.exp$exp";
233 if ($exp eq ".hd" && not -r $stderr_exp) {
234 $stderr_exp = "$name.stderr.exp";
235 }
236 (-r $stderr_exp) or die "Could not read `$stderr_exp'\n";
237
238 mysystem("diff -C0 $stdout_exp $name.stdout.out > $name.stdout.diff");
239 mysystem("diff -C0 $stderr_exp $name.stderr.out > $name.stderr.diff");
240
241 for my $ext ("stdout", "stderr") {
242 if (-s "$name.$ext.diff") {
243 print "*** $fullname failed ($ext) ***\n";
244 push(@failures, sprintf("%-30s $ext", "$fullname"));
245 } else {
246 unlink("$name.$ext.out", "$name.$ext.diff");
247 }
248 }
249}
250
251#----------------------------------------------------------------------------
njn25cac76cb2002-09-23 11:21:57 +0000252# Test one directory (and any subdirs)
njn25e49d8e72002-09-23 09:36:25 +0000253#----------------------------------------------------------------------------
njn25cac76cb2002-09-23 11:21:57 +0000254sub test_one_dir($); # forward declaration
255
njn25e49d8e72002-09-23 09:36:25 +0000256sub test_one_dir($)
257{
258 my ($dir) = @_;
259 $dir =~ s/\/$//; # trim a trailing '/'
260
njn25cac76cb2002-09-23 11:21:57 +0000261 if ($dir =~ /^(CVS|docs)$/) { return; } # ignore CVS/ and docs/ dirs
262
njn25e49d8e72002-09-23 09:36:25 +0000263 print "-- Running tests in $dir ----------------------------------\n";
264 chdir($dir) or die "Could not change into $dir\n";
265
njn25cac76cb2002-09-23 11:21:57 +0000266# my @vgtests = glob "*\.vgtest";
267 my @fs = glob "*";
268
269 foreach my $f (@fs) {
270 if (-d $f) {
271 test_one_dir($f);
272 } elsif ($f =~ /\.vgtest$/) {
273 do_one_test($dir, $f);
274 }
njn25e49d8e72002-09-23 09:36:25 +0000275 }
njn25cac76cb2002-09-23 11:21:57 +0000276
277 print "-- Finished tests in $dir ----------------------------------\n";
njn25e49d8e72002-09-23 09:36:25 +0000278 chdir("..");
njn25e49d8e72002-09-23 09:36:25 +0000279}
280
281#----------------------------------------------------------------------------
282# Summarise results
283#----------------------------------------------------------------------------
284sub summarise_results
285{
njn25cac76cb2002-09-23 11:21:57 +0000286 print "\n== Failed tests ===============================\n";
njn25e49d8e72002-09-23 09:36:25 +0000287 if (0 == @failures) {
288 print " (none)\n";
289 } else {
290 foreach my $failure (@failures) {
291 print "$failure\n";
292 }
293 }
294}
295
296#----------------------------------------------------------------------------
297# main(), sort of
298#----------------------------------------------------------------------------
299
300# undefine $VALGRIND_OPTS
301if ( exists $ENV{VALGRIND_OPTS} ) {
302 undef $ENV{VALGRIND_OPTS};
303}
304
305my @fs = process_command_line();
306foreach my $f (@fs) {
307 if (-d $f) {
308 test_one_dir($f);
309 } else {
310 # Allow the .vgtest suffix to be given or omitted
311 if ($f =~ /.vgtest$/ && -r $f) {
312 # do nothing
313 } elsif (-r "$f.vgtest") {
314 $f = "$f.vgtest";
315 } else {
316 die "`$f' neither a directory nor a readable test file/name\n"
317 }
318 my $dir = `dirname $f`; chomp $dir;
319 my $file = `basename $f`; chomp $file;
320 chdir($dir) or die "Could not change into $dir\n";
321 do_one_test($dir, $file);
322 chdir($tests_dir);
323 }
324}
325summarise_results();
326
327