blob: 948b7eef3a6db94309210ef68c5fa030cafdd1d9 [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##--------------------------------------------------------------------##
njnc2e7f482002-09-27 08:44:17 +00005
njnc9539842002-10-02 13:26:35 +00006# This file is part of Valgrind, an extensible x86 protected-mode
7# emulator for monitoring program execution on x86-Unixes.
njnc2e7f482002-09-27 08:44:17 +00008#
9# Copyright (C) 2002 Nicholas Nethercote
10# njn25@cam.ac.uk
11#
12# This program is free software; you can redistribute it and/or
13# modify it under the terms of the GNU General Public License as
14# published by the Free Software Foundation; either version 2 of the
15# License, or (at your option) any later version.
16#
17# This program is distributed in the hope that it will be useful, but
18# WITHOUT ANY WARRANTY; without even the implied warranty of
19# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
20# General Public License for more details.
21#
22# You should have received a copy of the GNU General Public License
23# along with this program; if not, write to the Free Software
24# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
25# 02111-1307, USA.
26#
27# The GNU General Public License is contained in the file COPYING.
28
29#----------------------------------------------------------------------------
njna217f3d2002-09-27 08:26:27 +000030# usage: vg_regtest [options] <dirs | files>
njn25e49d8e72002-09-23 09:36:25 +000031#
njna217f3d2002-09-27 08:26:27 +000032# Options:
33# --stable: use stable-branch stderr results (*.stderr.exp.hd)
34# --dev: use dev-branch stderr results (*.stderr.exp - default)
35# --all: run tests in all subdirs
njnc2e7f482002-09-27 08:44:17 +000036# --valgrind: valgrind to use. Default is one built from this source tree.
njna217f3d2002-09-27 08:26:27 +000037#
njn4ba5a792002-09-30 10:23:54 +000038# The easiest way is to run all tests in valgrind/ with (assuming you installed
39# in $PREFIX):
40#
41# $PREFIX/bin/vg_regtest --all
42#
njna217f3d2002-09-27 08:26:27 +000043# You can specify individual files to test, or whole directories, or both.
44# The stable-branch/dev-branch distinction allows slight differences in stderr
45# results.
njn25e49d8e72002-09-23 09:36:25 +000046#
47# Each test is defined in a file <test>.vgtest, containing one or more of the
njna217f3d2002-09-27 08:26:27 +000048# following lines, in any order:
njn25e49d8e72002-09-23 09:36:25 +000049# - prog: <prog to run> (compulsory)
50# - args: <args for prog> (default: none)
51# - vgopts: <Valgrind options> (default: none)
njna217f3d2002-09-27 08:26:27 +000052# - vgopts.st: <options, --stable only> (default: none)
53# - vgopts.dev: <options, --dev only> (default: none)
njn25e49d8e72002-09-23 09:36:25 +000054# - stdout_filter: <filter to run stdout through> (default: none)
njna217f3d2002-09-27 08:26:27 +000055# - stderr_filter: <filter to run stderr through> (default: ./filter_stderr)
njn25e49d8e72002-09-23 09:36:25 +000056#
njna217f3d2002-09-27 08:26:27 +000057# Note that filters are necessary for stderr results to filter out things that
58# always change, eg. process id numbers.
njn25e49d8e72002-09-23 09:36:25 +000059#
njna217f3d2002-09-27 08:26:27 +000060# Expected stdout (filtered) is kept in <test>.stdout.exp. It can be missing
61# if it would be empty.
62#
63# Expected stderr (filtered) is kept in <test>.stderr.exp for --dev, and
64# <test>.stderr.exp.hd for --stable (silly ".hd" extension for historical
65# reasons).
njn25e49d8e72002-09-23 09:36:25 +000066#
67# If results don't match, the output can be found in <test>.std<strm>.out,
68# and the diff between expected and actual in <test>.std<strm>.diff.
69#
njna217f3d2002-09-27 08:26:27 +000070# Notes on adding regression tests for a new skin are in
71# coregrind/docs/skins.html.
njn25e49d8e72002-09-23 09:36:25 +000072#----------------------------------------------------------------------------
73
74use strict;
75
76#----------------------------------------------------------------------------
77# Global vars
78#----------------------------------------------------------------------------
njna217f3d2002-09-27 08:26:27 +000079my $usage="vg_regtest [--stable|--dev, --all, --valgrind]\n";
njn25e49d8e72002-09-23 09:36:25 +000080
81my $tmp="vg_regtest.tmp.$$";
82
83# Test variables
84my $vgopts; # valgrind options
85my $prog; # test prog
86my $args; # test prog args
87my $stdout_filter; # filter program to run stdout results file through
88my $stderr_filter; # filter program to run stderr results file through
89
90my @failures; # List of failed tests
91
njna217f3d2002-09-27 08:26:27 +000092my $exp = ""; # --dev is default
njn25e49d8e72002-09-23 09:36:25 +000093
njnc2e7f482002-09-27 08:44:17 +000094# Default valgrind to use is this build tree's one
95my $prefix="@prefix@";
96my $exec_prefix="@exec_prefix@";
97my $valgrind = "@bindir@/valgrind";
njn25e49d8e72002-09-23 09:36:25 +000098
99chomp(my $tests_dir = `pwd`);
100
101# default filter is the one named "filter_stderr" in the test's directory
102my $default_stderr_filter = "filter_stderr";
103
104
105#----------------------------------------------------------------------------
106# Process command line, setup
107#----------------------------------------------------------------------------
108
109# If $prog is a relative path, it prepends $dir to it. Useful for two reasons:
110#
111# 1. Can prepend "." onto programs to avoid trouble with users who don't have
112# "." in their path (by making $dir = ".")
113# 2. Can prepend the current dir to make the command absolute to avoid
114# subsequent trouble when we change directories.
115#
116# Also checks the program exists and is executable.
117sub validate_program ($$)
118{
119 my ($dir, $prog) = @_;
120
121 # If absolute path, leave it alone. If relative, make it
122 # absolute -- by prepending current dir -- so we can change
123 # dirs and still use it.
124 $prog = "$dir/$prog" if ($prog !~ /^\//);
125 (-f $prog) or die "`$prog' not found or not a file ($dir)\n";
126 (-x $prog) or die "`$prog' not found or not executable ($dir)\n";
127
128 return $prog;
129}
130
131sub process_command_line()
132{
133 my $alldirs = 0;
134 my @fs;
135
136 for my $arg (@ARGV) {
137 if ($arg =~ /^-/) {
njna217f3d2002-09-27 08:26:27 +0000138 if ($arg =~ /^--stable$/) {
njn25e49d8e72002-09-23 09:36:25 +0000139 $exp = ".hd";
njna217f3d2002-09-27 08:26:27 +0000140 } elsif ($arg =~ /^--dev$/) {
njn25e49d8e72002-09-23 09:36:25 +0000141 $exp = "";
142 } elsif ($arg =~ /^--all$/) {
143 $alldirs = 1;
144 } elsif ($arg =~ /^--valgrind=(.*)$/) {
145 $valgrind = $1;
146 } else {
147 die $usage;
148 }
149 } else {
150 push(@fs, $arg);
151 }
152 }
153 $valgrind = validate_program($tests_dir, $valgrind);
154
155 if ($alldirs) {
156 @fs = ();
157 foreach my $f (glob "*") {
158 push(@fs, $f) if (-d $f);
159 }
160 }
161
162 (0 != @fs) or die "No test files or directories specified\n";
163
164 return @fs;
165}
166
167#----------------------------------------------------------------------------
168# Read a .vgtest file
169#----------------------------------------------------------------------------
170sub read_vgtest_file($)
171{
172 my ($f) = @_;
173
174 # Defaults.
175 ($vgopts, $prog, $args, $stdout_filter, $stderr_filter) =
176 ("", undef, "", undef, undef);
177
178 # Every test directory must have a "filter_stderr"
179 $stderr_filter = validate_program(".", $default_stderr_filter);
180
181 open(INPUTFILE, "< $f") || die "File $f not openable\n";
182
183 while (my $line = <INPUTFILE>) {
184 if ($line =~ /^\s*vgopts:\s*(.*)$/) {
185 $vgopts = $1;
186 } elsif ($line =~ /^\s*prog:\s*(.*)$/) {
187 $prog = validate_program(".", $1);
188 } elsif ($line =~ /^\s*args:\s*(.*)$/) {
189 $args = $1;
njna217f3d2002-09-27 08:26:27 +0000190 } elsif ($line =~ /^\s*vgopts\.st:\s*(.*)$/) {
njn25e49d8e72002-09-23 09:36:25 +0000191 $vgopts = $1 if ($exp eq ".hd");
njna217f3d2002-09-27 08:26:27 +0000192 } elsif ($line =~ /^\s*vgopts\.dev:\s*(.*)$/) {
njn25e49d8e72002-09-23 09:36:25 +0000193 $vgopts = $1 if ($exp eq "");
194 } elsif ($line =~ /^\s*stdout_filter:\s*(.*)$/) {
195 $stdout_filter = validate_program(".", $1);
196 } elsif ($line =~ /^\s*stderr_filter:\s*(.*)$/) {
197 $stderr_filter = validate_program(".", $1);
198 } else {
199 die "Bad line in $f: $line\n";
200 }
201 }
202 close(INPUTFILE);
203
204 if (!defined $prog) {
205 die "no `prog:' line in `$f'\n";
206 }
207}
208
209#----------------------------------------------------------------------------
210# Do one test
211#----------------------------------------------------------------------------
212# Since most of the program time is spent in system() calls, need this to
213# propagate a Ctrl-C enabling us to quit.
214sub mysystem($)
215{
216 (system($_[0]) != 2) or exit 1; # 2 is SIGINT
217}
218
njn25cac76cb2002-09-23 11:21:57 +0000219# from a directory name like "/foo/cachesim/tests/" determine the skin name
220sub determine_skin()
221{
222 my $dir = `pwd`;
223 $dir =~ /.*\/([^\/]+)\/tests.*/; # foo/skin_name/tests/foo
224 return $1;
225}
226
njn25e49d8e72002-09-23 09:36:25 +0000227sub do_one_test($$)
228{
229 my ($dir, $vgtest) = @_;
230 $vgtest =~ /^(.*)\.vgtest/;
231 my $name = $1;
232 my $fullname = "$dir/$name";
233
234 read_vgtest_file($vgtest);
235
236 printf("%-30s valgrind $vgopts $prog $args\n", "$fullname:");
237
njna217f3d2002-09-27 08:26:27 +0000238 # If --dev, pass the appropriate --skin option for the directory (can be
239 # overridden by an "args:" or "args.dev:" line, though)
njn25e49d8e72002-09-23 09:36:25 +0000240 if ($exp eq ".hd") {
241 mysystem("$valgrind $vgopts $prog $args > $name.stdout.out 2> $name.stderr.out");
242 } else {
njn25cac76cb2002-09-23 11:21:57 +0000243 my $skin=determine_skin();
244 mysystem("$valgrind --skin=$skin $vgopts $prog $args > $name.stdout.out 2> $name.stderr.out");
njn25e49d8e72002-09-23 09:36:25 +0000245 }
246
247 if (defined $stdout_filter) {
248 mysystem("$stdout_filter < $name.stdout.out > $tmp");
249 rename($tmp, "$name.stdout.out");
250 }
251
252 mysystem("$stderr_filter < $name.stderr.out > $tmp");
253 rename($tmp, "$name.stderr.out");
254
255 # If stdout expected empty, .exp file might be missing so diff with
256 # /dev/null
257 my $stdout_exp = ( -r "$name.stdout.exp"
258 ? "$name.stdout.exp"
259 : "/dev/null" );
260
njna217f3d2002-09-27 08:26:27 +0000261 # If stable-branch and dev-branch have the same expected stderr output,
njn25e49d8e72002-09-23 09:36:25 +0000262 # foo.stderr.exp.hd might be missing, so use foo.stderr.exp instead if
njna217f3d2002-09-27 08:26:27 +0000263 # --stable is true.
njn25e49d8e72002-09-23 09:36:25 +0000264 my $stderr_exp = "$name.stderr.exp$exp";
265 if ($exp eq ".hd" && not -r $stderr_exp) {
266 $stderr_exp = "$name.stderr.exp";
267 }
268 (-r $stderr_exp) or die "Could not read `$stderr_exp'\n";
269
270 mysystem("diff -C0 $stdout_exp $name.stdout.out > $name.stdout.diff");
271 mysystem("diff -C0 $stderr_exp $name.stderr.out > $name.stderr.diff");
272
273 for my $ext ("stdout", "stderr") {
274 if (-s "$name.$ext.diff") {
275 print "*** $fullname failed ($ext) ***\n";
276 push(@failures, sprintf("%-30s $ext", "$fullname"));
277 } else {
278 unlink("$name.$ext.out", "$name.$ext.diff");
279 }
280 }
281}
282
283#----------------------------------------------------------------------------
njn25cac76cb2002-09-23 11:21:57 +0000284# Test one directory (and any subdirs)
njn25e49d8e72002-09-23 09:36:25 +0000285#----------------------------------------------------------------------------
njn25cac76cb2002-09-23 11:21:57 +0000286sub test_one_dir($); # forward declaration
287
njn25e49d8e72002-09-23 09:36:25 +0000288sub test_one_dir($)
289{
290 my ($dir) = @_;
291 $dir =~ s/\/$//; # trim a trailing '/'
292
njn25cac76cb2002-09-23 11:21:57 +0000293 if ($dir =~ /^(CVS|docs)$/) { return; } # ignore CVS/ and docs/ dirs
294
njn25e49d8e72002-09-23 09:36:25 +0000295 print "-- Running tests in $dir ----------------------------------\n";
296 chdir($dir) or die "Could not change into $dir\n";
297
njn25cac76cb2002-09-23 11:21:57 +0000298# my @vgtests = glob "*\.vgtest";
299 my @fs = glob "*";
300
301 foreach my $f (@fs) {
302 if (-d $f) {
303 test_one_dir($f);
304 } elsif ($f =~ /\.vgtest$/) {
305 do_one_test($dir, $f);
306 }
njn25e49d8e72002-09-23 09:36:25 +0000307 }
njn25cac76cb2002-09-23 11:21:57 +0000308
309 print "-- Finished tests in $dir ----------------------------------\n";
njn25e49d8e72002-09-23 09:36:25 +0000310 chdir("..");
njn25e49d8e72002-09-23 09:36:25 +0000311}
312
313#----------------------------------------------------------------------------
314# Summarise results
315#----------------------------------------------------------------------------
316sub summarise_results
317{
njn25cac76cb2002-09-23 11:21:57 +0000318 print "\n== Failed tests ===============================\n";
njn25e49d8e72002-09-23 09:36:25 +0000319 if (0 == @failures) {
320 print " (none)\n";
321 } else {
322 foreach my $failure (@failures) {
323 print "$failure\n";
324 }
325 }
326}
327
328#----------------------------------------------------------------------------
329# main(), sort of
330#----------------------------------------------------------------------------
331
332# undefine $VALGRIND_OPTS
333if ( exists $ENV{VALGRIND_OPTS} ) {
334 undef $ENV{VALGRIND_OPTS};
335}
336
337my @fs = process_command_line();
338foreach my $f (@fs) {
339 if (-d $f) {
340 test_one_dir($f);
341 } else {
342 # Allow the .vgtest suffix to be given or omitted
343 if ($f =~ /.vgtest$/ && -r $f) {
344 # do nothing
345 } elsif (-r "$f.vgtest") {
346 $f = "$f.vgtest";
347 } else {
348 die "`$f' neither a directory nor a readable test file/name\n"
349 }
350 my $dir = `dirname $f`; chomp $dir;
351 my $file = `basename $f`; chomp $file;
352 chdir($dir) or die "Could not change into $dir\n";
353 do_one_test($dir, $file);
354 chdir($tests_dir);
355 }
356}
357summarise_results();
358
njnc2e7f482002-09-27 08:44:17 +0000359##--------------------------------------------------------------------##
360##--- end vg_regtest ---##
361##--------------------------------------------------------------------##