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