Once again syncing after too long an absence
[p5sagit/p5-mst-13.2.git] / lib / Test / Harness.pm
CommitLineData
0e06870b 1# -*- Mode: cperl; cperl-indent-level: 4 -*-
a0d0e21e 2package Test::Harness;
3
cb50131a 4use 5.005_64;
a0d0e21e 5use Exporter;
6use Benchmark;
4633a7c4 7use Config;
760ac839 8use strict;
9
cb50131a 10our($VERSION, $verbose, $switches, $have_devel_corestack, $curtest,
4b19af01 11 $columns, @ISA, @EXPORT, @EXPORT_OK);
c0ee6f5c 12$have_devel_corestack = 0;
4633a7c4 13
0e06870b 14$VERSION = "1.1607";
9b0ceca9 15
f19ae7a7 16$ENV{HARNESS_ACTIVE} = 1;
17
9b0ceca9 18# Some experimental versions of OS/2 build have broken $?
19my $ignore_exitcode = $ENV{HARNESS_IGNORE_EXITCODE};
20
17a79f5b 21my $files_in_dir = $ENV{HARNESS_FILELEAK_IN_DIR};
22
9b0ceca9 23my $tests_skipped = 0;
24my $subtests_skipped = 0;
4633a7c4 25
c07a80fd 26@ISA=('Exporter');
cb1a09d0 27@EXPORT= qw(&runtests);
a0d0e21e 28@EXPORT_OK= qw($verbose $switches);
29
6c31b336 30$verbose = 0;
31$switches = "-w";
4b19af01 32$columns = $ENV{HARNESS_COLUMNS} || $ENV{COLUMNS} || 80;
a0d0e21e 33
17a79f5b 34sub globdir { opendir DIRH, shift; my @f = readdir DIRH; closedir DIRH; @f }
35
a0d0e21e 36sub runtests {
37 my(@tests) = @_;
38 local($|) = 1;
4b19af01 39 my($test,$te,$ok,$next,$max,$pct,$totbonus,@failed,%failedtests);
6c31b336 40 my $totmax = 0;
4b19af01 41 my $totok = 0;
6c31b336 42 my $files = 0;
a0d0e21e 43 my $bad = 0;
44 my $good = 0;
45 my $total = @tests;
774d564b 46
47 # pass -I flags to children
81ff29e3 48 my $old5lib = $ENV{PERL5LIB};
774d564b 49
fca4e211 50 # VMS has a 255-byte limit on the length of %ENV entries, so
51 # toss the ones that involve perl_root, the install location
52 # for VMS
1250aba5 53 my $new5lib;
54 if ($^O eq 'VMS') {
55 $new5lib = join($Config{path_sep}, grep {!/perl_root/i;} @INC);
56 $switches =~ s/-(\S*[A-Z]\S*)/"-$1"/g;
57 }
58 else {
59 $new5lib = join($Config{path_sep}, @INC);
60 }
1250aba5 61 local($ENV{'PERL5LIB'}) = $new5lib;
a0d0e21e 62
17a79f5b 63 my @dir_files = globdir $files_in_dir if defined $files_in_dir;
a0d0e21e 64 my $t_start = new Benchmark;
65 while ($test = shift(@tests)) {
c07a80fd 66 $te = $test;
67 chop($te);
fe6f1558 68 if ($^O eq 'VMS') { $te =~ s/^.*\.t\./[.t./s; }
45c0de28 69 my $blank = (' ' x 77);
0d0c0d42 70 my $leader = "$te" . '.' x (20 - length($te));
71 my $ml = "";
23c4718a 72 $ml = "\r$blank\r$leader"
73 if -t STDOUT and not $ENV{HARNESS_NOTTY} and not $verbose;
0d0c0d42 74 print $leader;
0e06870b 75 open(my $fh, $test) or print "can't open $test. $!\n";
aa689395 76 my $first = <$fh>;
77 my $s = $switches;
2b32313b 78 $s .= " $ENV{'HARNESS_PERL_SWITCHES'}"
79 if exists $ENV{'HARNESS_PERL_SWITCHES'};
da4582cd 80 $s .= join " ", q[ "-T"], map {qq["-I$_"]} @INC
81 if $first =~ /^#!.*\bperl.*-\w*T/;
0e06870b 82 close($fh) or print "can't close $test. $!\n";
c529f79d 83 my $cmd = ($ENV{'HARNESS_COMPILE_TEST'})
84 ? "./perl -I../lib ../utils/perlcc $test "
85 . "-run 2>> ./compilelog |"
86 : "$^X $s $test|";
a5077310 87 $cmd = "MCR $cmd" if $^O eq 'VMS';
0e06870b 88 open($fh, $cmd) or print "can't run $test. $!\n";
c07a80fd 89 $ok = $next = $max = 0;
90 @failed = ();
7b13a3f5 91 my %todo = ();
92 my $bonus = 0;
fac76ed7 93 my $skipped = 0;
c854dc73 94 my $skip_reason;
c07a80fd 95 while (<$fh>) {
6c31b336 96 if( $verbose ){
c07a80fd 97 print $_;
98 }
7b13a3f5 99 if (/^1\.\.([0-9]+) todo([\d\s]+)\;/) {
100 $max = $1;
101 for (split(/\s+/, $2)) { $todo{$_} = 1; }
102 $totmax += $max;
103 $files++;
104 $next = 1;
45c0de28 105 } elsif (/^1\.\.([0-9]+)(\s*\#\s*[Ss]kip\S*(?>\s+)(.+))?/) {
c0ee6f5c 106 $max = $1;
107 $totmax += $max;
108 $files++;
109 $next = 1;
45c0de28 110 $skip_reason = $3 if not $max and defined $3;
c0ee6f5c 111 } elsif ($max && /^(not\s+)?ok\b/) {
112 my $this = $next;
113 if (/^not ok\s*(\d*)/){
114 $this = $1 if $1 > 0;
23c4718a 115 print "${ml}NOK $this" if $ml;
7b13a3f5 116 if (!$todo{$this}) {
117 push @failed, $this;
118 } else {
119 $ok++;
120 $totok++;
121 }
0e06870b 122 } elsif (/^ok\s*(\d*) *(\s*\#\s*[Ss]kip\S*(?:(?>\s+)(.+))?)?$/) {
c0ee6f5c 123 $this = $1 if $1 > 0;
45c0de28 124 print "${ml}ok $this/$max" if $ml;
c0ee6f5c 125 $ok++;
126 $totok++;
fac76ed7 127 $skipped++ if defined $2;
c854dc73 128 my $reason;
129 $reason = 'unknown reason' if defined $2;
130 $reason = $3 if defined $3;
131 if (defined $reason and defined $skip_reason) {
132 # print "was: '$skip_reason' new '$reason'\n";
133 $skip_reason = 'various reasons'
134 if $skip_reason ne $reason;
135 } elsif (defined $reason) {
136 $skip_reason = $reason;
137 }
7b13a3f5 138 $bonus++, $totbonus++ if $todo{$this};
0e06870b 139 } elsif (/^ok\s*(\d*)\s*\#([^\r]*)$/) {
140 $this = $1 if $1 > 0;
141 print "${ml}ok $this/$max" if $ml;
142 $ok++;
143 $totok++;
144 } else {
145 # an ok or not ok not matching the 3 cases above...
146 # just ignore it for compatibility with TEST
147 next;
c07a80fd 148 }
c0ee6f5c 149 if ($this > $next) {
4b19af01 150 # print "Test output counter mismatch [test $this]\n";
c0ee6f5c 151 # no need to warn probably
152 push @failed, $next..$this-1;
153 } elsif ($this < $next) {
154 #we have seen more "ok" lines than the number suggests
4b19af01 155 print "Confused test output: test $this answered after test ", $next-1, "\n";
c0ee6f5c 156 $next = $this;
157 }
158 $next = $this + 1;
0e06870b 159 } elsif (/^Bail out!\s*(.*)/i) { # magic words
160 die "FAILED--Further testing stopped" . ($1 ? ": $1\n" : ".\n");
161 }
c07a80fd 162 }
0e06870b 163 close($fh); # must close to reap child resource values
9b0ceca9 164 my $wstatus = $ignore_exitcode ? 0 : $?; # Can trust $? ?
395b061e 165 my $estatus;
166 $estatus = ($^O eq 'VMS'
68dc0745 167 ? eval 'use vmsish "status"; $estatus = $?'
168 : $wstatus >> 8);
169 if ($wstatus) {
aa689395 170 my ($failed, $canon, $percent) = ('??', '??');
0d0c0d42 171 printf "${ml}dubious\n\tTest returned status $estatus (wstat %d, 0x%x)\n",
fb73857a 172 $wstatus,$wstatus;
68dc0745 173 print "\t\t(VMS status is $estatus)\n" if $^O eq 'VMS';
c0ee6f5c 174 if (corestatus($wstatus)) { # until we have a wait module
175 if ($have_devel_corestack) {
176 Devel::CoreStack::stack($^X);
177 } else {
178 print "\ttest program seems to have generated a core\n";
179 }
180 }
181 $bad++;
aa689395 182 if ($max) {
183 if ($next == $max + 1 and not @failed) {
184 print "\tafter all the subtests completed successfully\n";
185 $percent = 0;
186 $failed = 0; # But we do not set $canon!
187 } else {
188 push @failed, $next..$max;
189 $failed = @failed;
89d3b7e2 190 (my $txt, $canon) = canonfailed($max,$skipped,@failed);
aa689395 191 $percent = 100*(scalar @failed)/$max;
192 print "DIED. ",$txt;
193 }
194 }
195 $failedtests{$test} = { canon => $canon, max => $max || '??',
196 failed => $failed,
197 name => $test, percent => $percent,
760ac839 198 estat => $estatus, wstat => $wstatus,
199 };
c0ee6f5c 200 } elsif ($ok == $max && $next == $max+1) {
7b13a3f5 201 if ($max and $skipped + $bonus) {
202 my @msg;
45c0de28 203 push(@msg, "$skipped/$max skipped: $skip_reason")
7b13a3f5 204 if $skipped;
45c0de28 205 push(@msg, "$bonus/$max unexpectedly succeeded")
7b13a3f5 206 if $bonus;
45c0de28 207 print "${ml}ok, ".join(', ', @msg)."\n";
fac76ed7 208 } elsif ($max) {
45c0de28 209 print "${ml}ok\n";
210 } elsif (defined $skip_reason) {
211 print "skipped: $skip_reason\n";
212 $tests_skipped++;
c0ee6f5c 213 } else {
45c0de28 214 print "skipped test on this platform\n";
9b0ceca9 215 $tests_skipped++;
c0ee6f5c 216 }
c07a80fd 217 $good++;
6c31b336 218 } elsif ($max) {
219 if ($next <= $max) {
220 push @failed, $next..$max;
221 }
c07a80fd 222 if (@failed) {
89d3b7e2 223 my ($txt, $canon) = canonfailed($max,$skipped,@failed);
4b19af01 224 print "${ml}$txt";
760ac839 225 $failedtests{$test} = { canon => $canon, max => $max,
226 failed => scalar @failed,
227 name => $test, percent => 100*(scalar @failed)/$max,
228 estat => '', wstat => '',
229 };
c07a80fd 230 } else {
c0ee6f5c 231 print "Don't know which tests failed: got $ok ok, expected $max\n";
760ac839 232 $failedtests{$test} = { canon => '??', max => $max,
233 failed => '??',
234 name => $test, percent => undef,
235 estat => '', wstat => '',
236 };
c07a80fd 237 }
238 $bad++;
6c31b336 239 } elsif ($next == 0) {
240 print "FAILED before any test output arrived\n";
241 $bad++;
760ac839 242 $failedtests{$test} = { canon => '??', max => '??',
243 failed => '??',
244 name => $test, percent => undef,
245 estat => '', wstat => '',
246 };
6c31b336 247 }
9b0ceca9 248 $subtests_skipped += $skipped;
17a79f5b 249 if (defined $files_in_dir) {
250 my @new_dir_files = globdir $files_in_dir;
251 if (@new_dir_files != @dir_files) {
252 my %f;
253 @f{@new_dir_files} = (1) x @new_dir_files;
254 delete @f{@dir_files};
255 my @f = sort keys %f;
256 print "LEAKED FILES: @f\n";
257 @dir_files = @new_dir_files;
258 }
259 }
a0d0e21e 260 }
261 my $t_total = timediff(new Benchmark, $t_start);
0e06870b 262
774d564b 263 if ($^O eq 'VMS') {
264 if (defined $old5lib) {
265 $ENV{PERL5LIB} = $old5lib;
b876d4a6 266 } else {
774d564b 267 delete $ENV{PERL5LIB};
268 }
269 }
7b13a3f5 270 my $bonusmsg = '';
271 $bonusmsg = (" ($totbonus subtest".($totbonus>1?'s':'').
272 " UNEXPECTEDLY SUCCEEDED)")
273 if $totbonus;
9b0ceca9 274 if ($tests_skipped) {
c4f6c246 275 $bonusmsg .= ", $tests_skipped test" . ($tests_skipped != 1 ? 's' : '');
276 if ($subtests_skipped) {
277 $bonusmsg .= " and $subtests_skipped subtest"
278 . ($subtests_skipped != 1 ? 's' : '');
279 }
280 $bonusmsg .= ' skipped';
9b0ceca9 281 }
c4f6c246 282 elsif ($subtests_skipped) {
283 $bonusmsg .= ", $subtests_skipped subtest"
284 . ($subtests_skipped != 1 ? 's' : '')
285 . " skipped";
9b0ceca9 286 }
6c31b336 287 if ($bad == 0 && $totmax) {
7b13a3f5 288 print "All tests successful$bonusmsg.\n";
6c31b336 289 } elsif ($total==0){
290 die "FAILED--no tests were run for some reason.\n";
291 } elsif ($totmax==0) {
292 my $blurb = $total==1 ? "script" : "scripts";
c0ee6f5c 293 die "FAILED--$total test $blurb could be run, alas--no output ever seen\n";
c07a80fd 294 } else {
295 $pct = sprintf("%.2f", $good / $total * 100);
6c31b336 296 my $subpct = sprintf " %d/%d subtests failed, %.2f%% okay.",
297 $totmax - $totok, $totmax, 100*$totok/$totmax;
4b19af01 298 # Create formats
299 # First, figure out max length of test names
300 my $failed_str = "Failed Test";
301 my $middle_str = " Status Wstat Total Fail Failed ";
302 my $list_str = "List of Failed";
303 my $max_namelen = length($failed_str);
760ac839 304 my $script;
4b19af01 305 foreach $script (keys %failedtests) {
306 $max_namelen =
307 (length $failedtests{$script}->{name} > $max_namelen) ?
308 length $failedtests{$script}->{name} : $max_namelen;
309 }
310 my $list_len = $columns - length($middle_str) - $max_namelen;
311 if ($list_len < length($list_str)) {
312 $list_len = length($list_str);
313 $max_namelen = $columns - length($middle_str) - $list_len;
314 if ($max_namelen < length($failed_str)) {
315 $max_namelen = length($failed_str);
316 $columns = $max_namelen + length($middle_str) + $list_len;
317 }
318 }
319
320 my $fmt_top = "format STDOUT_TOP =\n"
321 . sprintf("%-${max_namelen}s", $failed_str)
322 . $middle_str
323 . $list_str . "\n"
324 . "-" x $columns
325 . "\n.\n";
326 my $fmt = "format STDOUT =\n"
327 . "@" . "<" x ($max_namelen - 1)
328 . " @>> @>>>> @>>>> @>>> ^##.##% "
329 . "^" . "<" x ($list_len - 1) . "\n"
330 . '{ $curtest->{name}, $curtest->{estat},'
331 . ' $curtest->{wstat}, $curtest->{max},'
332 . ' $curtest->{failed}, $curtest->{percent},'
333 . ' $curtest->{canon}'
334 . "\n}\n"
335 . "~~" . " " x ($columns - $list_len - 2) . "^"
336 . "<" x ($list_len - 1) . "\n"
337 . '$curtest->{canon}'
338 . "\n.\n";
339
340 eval $fmt_top;
341 die $@ if $@;
342 eval $fmt;
343 die $@ if $@;
344
345 # Now write to formats
760ac839 346 for $script (sort keys %failedtests) {
347 $curtest = $failedtests{$script};
348 write;
349 }
b876d4a6 350 if ($bad) {
9b0ceca9 351 $bonusmsg =~ s/^,\s*//;
352 print "$bonusmsg.\n" if $bonusmsg;
6c31b336 353 die "Failed $bad/$total test scripts, $pct% okay.$subpct\n";
c07a80fd 354 }
355 }
5603f27d 356 printf("Files=%d, Tests=%d, %s\n", $files, $totmax, timestr($t_total, 'nop'));
f0a9308e 357
358 return ($bad == 0 && $totmax) ;
c07a80fd 359}
360
aa689395 361my $tried_devel_corestack;
c0ee6f5c 362sub corestatus {
363 my($st) = @_;
c0ee6f5c 364
365 eval {require 'wait.ph'};
4b19af01 366 my $ret = defined &WCOREDUMP ? WCOREDUMP($st) : $st & 0200;
c0ee6f5c 367
aa689395 368 eval { require Devel::CoreStack; $have_devel_corestack++ }
369 unless $tried_devel_corestack++;
c0ee6f5c 370
371 $ret;
372}
373
c07a80fd 374sub canonfailed ($@) {
89d3b7e2 375 my($max,$skipped,@failed) = @_;
6c31b336 376 my %seen;
377 @failed = sort {$a <=> $b} grep !$seen{$_}++, @failed;
c07a80fd 378 my $failed = @failed;
379 my @result = ();
380 my @canon = ();
381 my $min;
382 my $last = $min = shift @failed;
760ac839 383 my $canon;
c07a80fd 384 if (@failed) {
385 for (@failed, $failed[-1]) { # don't forget the last one
386 if ($_ > $last+1 || $_ == $last) {
387 if ($min == $last) {
388 push @canon, $last;
389 } else {
390 push @canon, "$min-$last";
391 }
392 $min = $_;
393 }
394 $last = $_;
395 }
396 local $" = ", ";
397 push @result, "FAILED tests @canon\n";
760ac839 398 $canon = "@canon";
a0d0e21e 399 } else {
c07a80fd 400 push @result, "FAILED test $last\n";
760ac839 401 $canon = $last;
a0d0e21e 402 }
c07a80fd 403
404 push @result, "\tFailed $failed/$max tests, ";
89d3b7e2 405 push @result, sprintf("%.2f",100*(1-$failed/$max)), "% okay";
406 my $ender = 's' x ($skipped > 1);
407 my $good = $max - $failed - $skipped;
408 my $goodper = sprintf("%.2f",100*($good/$max));
409 push @result, " (-$skipped skipped test$ender: $good okay, $goodper%)" if $skipped;
410 push @result, "\n";
760ac839 411 my $txt = join "", @result;
412 ($txt, $canon);
a0d0e21e 413}
414
4151;
cb1a09d0 416__END__
417
418=head1 NAME
419
420Test::Harness - run perl standard test scripts with statistics
421
422=head1 SYNOPSIS
423
424use Test::Harness;
425
426runtests(@tests);
427
428=head1 DESCRIPTION
429
7b13a3f5 430(By using the L<Test> module, you can write test scripts without
431knowing the exact output this module expects. However, if you need to
432know the specifics, read on!)
433
cb1a09d0 434Perl test scripts print to standard output C<"ok N"> for each single
435test, where C<N> is an increasing sequence of integers. The first line
c0ee6f5c 436output by a standard test script is C<"1..M"> with C<M> being the
cb1a09d0 437number of tests that should be run within the test
c0ee6f5c 438script. Test::Harness::runtests(@tests) runs all the testscripts
cb1a09d0 439named as arguments and checks standard output for the expected
440C<"ok N"> strings.
441
c0ee6f5c 442After all tests have been performed, runtests() prints some
cb1a09d0 443performance statistics that are computed by the Benchmark module.
444
6c31b336 445=head2 The test script output
446
447Any output from the testscript to standard error is ignored and
448bypassed, thus will be seen by the user. Lines written to standard
c0ee6f5c 449output containing C</^(not\s+)?ok\b/> are interpreted as feedback for
450runtests(). All other lines are discarded.
6c31b336 451
452It is tolerated if the test numbers after C<ok> are omitted. In this
453case Test::Harness maintains temporarily its own counter until the
454script supplies test numbers again. So the following test script
455
456 print <<END;
457 1..6
458 not ok
459 ok
460 not ok
461 ok
462 ok
463 END
464
0e06870b 465will generate
6c31b336 466
467 FAILED tests 1, 3, 6
468 Failed 3/6 tests, 50.00% okay
469
470The global variable $Test::Harness::verbose is exportable and can be
c0ee6f5c 471used to let runtests() display the standard output of the script
6c31b336 472without altering the behavior otherwise.
473
fb73857a 474The global variable $Test::Harness::switches is exportable and can be
475used to set perl command line options used for running the test
476script(s). The default value is C<-w>.
477
fac76ed7 478If the standard output line contains substring C< # Skip> (with
479variations in spacing and case) after C<ok> or C<ok NUMBER>, it is
0e06870b 480counted as a skipped test. In no other circumstance is anything
481allowed to follow C<ok> or C<ok NUMBER>. If the whole testscript
482succeeds, the count of skipped tests is included in the generated
483output.
fac76ed7 484
0e06870b 485C<Test::Harness> reports the text after C< # Skip\S*\s+> as a reason
486for skipping. Similarly, one can include a similar explanation in a
487C<1..0> line emitted if the test is skipped completely:
45c0de28 488
489 1..0 # Skipped: no leverage found
490
0e06870b 491As an emergency measure, a test script can decide that further tests
492are useless (e.g. missing dependencies) and testing should stop
493immediately. In that case the test script prints the magic words
494
495 Bail out!
496
497to standard output. Any message after these words will be displayed by
498C<Test::Harness> as the reason why testing is stopped.
499
cb1a09d0 500=head1 EXPORT
501
c0ee6f5c 502C<&runtests> is exported by Test::Harness per default.
cb1a09d0 503
504=head1 DIAGNOSTICS
505
506=over 4
507
508=item C<All tests successful.\nFiles=%d, Tests=%d, %s>
509
510If all tests are successful some statistics about the performance are
511printed.
512
6c31b336 513=item C<FAILED tests %s\n\tFailed %d/%d tests, %.2f%% okay.>
514
515For any single script that has failing subtests statistics like the
516above are printed.
517
518=item C<Test returned status %d (wstat %d)>
519
81ff29e3 520Scripts that return a non-zero exit status, both C<$? E<gt>E<gt> 8> and C<$?> are
6c31b336 521printed in a message similar to the above.
522
523=item C<Failed 1 test, %.2f%% okay. %s>
cb1a09d0 524
6c31b336 525=item C<Failed %d/%d tests, %.2f%% okay. %s>
cb1a09d0 526
527If not all tests were successful, the script dies with one of the
528above messages.
529
0e06870b 530=item C<FAILED--Further testing stopped%s>
531
532If a single subtest decides that further testing will not make sense,
533the script dies with this message.
534
cb1a09d0 535=back
536
9b0ceca9 537=head1 ENVIRONMENT
538
17a79f5b 539Setting C<HARNESS_IGNORE_EXITCODE> makes harness ignore the exit status
9b0ceca9 540of child processes.
541
0d0c0d42 542Setting C<HARNESS_NOTTY> to a true value forces it to behave as though
543STDOUT were not a console. You may need to set this if you don't want
544harness to output more frequent progress messages using carriage returns.
545Some consoles may not handle carriage returns properly (which results
546in a somewhat messy output).
547
c529f79d 548Setting C<HARNESS_COMPILE_TEST> to a true value will make harness attempt
549to compile the test using C<perlcc> before running it.
550
17a79f5b 551If C<HARNESS_FILELEAK_IN_DIR> is set to the name of a directory, harness
552will check after each test whether new files appeared in that directory,
553and report them as
554
555 LEAKED FILES: scr.tmp 0 my.db
556
557If relative, directory name is with respect to the current directory at
558the moment runtests() was called. Putting absolute path into
559C<HARNESS_FILELEAK_IN_DIR> may give more predicatable results.
560
2b32313b 561The value of C<HARNESS_PERL_SWITCHES> will be prepended to the
562switches used to invoke perl on each test. For example, setting
563C<HARNESS_PERL_SWITCHES> to "-W" will run all tests with all
564warnings enabled.
565
4b19af01 566If C<HARNESS_COLUMNS> is set, then this value will be used for the
567width of the terminal. If it is not set then it will default to
568C<COLUMNS>. If this is not set, it will default to 80. Note that users
569of Bourne-sh based shells will need to C<export COLUMNS> for this
570module to use that variable.
571
f19ae7a7 572Harness sets C<HARNESS_ACTIVE> before executing the individual tests.
573This allows the tests to determine if they are being executed through the
574harness or by any other means.
575
cb1a09d0 576=head1 SEE ALSO
577
7b13a3f5 578L<Test> for writing test scripts and also L<Benchmark> for the
579underlying timing routines.
c07a80fd 580
581=head1 AUTHORS
582
583Either Tim Bunce or Andreas Koenig, we don't know. What we know for
584sure is, that it was inspired by Larry Wall's TEST script that came
b876d4a6 585with perl distributions for ages. Numerous anonymous contributors
586exist. Current maintainer is Andreas Koenig.
cb1a09d0 587
588=head1 BUGS
589
590Test::Harness uses $^X to determine the perl binary to run the tests
6c31b336 591with. Test scripts running via the shebang (C<#!>) line may not be
592portable because $^X is not consistent for shebang scripts across
cb1a09d0 593platforms. This is no problem when Test::Harness is run with an
6c31b336 594absolute path to the perl binary or when $^X can be found in the path.
cb1a09d0 595
596=cut