improve 'frame' handling in debugger
[p5sagit/p5-mst-13.2.git] / lib / Test / Harness.pm
CommitLineData
a0d0e21e 1package Test::Harness;
2
b876d4a6 3BEGIN {require 5.002;}
a0d0e21e 4use Exporter;
5use Benchmark;
4633a7c4 6use Config;
6c31b336 7use FileHandle;
760ac839 8use strict;
9
10use vars qw($VERSION $verbose $switches $have_devel_corestack $curtest
11 @ISA @EXPORT @EXPORT_OK);
c0ee6f5c 12$have_devel_corestack = 0;
4633a7c4 13
7b13a3f5 14$VERSION = "1.1601";
4633a7c4 15
c07a80fd 16@ISA=('Exporter');
cb1a09d0 17@EXPORT= qw(&runtests);
a0d0e21e 18@EXPORT_OK= qw($verbose $switches);
19
760ac839 20format STDOUT_TOP =
21Failed Test Status Wstat Total Fail Failed List of failed
fb73857a 22-------------------------------------------------------------------------------
760ac839 23.
24
25format STDOUT =
fb73857a 26@<<<<<<<<<<<<<< @>> @>>>> @>>>> @>>> ^##.##% ^<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
760ac839 27{ $curtest->{name},
28 $curtest->{estat},
29 $curtest->{wstat},
30 $curtest->{max},
31 $curtest->{failed},
32 $curtest->{percent},
33 $curtest->{canon}
34}
fb73857a 35~~ ^<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
36 $curtest->{canon}
760ac839 37.
38
c07a80fd 39
6c31b336 40$verbose = 0;
41$switches = "-w";
a0d0e21e 42
43sub runtests {
44 my(@tests) = @_;
45 local($|) = 1;
7b13a3f5 46 my($test,$te,$ok,$next,$max,$pct,$totok,$totbonus,@failed,%failedtests);
6c31b336 47 my $totmax = 0;
48 my $files = 0;
a0d0e21e 49 my $bad = 0;
50 my $good = 0;
51 my $total = @tests;
774d564b 52
53 # pass -I flags to children
81ff29e3 54 my $old5lib = $ENV{PERL5LIB};
774d564b 55 local($ENV{'PERL5LIB'}) = join($Config{path_sep}, @INC);
56
a5077310 57 if ($^O eq 'VMS') { $switches =~ s/-(\S*[A-Z]\S*)/"-$1"/g }
a0d0e21e 58
59 my $t_start = new Benchmark;
60 while ($test = shift(@tests)) {
c07a80fd 61 $te = $test;
62 chop($te);
68dc0745 63 if ($^O eq 'VMS') { $te =~ s/^.*\.t\./[.t./; }
c07a80fd 64 print "$te" . '.' x (20 - length($te));
6c31b336 65 my $fh = new FileHandle;
aa689395 66 $fh->open($test) or print "can't open $test. $!\n";
67 my $first = <$fh>;
68 my $s = $switches;
68dc0745 69 $s .= q[ "-T"] if $first =~ /^#!.*\bperl.*-\w*T/;
aa689395 70 $fh->close or print "can't close $test. $!\n";
52cebf5e 71 my $cmd = ($ENV{'COMPILE_TEST'})?
72"./perl -I../lib ../utils/perlcc $test -run -verbose dcf -log ./compilelog |"
73 : "$^X $s $test|";
a5077310 74 $cmd = "MCR $cmd" if $^O eq 'VMS';
aa689395 75 $fh->open($cmd) or print "can't run $test. $!\n";
c07a80fd 76 $ok = $next = $max = 0;
77 @failed = ();
7b13a3f5 78 my %todo = ();
79 my $bonus = 0;
fac76ed7 80 my $skipped = 0;
c07a80fd 81 while (<$fh>) {
6c31b336 82 if( $verbose ){
c07a80fd 83 print $_;
84 }
7b13a3f5 85 if (/^1\.\.([0-9]+) todo([\d\s]+)\;/) {
86 $max = $1;
87 for (split(/\s+/, $2)) { $todo{$_} = 1; }
88 $totmax += $max;
89 $files++;
90 $next = 1;
91 } elsif (/^1\.\.([0-9]+)/) {
c0ee6f5c 92 $max = $1;
93 $totmax += $max;
94 $files++;
95 $next = 1;
96 } elsif ($max && /^(not\s+)?ok\b/) {
97 my $this = $next;
98 if (/^not ok\s*(\d*)/){
99 $this = $1 if $1 > 0;
7b13a3f5 100 if (!$todo{$this}) {
101 push @failed, $this;
102 } else {
103 $ok++;
104 $totok++;
105 }
fac76ed7 106 } elsif (/^ok\s*(\d*)(\s*\#\s*[Ss]kip)?/) {
c0ee6f5c 107 $this = $1 if $1 > 0;
108 $ok++;
109 $totok++;
fac76ed7 110 $skipped++ if defined $2;
7b13a3f5 111 $bonus++, $totbonus++ if $todo{$this};
c07a80fd 112 }
c0ee6f5c 113 if ($this > $next) {
114 # warn "Test output counter mismatch [test $this]\n";
115 # no need to warn probably
116 push @failed, $next..$this-1;
117 } elsif ($this < $next) {
118 #we have seen more "ok" lines than the number suggests
119 warn "Confused test output: test $this answered after test ", $next-1, "\n";
120 $next = $this;
121 }
122 $next = $this + 1;
c07a80fd 123 }
124 }
6c31b336 125 $fh->close; # must close to reap child resource values
c07a80fd 126 my $wstatus = $?;
395b061e 127 my $estatus;
128 $estatus = ($^O eq 'VMS'
68dc0745 129 ? eval 'use vmsish "status"; $estatus = $?'
130 : $wstatus >> 8);
131 if ($wstatus) {
aa689395 132 my ($failed, $canon, $percent) = ('??', '??');
fb73857a 133 printf "dubious\n\tTest returned status $estatus (wstat %d, 0x%x)\n",
134 $wstatus,$wstatus;
68dc0745 135 print "\t\t(VMS status is $estatus)\n" if $^O eq 'VMS';
c0ee6f5c 136 if (corestatus($wstatus)) { # until we have a wait module
137 if ($have_devel_corestack) {
138 Devel::CoreStack::stack($^X);
139 } else {
140 print "\ttest program seems to have generated a core\n";
141 }
142 }
143 $bad++;
aa689395 144 if ($max) {
145 if ($next == $max + 1 and not @failed) {
146 print "\tafter all the subtests completed successfully\n";
147 $percent = 0;
148 $failed = 0; # But we do not set $canon!
149 } else {
150 push @failed, $next..$max;
151 $failed = @failed;
152 (my $txt, $canon) = canonfailed($max,@failed);
153 $percent = 100*(scalar @failed)/$max;
154 print "DIED. ",$txt;
155 }
156 }
157 $failedtests{$test} = { canon => $canon, max => $max || '??',
158 failed => $failed,
159 name => $test, percent => $percent,
760ac839 160 estat => $estatus, wstat => $wstatus,
161 };
c0ee6f5c 162 } elsif ($ok == $max && $next == $max+1) {
7b13a3f5 163 if ($max and $skipped + $bonus) {
164 my @msg;
165 push(@msg, "$skipped subtest".($skipped>1?'s':'')." skipped")
166 if $skipped;
167 push(@msg, "$bonus subtest".($bonus>1?'s':'').
168 " unexpectedly succeeded")
169 if $bonus;
170 print "ok, ".join(', ', @msg)."\n";
fac76ed7 171 } elsif ($max) {
c0ee6f5c 172 print "ok\n";
173 } else {
174 print "skipping test on this platform\n";
175 }
c07a80fd 176 $good++;
6c31b336 177 } elsif ($max) {
178 if ($next <= $max) {
179 push @failed, $next..$max;
180 }
c07a80fd 181 if (@failed) {
760ac839 182 my ($txt, $canon) = canonfailed($max,@failed);
183 print $txt;
184 $failedtests{$test} = { canon => $canon, max => $max,
185 failed => scalar @failed,
186 name => $test, percent => 100*(scalar @failed)/$max,
187 estat => '', wstat => '',
188 };
c07a80fd 189 } else {
c0ee6f5c 190 print "Don't know which tests failed: got $ok ok, expected $max\n";
760ac839 191 $failedtests{$test} = { canon => '??', max => $max,
192 failed => '??',
193 name => $test, percent => undef,
194 estat => '', wstat => '',
195 };
c07a80fd 196 }
197 $bad++;
6c31b336 198 } elsif ($next == 0) {
199 print "FAILED before any test output arrived\n";
200 $bad++;
760ac839 201 $failedtests{$test} = { canon => '??', max => '??',
202 failed => '??',
203 name => $test, percent => undef,
204 estat => '', wstat => '',
205 };
6c31b336 206 }
a0d0e21e 207 }
208 my $t_total = timediff(new Benchmark, $t_start);
c07a80fd 209
774d564b 210 if ($^O eq 'VMS') {
211 if (defined $old5lib) {
212 $ENV{PERL5LIB} = $old5lib;
b876d4a6 213 } else {
774d564b 214 delete $ENV{PERL5LIB};
215 }
216 }
7b13a3f5 217 my $bonusmsg = '';
218 $bonusmsg = (" ($totbonus subtest".($totbonus>1?'s':'').
219 " UNEXPECTEDLY SUCCEEDED)")
220 if $totbonus;
6c31b336 221 if ($bad == 0 && $totmax) {
7b13a3f5 222 print "All tests successful$bonusmsg.\n";
6c31b336 223 } elsif ($total==0){
224 die "FAILED--no tests were run for some reason.\n";
225 } elsif ($totmax==0) {
226 my $blurb = $total==1 ? "script" : "scripts";
c0ee6f5c 227 die "FAILED--$total test $blurb could be run, alas--no output ever seen\n";
c07a80fd 228 } else {
229 $pct = sprintf("%.2f", $good / $total * 100);
6c31b336 230 my $subpct = sprintf " %d/%d subtests failed, %.2f%% okay.",
231 $totmax - $totok, $totmax, 100*$totok/$totmax;
760ac839 232 my $script;
233 for $script (sort keys %failedtests) {
234 $curtest = $failedtests{$script};
235 write;
236 }
b876d4a6 237 if ($bad) {
6c31b336 238 die "Failed $bad/$total test scripts, $pct% okay.$subpct\n";
c07a80fd 239 }
240 }
241 printf("Files=%d, Tests=%d, %s\n", $files, $totmax, timestr($t_total, 'nop'));
f0a9308e 242
243 return ($bad == 0 && $totmax) ;
c07a80fd 244}
245
aa689395 246my $tried_devel_corestack;
c0ee6f5c 247sub corestatus {
248 my($st) = @_;
249 my($ret);
250
251 eval {require 'wait.ph'};
252 if ($@) {
253 SWITCH: {
254 $ret = ($st & 0200); # Tim says, this is for 90%
255 }
256 } else {
257 $ret = WCOREDUMP($st);
258 }
259
aa689395 260 eval { require Devel::CoreStack; $have_devel_corestack++ }
261 unless $tried_devel_corestack++;
c0ee6f5c 262
263 $ret;
264}
265
c07a80fd 266sub canonfailed ($@) {
267 my($max,@failed) = @_;
6c31b336 268 my %seen;
269 @failed = sort {$a <=> $b} grep !$seen{$_}++, @failed;
c07a80fd 270 my $failed = @failed;
271 my @result = ();
272 my @canon = ();
273 my $min;
274 my $last = $min = shift @failed;
760ac839 275 my $canon;
c07a80fd 276 if (@failed) {
277 for (@failed, $failed[-1]) { # don't forget the last one
278 if ($_ > $last+1 || $_ == $last) {
279 if ($min == $last) {
280 push @canon, $last;
281 } else {
282 push @canon, "$min-$last";
283 }
284 $min = $_;
285 }
286 $last = $_;
287 }
288 local $" = ", ";
289 push @result, "FAILED tests @canon\n";
760ac839 290 $canon = "@canon";
a0d0e21e 291 } else {
c07a80fd 292 push @result, "FAILED test $last\n";
760ac839 293 $canon = $last;
a0d0e21e 294 }
c07a80fd 295
296 push @result, "\tFailed $failed/$max tests, ";
297 push @result, sprintf("%.2f",100*(1-$failed/$max)), "% okay\n";
760ac839 298 my $txt = join "", @result;
299 ($txt, $canon);
a0d0e21e 300}
301
3021;
cb1a09d0 303__END__
304
305=head1 NAME
306
307Test::Harness - run perl standard test scripts with statistics
308
309=head1 SYNOPSIS
310
311use Test::Harness;
312
313runtests(@tests);
314
315=head1 DESCRIPTION
316
7b13a3f5 317(By using the L<Test> module, you can write test scripts without
318knowing the exact output this module expects. However, if you need to
319know the specifics, read on!)
320
cb1a09d0 321Perl test scripts print to standard output C<"ok N"> for each single
322test, where C<N> is an increasing sequence of integers. The first line
c0ee6f5c 323output by a standard test script is C<"1..M"> with C<M> being the
cb1a09d0 324number of tests that should be run within the test
c0ee6f5c 325script. Test::Harness::runtests(@tests) runs all the testscripts
cb1a09d0 326named as arguments and checks standard output for the expected
327C<"ok N"> strings.
328
c0ee6f5c 329After all tests have been performed, runtests() prints some
cb1a09d0 330performance statistics that are computed by the Benchmark module.
331
6c31b336 332=head2 The test script output
333
334Any output from the testscript to standard error is ignored and
335bypassed, thus will be seen by the user. Lines written to standard
c0ee6f5c 336output containing C</^(not\s+)?ok\b/> are interpreted as feedback for
337runtests(). All other lines are discarded.
6c31b336 338
339It is tolerated if the test numbers after C<ok> are omitted. In this
340case Test::Harness maintains temporarily its own counter until the
341script supplies test numbers again. So the following test script
342
343 print <<END;
344 1..6
345 not ok
346 ok
347 not ok
348 ok
349 ok
350 END
351
352will generate
353
354 FAILED tests 1, 3, 6
355 Failed 3/6 tests, 50.00% okay
356
357The global variable $Test::Harness::verbose is exportable and can be
c0ee6f5c 358used to let runtests() display the standard output of the script
6c31b336 359without altering the behavior otherwise.
360
fb73857a 361The global variable $Test::Harness::switches is exportable and can be
362used to set perl command line options used for running the test
363script(s). The default value is C<-w>.
364
fac76ed7 365If the standard output line contains substring C< # Skip> (with
366variations in spacing and case) after C<ok> or C<ok NUMBER>, it is
367counted as a skipped test. If the whole testscript succeeds, the
368count of skipped tests is included in the generated output.
369
cb1a09d0 370=head1 EXPORT
371
c0ee6f5c 372C<&runtests> is exported by Test::Harness per default.
cb1a09d0 373
374=head1 DIAGNOSTICS
375
376=over 4
377
378=item C<All tests successful.\nFiles=%d, Tests=%d, %s>
379
380If all tests are successful some statistics about the performance are
381printed.
382
6c31b336 383=item C<FAILED tests %s\n\tFailed %d/%d tests, %.2f%% okay.>
384
385For any single script that has failing subtests statistics like the
386above are printed.
387
388=item C<Test returned status %d (wstat %d)>
389
81ff29e3 390Scripts that return a non-zero exit status, both C<$? E<gt>E<gt> 8> and C<$?> are
6c31b336 391printed in a message similar to the above.
392
393=item C<Failed 1 test, %.2f%% okay. %s>
cb1a09d0 394
6c31b336 395=item C<Failed %d/%d tests, %.2f%% okay. %s>
cb1a09d0 396
397If not all tests were successful, the script dies with one of the
398above messages.
399
400=back
401
402=head1 SEE ALSO
403
7b13a3f5 404L<Test> for writing test scripts and also L<Benchmark> for the
405underlying timing routines.
c07a80fd 406
407=head1 AUTHORS
408
409Either Tim Bunce or Andreas Koenig, we don't know. What we know for
410sure is, that it was inspired by Larry Wall's TEST script that came
b876d4a6 411with perl distributions for ages. Numerous anonymous contributors
412exist. Current maintainer is Andreas Koenig.
cb1a09d0 413
414=head1 BUGS
415
416Test::Harness uses $^X to determine the perl binary to run the tests
6c31b336 417with. Test scripts running via the shebang (C<#!>) line may not be
418portable because $^X is not consistent for shebang scripts across
cb1a09d0 419platforms. This is no problem when Test::Harness is run with an
6c31b336 420absolute path to the perl binary or when $^X can be found in the path.
cb1a09d0 421
422=cut