Re: TODO tests and test::harness
[p5sagit/p5-mst-13.2.git] / lib / Test / Harness.pm
CommitLineData
d667a7e6 1# -*- Mode: cperl; cperl-indent-level: 4 -*-
b82fa0b7 2
a0d0e21e 3package Test::Harness;
4
3c87ea76 5require 5.00405;
13287dd5 6use Test::Harness::Straps;
7use Test::Harness::Assert;
a0d0e21e 8use Exporter;
9use Benchmark;
4633a7c4 10use Config;
760ac839 11use strict;
12
ca09b021 13
e4fc8a1e 14use vars qw(
15 $VERSION
16 @ISA @EXPORT @EXPORT_OK
17 $Verbose $Switches $Debug
18 $verbose $switches $debug
20f9f807 19 $Columns
43ef773b 20 $Timer
e4fc8a1e 21 $ML $Last_ML_Print
22 $Strap
43ef773b 23 $has_time_hires
e4fc8a1e 24);
25
43ef773b 26BEGIN {
27 eval "use Time::HiRes 'time'";
28 $has_time_hires = !$@;
29}
30
e4fc8a1e 31=head1 NAME
32
33Test::Harness - Run Perl standard test scripts with statistics
34
35=head1 VERSION
36
20f9f807 37Version 2.57_05
e4fc8a1e 38
39=cut
40
20f9f807 41$VERSION = "2.57_05";
c6b05a01 42$VERSION = eval $VERSION;
4633a7c4 43
9c5c68c8 44# Backwards compatibility for exportable variable names.
5c0604c3 45*verbose = *Verbose;
46*switches = *Switches;
e4fc8a1e 47*debug = *Debug;
9c5c68c8 48
f19ae7a7 49$ENV{HARNESS_ACTIVE} = 1;
c0c1f8c2 50$ENV{HARNESS_VERSION} = $VERSION;
f19ae7a7 51
13287dd5 52END {
53 # For VMS.
54 delete $ENV{HARNESS_ACTIVE};
c0c1f8c2 55 delete $ENV{HARNESS_VERSION};
13287dd5 56}
57
9c5c68c8 58my $Files_In_Dir = $ENV{HARNESS_FILELEAK_IN_DIR};
9b0ceca9 59
d5d4ec93 60$Strap = Test::Harness::Straps->new;
17a79f5b 61
3c87ea76 62sub strap { return $Strap };
63
9c5c68c8 64@ISA = ('Exporter');
65@EXPORT = qw(&runtests);
20f9f807 66@EXPORT_OK = qw(&execute_tests $verbose $switches);
4633a7c4 67
356733da 68$Verbose = $ENV{HARNESS_VERBOSE} || 0;
e4fc8a1e 69$Debug = $ENV{HARNESS_DEBUG} || 0;
9c5c68c8 70$Switches = "-w";
71$Columns = $ENV{HARNESS_COLUMNS} || $ENV{COLUMNS} || 80;
b82fa0b7 72$Columns--; # Some shells have trouble with a full line of text.
43ef773b 73$Timer = $ENV{HARNESS_TIMER} || 0;
b82fa0b7 74
b82fa0b7 75=head1 SYNOPSIS
76
77 use Test::Harness;
78
79 runtests(@test_files);
80
81=head1 DESCRIPTION
a0d0e21e 82
3c87ea76 83B<STOP!> If all you want to do is write a test script, consider
84using Test::Simple. Test::Harness is the module that reads the
85output from Test::Simple, Test::More and other modules based on
86Test::Builder. You don't need to know about Test::Harness to use
87those modules.
b82fa0b7 88
3c87ea76 89Test::Harness runs tests and expects output from the test in a
90certain format. That format is called TAP, the Test Anything
91Protocol. It is defined in L<Test::Harness::TAP>.
b82fa0b7 92
3c87ea76 93C<Test::Harness::runtests(@tests)> runs all the testscripts named
94as arguments and checks standard output for the expected strings
95in TAP format.
b82fa0b7 96
3c87ea76 97The F<prove> utility is a thin wrapper around Test::Harness.
b82fa0b7 98
13287dd5 99=head2 Taint mode
100
e4fc8a1e 101Test::Harness will honor the C<-T> or C<-t> in the #! line on your
102test files. So if you begin a test with:
13287dd5 103
104 #!perl -T
105
106the test will be run with taint mode on.
107
13287dd5 108=head2 Configuration variables.
109
110These variables can be used to configure the behavior of
111Test::Harness. They are exported on request.
112
113=over 4
114
3c87ea76 115=item C<$Test::Harness::Verbose>
13287dd5 116
3c87ea76 117The package variable C<$Test::Harness::Verbose> is exportable and can be
e4fc8a1e 118used to let C<runtests()> display the standard output of the script
119without altering the behavior otherwise. The F<prove> utility's C<-v>
120flag will set this.
13287dd5 121
3c87ea76 122=item C<$Test::Harness::switches>
13287dd5 123
3c87ea76 124The package variable C<$Test::Harness::switches> is exportable and can be
13287dd5 125used to set perl command line options used for running the test
e4fc8a1e 126script(s). The default value is C<-w>. It overrides C<HARNESS_SWITCHES>.
13287dd5 127
43ef773b 128=item C<$Test::Harness::Timer>
129
130If set to true, and C<Time::HiRes> is available, print elapsed seconds
131after each test file.
132
13287dd5 133=back
134
135
b82fa0b7 136=head2 Failure
137
3c87ea76 138When tests fail, analyze the summary report:
b82fa0b7 139
2fe373ce 140 t/base..............ok
141 t/nonumbers.........ok
142 t/ok................ok
143 t/test-harness......ok
144 t/waterloo..........dubious
b82fa0b7 145 Test returned status 3 (wstat 768, 0x300)
146 DIED. FAILED tests 1, 3, 5, 7, 9, 11, 13, 15, 17, 19
147 Failed 10/20 tests, 50.00% okay
148 Failed Test Stat Wstat Total Fail Failed List of Failed
149 -----------------------------------------------------------------------
150 t/waterloo.t 3 768 20 10 50.00% 1 3 5 7 9 11 13 15 17 19
151 Failed 1/5 test scripts, 80.00% okay. 10/44 subtests failed, 77.27% okay.
152
3c87ea76 153Everything passed but F<t/waterloo.t>. It failed 10 of 20 tests and
b82fa0b7 154exited with non-zero status indicating something dubious happened.
155
156The columns in the summary report mean:
157
158=over 4
159
160=item B<Failed Test>
161
162The test file which failed.
163
164=item B<Stat>
165
166If the test exited with non-zero, this is its exit status.
167
168=item B<Wstat>
169
e4fc8a1e 170The wait status of the test.
b82fa0b7 171
172=item B<Total>
173
174Total number of tests expected to run.
175
176=item B<Fail>
177
178Number which failed, either from "not ok" or because they never ran.
179
180=item B<Failed>
181
182Percentage of the total tests which failed.
183
184=item B<List of Failed>
185
186A list of the tests which failed. Successive failures may be
187abbreviated (ie. 15-20 to indicate that tests 15, 16, 17, 18, 19 and
18820 failed).
189
190=back
191
192
20f9f807 193=head1 FUNCTIONS
b82fa0b7 194
20f9f807 195The following functions are available.
b82fa0b7 196
20f9f807 197=head2 runtests( @test_files )
b82fa0b7 198
3c87ea76 199This runs all the given I<@test_files> and divines whether they passed
b82fa0b7 200or failed based on their output to STDOUT (details above). It prints
201out each individual test which failed along with a summary report and
202a how long it all took.
203
3c87ea76 204It returns true if everything was ok. Otherwise it will C<die()> with
d5d4ec93 205one of the messages in the DIAGNOSTICS section.
b82fa0b7 206
b82fa0b7 207=cut
17a79f5b 208
a0d0e21e 209sub runtests {
210 my(@tests) = @_;
9c5c68c8 211
b82fa0b7 212 local ($\, $,);
213
20f9f807 214 my ($tot, $failedtests,$todo_passed) = execute_tests(tests => \@tests);
215 print get_results($tot, $failedtests,$todo_passed);
9c5c68c8 216
2fe373ce 217 my $ok = _all_ok($tot);
b82fa0b7 218
13287dd5 219 assert(($ok xor keys %$failedtests),
220 q{ok status jives with $failedtests});
b82fa0b7 221
222 return $ok;
223}
224
20f9f807 225# my $ok = _all_ok(\%tot);
226# Tells you if this test run is overall successful or not.
2fe373ce 227
228sub _all_ok {
229 my($tot) = shift;
230
231 return $tot->{bad} == 0 && ($tot->{max} || $tot->{skipped}) ? 1 : 0;
232}
233
20f9f807 234# Returns all the files in a directory. This is shorthand for backwards
235# compatibility on systems where C<glob()> doesn't work right.
b82fa0b7 236
20f9f807 237sub _globdir {
238 local *DIRH;
b82fa0b7 239
20f9f807 240 opendir DIRH, shift;
241 my @f = readdir DIRH;
242 closedir DIRH;
b82fa0b7 243
244 return @f;
9c5c68c8 245}
246
20f9f807 247=head2 execute_tests( tests => \@test_files, out => \*FH )
b82fa0b7 248
20f9f807 249Runs all the given C<@test_files> (just like C<runtests()>) but
250doesn't generate the final report. During testing, progress
251information will be written to the currently selected output
252filehandle (usually C<STDOUT>), or to the filehandle given by the
253C<out> parameter. The I<out> is optional.
b82fa0b7 254
20f9f807 255Returns a list of two values, C<$total> and C<$failed>, describing the
256results. C<$total> is a hash ref summary of all the tests run. Its
257keys and values are this:
b82fa0b7 258
259 bonus Number of individual todo tests unexpectedly passed
260 max Number of individual tests ran
261 ok Number of individual tests passed
262 sub_skipped Number of individual tests skipped
2fe373ce 263 todo Number of individual todo tests
b82fa0b7 264
265 files Number of test files ran
266 good Number of test files passed
267 bad Number of test files failed
268 tests Number of test files originally given
269 skipped Number of test files skipped
270
e4fc8a1e 271If C<< $total->{bad} == 0 >> and C<< $total->{max} > 0 >>, you've
272got a successful test.
b82fa0b7 273
20f9f807 274C<$failed> is a hash ref of all the test scripts that failed. Each key
b82fa0b7 275is the name of a test script, each value is another hash representing
276how that script failed. Its keys are these:
9c5c68c8 277
b82fa0b7 278 name Name of the test which failed
279 estat Script's exit value
280 wstat Script's wait status
281 max Number of individual tests
282 failed Number which failed
283 percent Percentage of tests which failed
284 canon List of tests which failed (as string).
285
e4fc8a1e 286C<$failed> should be empty if everything passed.
b82fa0b7 287
b82fa0b7 288=cut
289
20f9f807 290sub execute_tests {
291 my %args = @_;
292 my @tests = @{$args{tests}};
293 my $out = $args{out} || select();
3c87ea76 294
20f9f807 295 # We allow filehandles that are symbolic refs
296 no strict 'refs';
297 _autoflush($out);
3c87ea76 298 _autoflush(\*STDERR);
299
20f9f807 300 my %failedtests;
301 my %todo_passed;
9c5c68c8 302
303 # Test-wide totals.
304 my(%tot) = (
305 bonus => 0,
306 max => 0,
307 ok => 0,
308 files => 0,
309 bad => 0,
310 good => 0,
311 tests => scalar @tests,
312 sub_skipped => 0,
2fe373ce 313 todo => 0,
9c5c68c8 314 skipped => 0,
2fe373ce 315 bench => 0,
9c5c68c8 316 );
774d564b 317
76df5e8f 318 my @dir_files;
319 @dir_files = _globdir $Files_In_Dir if defined $Files_In_Dir;
ca09b021 320 my $run_start_time = new Benchmark;
9c5c68c8 321
13287dd5 322 my $width = _leader_width(@tests);
b82fa0b7 323 foreach my $tfile (@tests) {
5c0604c3 324 $Last_ML_Print = 0; # so each test prints at least once
7a315204 325 my($leader, $ml) = _mk_leader($tfile, $width);
308957f5 326 local $ML = $ml;
e4fc8a1e 327
20f9f807 328 print $out $leader;
9c5c68c8 329
356733da 330 $tot{files}++;
331
308957f5 332 $Strap->{_seen_header} = 0;
3c87ea76 333 if ( $Test::Harness::Debug ) {
20f9f807 334 print $out "# Running: ", $Strap->_command_line($tfile), "\n";
3c87ea76 335 }
43ef773b 336 my $test_start_time = $Timer ? time : 0;
0be28027 337 my %results = $Strap->analyze_file($tfile) or
e4fc8a1e 338 do { warn $Strap->{error}, "\n"; next };
43ef773b 339 my $elapsed;
340 if ( $Timer ) {
341 $elapsed = time - $test_start_time;
342 if ( $has_time_hires ) {
20f9f807 343 $elapsed = sprintf( " %8d ms", $elapsed*1000 );
43ef773b 344 }
345 else {
20f9f807 346 $elapsed = sprintf( " %8s s", $elapsed ? $elapsed : "<1" );
43ef773b 347 }
348 }
349 else {
350 $elapsed = "";
351 }
308957f5 352
9c5c68c8 353 # state of the current test.
308957f5 354 my @failed = grep { !$results{details}[$_-1]{ok} }
355 1..@{$results{details}};
c6b05a01 356 my @todo_pass = grep { $results{details}[$_-1]{actual_ok} &&
20f9f807 357 $results{details}[$_-1]{type} eq 'todo' }
358 1..@{$results{details}};
359
9c5c68c8 360 my %test = (
308957f5 361 ok => $results{ok},
362 'next' => $Strap->{'next'},
363 max => $results{max},
364 failed => \@failed,
20f9f807 365 todo_pass => \@todo_pass,
c6b05a01 366 todo => $results{todo},
308957f5 367 bonus => $results{bonus},
368 skipped => $results{skip},
a72fde19 369 skip_reason => $results{skip_reason},
c0bb2de7 370 skip_all => $Strap->{skip_all},
9c5c68c8 371 ml => $ml,
372 );
373
308957f5 374 $tot{bonus} += $results{bonus};
375 $tot{max} += $results{max};
376 $tot{ok} += $results{ok};
377 $tot{todo} += $results{todo};
378 $tot{sub_skipped} += $results{skip};
9c5c68c8 379
308957f5 380 my($estatus, $wstatus) = @results{qw(exit wait)};
b82fa0b7 381
a72fde19 382 if ($results{passing}) {
ca09b021 383 # XXX Combine these first two
2fe373ce 384 if ($test{max} and $test{skipped} + $test{bonus}) {
385 my @msg;
386 push(@msg, "$test{skipped}/$test{max} skipped: $test{skip_reason}")
387 if $test{skipped};
20f9f807 388 if ($test{bonus}) {
c6b05a01 389 my ($txt, $canon) = _canondetail($test{todo},0,'TODO passed',
20f9f807 390 @{$test{todo_pass}});
391 $todo_passed{$tfile} = {
392 canon => $canon,
c6b05a01 393 max => $test{todo},
20f9f807 394 failed => $test{bonus},
395 name => $tfile,
c6b05a01 396 percent => 100*$test{bonus}/$test{todo},
20f9f807 397 estat => '',
398 wstat => '',
399 };
400
401 push(@msg, "$test{bonus}/$test{max} unexpectedly succeeded\n$txt");
402 }
403 print $out "$test{ml}ok$elapsed\n ".join(', ', @msg)."\n";
ca09b021 404 }
405 elsif ( $test{max} ) {
20f9f807 406 print $out "$test{ml}ok$elapsed\n";
ca09b021 407 }
408 elsif ( defined $test{skip_all} and length $test{skip_all} ) {
20f9f807 409 print $out "skipped\n all skipped: $test{skip_all}\n";
2fe373ce 410 $tot{skipped}++;
ca09b021 411 }
412 else {
20f9f807 413 print $out "skipped\n all skipped: no reason given\n";
2fe373ce 414 $tot{skipped}++;
415 }
416 $tot{good}++;
417 }
b82fa0b7 418 else {
a72fde19 419 # List unrun tests as failures.
420 if ($test{'next'} <= $test{max}) {
421 push @{$test{failed}}, $test{'next'}..$test{max};
422 }
423 # List overruns as failures.
424 else {
425 my $details = $results{details};
3c87ea76 426 foreach my $overrun ($test{max}+1..@$details) {
a72fde19 427 next unless ref $details->[$overrun-1];
428 push @{$test{failed}}, $overrun
b82fa0b7 429 }
a72fde19 430 }
431
432 if ($wstatus) {
433 $failedtests{$tfile} = _dubious_return(\%test, \%tot,
434 $estatus, $wstatus);
435 $failedtests{$tfile}{name} = $tfile;
436 }
437 elsif($results{seen}) {
c4b2e1b6 438 if (@{$test{failed}} and $test{max}) {
20f9f807 439 my ($txt, $canon) = _canondetail($test{max},$test{skipped},'Failed',
b82fa0b7 440 @{$test{failed}});
20f9f807 441 print $out "$test{ml}$txt";
b82fa0b7 442 $failedtests{$tfile} = { canon => $canon,
443 max => $test{max},
444 failed => scalar @{$test{failed}},
445 name => $tfile,
446 percent => 100*(scalar @{$test{failed}})/$test{max},
447 estat => '',
448 wstat => '',
449 };
ca09b021 450 }
451 else {
20f9f807 452 print $out "Don't know which tests failed: got $test{ok} ok, ".
b82fa0b7 453 "expected $test{max}\n";
454 $failedtests{$tfile} = { canon => '??',
455 max => $test{max},
456 failed => '??',
457 name => $tfile,
458 percent => undef,
459 estat => '',
460 wstat => '',
461 };
462 }
463 $tot{bad}++;
ca09b021 464 }
465 else {
20f9f807 466 print $out "FAILED before any test output arrived\n";
b82fa0b7 467 $tot{bad}++;
468 $failedtests{$tfile} = { canon => '??',
469 max => '??',
470 failed => '??',
471 name => $tfile,
472 percent => undef,
473 estat => '',
474 wstat => '',
475 };
476 }
477 }
478
2fe373ce 479 if (defined $Files_In_Dir) {
480 my @new_dir_files = _globdir $Files_In_Dir;
481 if (@new_dir_files != @dir_files) {
482 my %f;
483 @f{@new_dir_files} = (1) x @new_dir_files;
484 delete @f{@dir_files};
485 my @f = sort keys %f;
20f9f807 486 print $out "LEAKED FILES: @f\n";
2fe373ce 487 @dir_files = @new_dir_files;
488 }
489 }
3c87ea76 490 } # foreach test
ca09b021 491 $tot{bench} = timediff(new Benchmark, $run_start_time);
d667a7e6 492
13287dd5 493 $Strap->_restore_PERL5LIB;
9c5c68c8 494
20f9f807 495 return(\%tot, \%failedtests, \%todo_passed);
496}
497
498# Turns on autoflush for the handle passed
499sub _autoflush {
500 my $flushy_fh = shift;
501 my $old_fh = select $flushy_fh;
502 $| = 1;
503 select $old_fh;
9c5c68c8 504}
505
20f9f807 506=for private _mk_leader
b82fa0b7 507
20f9f807 508 my($leader, $ml) = _mk_leader($test_file, $width);
b82fa0b7 509
3c87ea76 510Generates the 't/foo........' leader for the given C<$test_file> as well
b82fa0b7 511as a similar version which will overwrite the current line (by use of
e4fc8a1e 512\r and such). C<$ml> may be empty if Test::Harness doesn't think you're
2fe373ce 513on TTY.
514
e4fc8a1e 515The C<$width> is the width of the "yada/blah.." string.
b82fa0b7 516
517=cut
518
519sub _mk_leader {
2fe373ce 520 my($te, $width) = @_;
521 chomp($te);
b695f709 522 $te =~ s/\.\w+$/./;
b82fa0b7 523
ca09b021 524 if ($^O eq 'VMS') {
525 $te =~ s/^.*\.t\./\[.t./s;
526 }
7a315204 527 my $leader = "$te" . '.' x ($width - length($te));
b82fa0b7 528 my $ml = "";
529
ca09b021 530 if ( -t STDOUT and not $ENV{HARNESS_NOTTY} and not $Verbose ) {
531 $ml = "\r" . (' ' x 77) . "\r$leader"
532 }
b82fa0b7 533
534 return($leader, $ml);
535}
536
20f9f807 537=for private _leader_width
13287dd5 538
539 my($width) = _leader_width(@test_files);
540
541Calculates how wide the leader should be based on the length of the
542longest test name.
543
544=cut
545
546sub _leader_width {
547 my $maxlen = 0;
548 my $maxsuflen = 0;
549 foreach (@_) {
550 my $suf = /\.(\w+)$/ ? $1 : '';
551 my $len = length;
552 my $suflen = length $suf;
553 $maxlen = $len if $len > $maxlen;
554 $maxsuflen = $suflen if $suflen > $maxsuflen;
555 }
356733da 556 # + 3 : we want three dots between the test name and the "ok"
557 return $maxlen + 3 - $maxsuflen;
13287dd5 558}
559
20f9f807 560sub get_results {
561 my $tot = shift;
562 my $failedtests = shift;
563 my $todo_passed = shift;
9c5c68c8 564
20f9f807 565 my $out = '';
9c5c68c8 566
567 my $pct;
568 my $bonusmsg = _bonusmsg($tot);
569
2fe373ce 570 if (_all_ok($tot)) {
20f9f807 571 $out .= "All tests successful$bonusmsg.\n";
572 if ($tot->{bonus}) {
c6b05a01 573 my($fmt_top, $fmt) = _create_fmts("Passed Todo",$todo_passed);
20f9f807 574 # Now write to formats
575 for my $script (sort keys %{$todo_passed||{}}) {
576 my $Curtest = $todo_passed->{$script};
577
578 $out .= swrite( $fmt_top );
579 $out .= swrite( $fmt, @{ $Curtest }{qw(name estat wstat max failed percent canon)} );
580 }
581 }
ca09b021 582 }
583 elsif (!$tot->{tests}){
2fe373ce 584 die "FAILED--no tests were run for some reason.\n";
ca09b021 585 }
586 elsif (!$tot->{max}) {
2fe373ce 587 my $blurb = $tot->{tests}==1 ? "script" : "scripts";
588 die "FAILED--$tot->{tests} test $blurb could be run, ".
9c5c68c8 589 "alas--no output ever seen\n";
ca09b021 590 }
591 else {
2fe373ce 592 $pct = sprintf("%.2f", $tot->{good} / $tot->{tests} * 100);
593 my $percent_ok = 100*$tot->{ok}/$tot->{max};
594 my $subpct = sprintf " %d/%d subtests failed, %.2f%% okay.",
595 $tot->{max} - $tot->{ok}, $tot->{max},
596 $percent_ok;
0a931e4a 597
c6b05a01 598 my($fmt_top, $fmt1, $fmt2) = _create_fmts("Failed Test",$failedtests);
0a931e4a 599
2fe373ce 600 # Now write to formats
601 for my $script (sort keys %$failedtests) {
20f9f807 602 my $Curtest = $failedtests->{$script};
603 $out .= swrite( $fmt_top );
604 $out .= swrite( $fmt1, @{ $Curtest }{qw(name estat wstat max failed percent canon)} );
605 $out .= swrite( $fmt2, $Curtest->{canon} );
2fe373ce 606 }
607 if ($tot->{bad}) {
608 $bonusmsg =~ s/^,\s*//;
20f9f807 609 $out .= "$bonusmsg.\n" if $bonusmsg;
610 $out .= "Failed $tot->{bad}/$tot->{tests} test scripts, $pct% okay.$subpct\n";
2fe373ce 611 }
c07a80fd 612 }
f0a9308e 613
20f9f807 614 $out .= sprintf("Files=%d, Tests=%d, %s\n",
9c5c68c8 615 $tot->{files}, $tot->{max}, timestr($tot->{bench}, 'nop'));
20f9f807 616 return $out;
617}
618
619sub swrite {
620 my $format = shift;
621 $^A = '';
622 formline($format,@_);
623 my $out = $^A;
624 $^A = '';
625 return $out;
9c5c68c8 626}
627
628
3c87ea76 629my %Handlers = (
630 header => \&header_handler,
631 test => \&test_handler,
632 bailout => \&bailout_handler,
633);
634
635$Strap->{callback} = \&strap_callback;
636sub strap_callback {
308957f5 637 my($self, $line, $type, $totals) = @_;
638 print $line if $Verbose;
9c5c68c8 639
308957f5 640 my $meth = $Handlers{$type};
641 $meth->($self, $line, $type, $totals) if $meth;
642};
9c5c68c8 643
9c5c68c8 644
3c87ea76 645sub header_handler {
308957f5 646 my($self, $line, $type, $totals) = @_;
9c5c68c8 647
308957f5 648 warn "Test header seen more than once!\n" if $self->{_seen_header};
9c5c68c8 649
308957f5 650 $self->{_seen_header}++;
9c5c68c8 651
308957f5 652 warn "1..M can only appear at the beginning or end of tests\n"
653 if $totals->{seen} &&
654 $totals->{max} < $totals->{seen};
655};
13287dd5 656
3c87ea76 657sub test_handler {
308957f5 658 my($self, $line, $type, $totals) = @_;
9c5c68c8 659
308957f5 660 my $curr = $totals->{seen};
661 my $next = $self->{'next'};
662 my $max = $totals->{max};
663 my $detail = $totals->{details}[-1];
b82fa0b7 664
308957f5 665 if( $detail->{ok} ) {
5c0604c3 666 _print_ml_less("ok $curr/$max");
356733da 667
308957f5 668 if( $detail->{type} eq 'skip' ) {
a72fde19 669 $totals->{skip_reason} = $detail->{reason}
670 unless defined $totals->{skip_reason};
671 $totals->{skip_reason} = 'various reasons'
672 if $totals->{skip_reason} ne $detail->{reason};
308957f5 673 }
b82fa0b7 674 }
675 else {
308957f5 676 _print_ml("NOK $curr");
b82fa0b7 677 }
b82fa0b7 678
308957f5 679 if( $curr > $next ) {
680 print "Test output counter mismatch [test $curr]\n";
681 }
682 elsif( $curr < $next ) {
683 print "Confused test output: test $curr answered after ".
684 "test ", $next - 1, "\n";
685 }
b82fa0b7 686
308957f5 687};
2fe373ce 688
3c87ea76 689sub bailout_handler {
308957f5 690 my($self, $line, $type, $totals) = @_;
9c5c68c8 691
308957f5 692 die "FAILED--Further testing stopped" .
693 ($self->{bailout_reason} ? ": $self->{bailout_reason}\n" : ".\n");
694};
356733da 695
9c5c68c8 696
308957f5 697sub _print_ml {
698 print join '', $ML, @_ if $ML;
9c5c68c8 699}
700
701
43ef773b 702# Print updates only once per second.
5c0604c3 703sub _print_ml_less {
43ef773b 704 my $now = CORE::time;
705 if ( $Last_ML_Print != $now ) {
5c0604c3 706 _print_ml(@_);
43ef773b 707 $Last_ML_Print = $now;
5c0604c3 708 }
709}
710
9c5c68c8 711sub _bonusmsg {
712 my($tot) = @_;
713
714 my $bonusmsg = '';
715 $bonusmsg = (" ($tot->{bonus} subtest".($tot->{bonus} > 1 ? 's' : '').
2fe373ce 716 " UNEXPECTEDLY SUCCEEDED)")
717 if $tot->{bonus};
9c5c68c8 718
719 if ($tot->{skipped}) {
2fe373ce 720 $bonusmsg .= ", $tot->{skipped} test"
9c5c68c8 721 . ($tot->{skipped} != 1 ? 's' : '');
2fe373ce 722 if ($tot->{sub_skipped}) {
723 $bonusmsg .= " and $tot->{sub_skipped} subtest"
724 . ($tot->{sub_skipped} != 1 ? 's' : '');
725 }
726 $bonusmsg .= ' skipped';
9c5c68c8 727 }
728 elsif ($tot->{sub_skipped}) {
2fe373ce 729 $bonusmsg .= ", $tot->{sub_skipped} subtest"
730 . ($tot->{sub_skipped} != 1 ? 's' : '')
731 . " skipped";
9c5c68c8 732 }
9c5c68c8 733 return $bonusmsg;
734}
735
9c5c68c8 736# Test program go boom.
737sub _dubious_return {
738 my($test, $tot, $estatus, $wstatus) = @_;
739 my ($failed, $canon, $percent) = ('??', '??');
740
741 printf "$test->{ml}dubious\n\tTest returned status $estatus ".
742 "(wstat %d, 0x%x)\n",
743 $wstatus,$wstatus;
744 print "\t\t(VMS status is $estatus)\n" if $^O eq 'VMS';
745
9c5c68c8 746 $tot->{bad}++;
747
748 if ($test->{max}) {
b82fa0b7 749 if ($test->{'next'} == $test->{max} + 1 and not @{$test->{failed}}) {
9c5c68c8 750 print "\tafter all the subtests completed successfully\n";
751 $percent = 0;
2fe373ce 752 $failed = 0; # But we do not set $canon!
9c5c68c8 753 }
754 else {
b82fa0b7 755 push @{$test->{failed}}, $test->{'next'}..$test->{max};
9c5c68c8 756 $failed = @{$test->{failed}};
20f9f807 757 (my $txt, $canon) = _canondetail($test->{max},$test->{skipped},'Failed',@{$test->{failed}});
9c5c68c8 758 $percent = 100*(scalar @{$test->{failed}})/$test->{max};
759 print "DIED. ",$txt;
760 }
761 }
762
763 return { canon => $canon, max => $test->{max} || '??',
764 failed => $failed,
66fd8cb9 765 percent => $percent,
9c5c68c8 766 estat => $estatus, wstat => $wstatus,
767 };
768}
769
770
9c5c68c8 771sub _create_fmts {
c6b05a01 772 my $failed_str = shift;
20f9f807 773 my $failedtests = shift;
9c5c68c8 774
c6b05a01 775 my ($type) = split /\s/,$failed_str;
20f9f807 776 my $short = substr($type,0,4);
c6b05a01 777 my $total = $short eq 'Pass' ? 'Todos' : 'Total';
778 my $middle_str = " Stat Wstat $total $short $type ";
20f9f807 779 my $list_str = "List of $type";
9c5c68c8 780
781 # Figure out our longest name string for formatting purposes.
782 my $max_namelen = length($failed_str);
783 foreach my $script (keys %$failedtests) {
784 my $namelen = length $failedtests->{$script}->{name};
785 $max_namelen = $namelen if $namelen > $max_namelen;
786 }
787
788 my $list_len = $Columns - length($middle_str) - $max_namelen;
789 if ($list_len < length($list_str)) {
790 $list_len = length($list_str);
791 $max_namelen = $Columns - length($middle_str) - $list_len;
792 if ($max_namelen < length($failed_str)) {
793 $max_namelen = length($failed_str);
794 $Columns = $max_namelen + length($middle_str) + $list_len;
795 }
796 }
797
20f9f807 798 my $fmt_top = sprintf("%-${max_namelen}s", $failed_str)
9c5c68c8 799 . $middle_str
2fe373ce 800 . $list_str . "\n"
801 . "-" x $Columns
20f9f807 802 . "\n";
9c5c68c8 803
20f9f807 804 my $fmt1 = "@" . "<" x ($max_namelen - 1)
b82fa0b7 805 . " @>> @>>>> @>>>> @>>> ^##.##% "
20f9f807 806 . "^" . "<" x ($list_len - 1) . "\n";
807 my $fmt2 = "~~" . " " x ($Columns - $list_len - 2) . "^"
808 . "<" x ($list_len - 1) . "\n";
809
810 return($fmt_top, $fmt1, $fmt2);
9c5c68c8 811}
812
20f9f807 813sub _canondetail {
814 my $max = shift;
815 my $skipped = shift;
816 my $type = shift;
817 my @detail = @_;
6c31b336 818 my %seen;
20f9f807 819 @detail = sort {$a <=> $b} grep !$seen{$_}++, @detail;
820 my $detail = @detail;
c07a80fd 821 my @result = ();
822 my @canon = ();
823 my $min;
20f9f807 824 my $last = $min = shift @detail;
760ac839 825 my $canon;
20f9f807 826 my $uc_type = uc($type);
827 if (@detail) {
828 for (@detail, $detail[-1]) { # don't forget the last one
2fe373ce 829 if ($_ > $last+1 || $_ == $last) {
ca09b021 830 push @canon, ($min == $last) ? $last : "$min-$last";
2fe373ce 831 $min = $_;
832 }
833 $last = $_;
834 }
835 local $" = ", ";
20f9f807 836 push @result, "$uc_type tests @canon\n";
2fe373ce 837 $canon = join ' ', @canon;
ca09b021 838 }
839 else {
20f9f807 840 push @result, "$uc_type test $last\n";
2fe373ce 841 $canon = $last;
a0d0e21e 842 }
c07a80fd 843
20f9f807 844 return (join("", @result), $canon)
845 if $type=~/todo/i;
846 push @result, "\t$type $detail/$max tests, ";
e93c2686 847 if ($max) {
20f9f807 848 push @result, sprintf("%.2f",100*(1-$detail/$max)), "% okay";
ca09b021 849 }
850 else {
e93c2686 851 push @result, "?% okay";
852 }
89d3b7e2 853 my $ender = 's' x ($skipped > 1);
e93c2686 854 if ($skipped) {
20f9f807 855 my $good = $max - $detail - $skipped;
e93c2686 856 my $skipmsg = " (less $skipped skipped test$ender: $good okay, ";
857 if ($max) {
858 my $goodper = sprintf("%.2f",100*($good/$max));
859 $skipmsg .= "$goodper%)";
ca09b021 860 }
861 else {
e93c2686 862 $skipmsg .= "?%)";
863 }
864 push @result, $skipmsg;
865 }
89d3b7e2 866 push @result, "\n";
760ac839 867 my $txt = join "", @result;
20f9f807 868 return ($txt, $canon);
a0d0e21e 869}
870
b82fa0b7 8711;
872__END__
9c5c68c8 873
874
cb1a09d0 875=head1 EXPORT
876
e8df9912 877C<&runtests> is exported by Test::Harness by default.
cb1a09d0 878
20f9f807 879C<&execute_tests>, C<$verbose>, C<$switches> and C<$debug> are
880exported upon request.
9c5c68c8 881
cb1a09d0 882=head1 DIAGNOSTICS
883
884=over 4
885
886=item C<All tests successful.\nFiles=%d, Tests=%d, %s>
887
888If all tests are successful some statistics about the performance are
889printed.
890
6c31b336 891=item C<FAILED tests %s\n\tFailed %d/%d tests, %.2f%% okay.>
892
893For any single script that has failing subtests statistics like the
894above are printed.
895
896=item C<Test returned status %d (wstat %d)>
897
9c5c68c8 898Scripts that return a non-zero exit status, both C<$? E<gt>E<gt> 8>
899and C<$?> are printed in a message similar to the above.
6c31b336 900
901=item C<Failed 1 test, %.2f%% okay. %s>
cb1a09d0 902
6c31b336 903=item C<Failed %d/%d tests, %.2f%% okay. %s>
cb1a09d0 904
905If not all tests were successful, the script dies with one of the
906above messages.
907
308957f5 908=item C<FAILED--Further testing stopped: %s>
d667a7e6 909
910If a single subtest decides that further testing will not make sense,
911the script dies with this message.
912
cb1a09d0 913=back
914
c0c1f8c2 915=head1 ENVIRONMENT VARIABLES THAT TEST::HARNESS SETS
916
917Test::Harness sets these before executing the individual tests.
9b0ceca9 918
37ce32a7 919=over 4
920
356733da 921=item C<HARNESS_ACTIVE>
37ce32a7 922
c0c1f8c2 923This is set to a true value. It allows the tests to determine if they
924are being executed through the harness or by any other means.
925
926=item C<HARNESS_VERSION>
927
928This is the version of Test::Harness.
929
930=back
931
932=head1 ENVIRONMENT VARIABLES THAT AFFECT TEST::HARNESS
933
934=over 4
37ce32a7 935
356733da 936=item C<HARNESS_COLUMNS>
9b0ceca9 937
356733da 938This value will be used for the width of the terminal. If it is not
939set then it will default to C<COLUMNS>. If this is not set, it will
940default to 80. Note that users of Bourne-sh based shells will need to
941C<export COLUMNS> for this module to use that variable.
0d0c0d42 942
b82fa0b7 943=item C<HARNESS_COMPILE_TEST>
9636a016 944
37ce32a7 945When true it will make harness attempt to compile the test using
946C<perlcc> before running it.
947
b82fa0b7 948B<NOTE> This currently only works when sitting in the perl source
949directory!
950
e4fc8a1e 951=item C<HARNESS_DEBUG>
952
953If true, Test::Harness will print debugging information about itself as
954it runs the tests. This is different from C<HARNESS_VERBOSE>, which prints
955the output from the test being run. Setting C<$Test::Harness::Debug> will
956override this, or you can use the C<-d> switch in the F<prove> utility.
957
b82fa0b7 958=item C<HARNESS_FILELEAK_IN_DIR>
37ce32a7 959
960When set to the name of a directory, harness will check after each
961test whether new files appeared in that directory, and report them as
17a79f5b 962
963 LEAKED FILES: scr.tmp 0 my.db
964
965If relative, directory name is with respect to the current directory at
966the moment runtests() was called. Putting absolute path into
13287dd5 967C<HARNESS_FILELEAK_IN_DIR> may give more predictable results.
17a79f5b 968
356733da 969=item C<HARNESS_NOTTY>
970
971When set to a true value, forces it to behave as though STDOUT were
972not a console. You may need to set this if you don't want harness to
973output more frequent progress messages using carriage returns. Some
974consoles may not handle carriage returns properly (which results in a
975somewhat messy output).
976
e4fc8a1e 977=item C<HARNESS_PERL>
978
979Usually your tests will be run by C<$^X>, the currently-executing Perl.
980However, you may want to have it run by a different executable, such as
981a threading perl, or a different version.
982
983If you're using the F<prove> utility, you can use the C<--perl> switch.
60af4b93 984
b82fa0b7 985=item C<HARNESS_PERL_SWITCHES>
37ce32a7 986
987Its value will be prepended to the switches used to invoke perl on
b82fa0b7 988each test. For example, setting C<HARNESS_PERL_SWITCHES> to C<-W> will
37ce32a7 989run all tests with all warnings enabled.
990
356733da 991=item C<HARNESS_VERBOSE>
37ce32a7 992
356733da 993If true, Test::Harness will output the verbose results of running
e4fc8a1e 994its tests. Setting C<$Test::Harness::verbose> will override this,
995or you can use the C<-v> switch in the F<prove> utility.
37ce32a7 996
997=back
0a931e4a 998
b82fa0b7 999=head1 EXAMPLE
1000
1001Here's how Test::Harness tests itself
1002
1003 $ cd ~/src/devel/Test-Harness
1004 $ perl -Mblib -e 'use Test::Harness qw(&runtests $verbose);
1005 $verbose=0; runtests @ARGV;' t/*.t
1006 Using /home/schwern/src/devel/Test-Harness/blib
1007 t/base..............ok
1008 t/nonumbers.........ok
1009 t/ok................ok
1010 t/test-harness......ok
1011 All tests successful.
1012 Files=4, Tests=24, 2 wallclock secs ( 0.61 cusr + 0.41 csys = 1.02 CPU)
f19ae7a7 1013
cb1a09d0 1014=head1 SEE ALSO
1015
42d29bac 1016The included F<prove> utility for running test scripts from the command line,
b82fa0b7 1017L<Test> and L<Test::Simple> for writing test scripts, L<Benchmark> for
3c87ea76 1018the underlying timing routines, and L<Devel::Cover> for test coverage
b82fa0b7 1019analysis.
c07a80fd 1020
b82fa0b7 1021=head1 TODO
1022
1023Provide a way of running tests quietly (ie. no printing) for automated
1024validation of tests. This will probably take the form of a version
1025of runtests() which rather than printing its output returns raw data
356733da 1026on the state of the tests. (Partially done in Test::Harness::Straps)
b82fa0b7 1027
cf2ab31a 1028Document the format.
1029
b82fa0b7 1030Fix HARNESS_COMPILE_TEST without breaking its core usage.
1031
1032Figure a way to report test names in the failure summary.
37ce32a7 1033
b82fa0b7 1034Rework the test summary so long test names are not truncated as badly.
308957f5 1035(Partially done with new skip test styles)
b82fa0b7 1036
b82fa0b7 1037Add option for coverage analysis.
1038
cf2ab31a 1039Trap STDERR.
1040
1041Implement Straps total_results()
1042
1043Remember exit code
1044
1045Completely redo the print summary code.
1046
1047Implement Straps callbacks. (experimentally implemented)
1048
1049Straps->analyze_file() not taint clean, don't know if it can be
1050
1051Fix that damned VMS nit.
1052
1053HARNESS_TODOFAIL to display TODO failures
1054
1055Add a test for verbose.
1056
1057Change internal list of test results to a hash.
1058
1059Fix stats display when there's an overrun.
1060
1061Fix so perls with spaces in the filename work.
1062
b82fa0b7 1063Keeping whittling away at _run_all_tests()
1064
b82fa0b7 1065Clean up how the summary is printed. Get rid of those damned formats.
cb1a09d0 1066
1067=head1 BUGS
1068
20f9f807 1069Please report any bugs or feature requests to
1070C<bug-test-harness at rt.cpan.org>, or through the web interface at
1071L<http://rt.cpan.org/NoAuth/ReportBug.html?Queue=Test-Harness>.
1072I will be notified, and then you'll automatically be notified of progress on
1073your bug as I make changes.
1074
1075=head1 SUPPORT
1076
1077You can find documentation for this module with the F<perldoc> command.
1078
1079 perldoc Test::Harness
1080
1081You can get docs for F<prove> with
1082
1083 prove --man
1084
1085You can also look for information at:
1086
1087=over 4
1088
1089=item * AnnoCPAN: Annotated CPAN documentation
1090
1091L<http://annocpan.org/dist/Test-Harness>
1092
1093=item * CPAN Ratings
1094
1095L<http://cpanratings.perl.org/d/Test-Harness>
1096
1097=item * RT: CPAN's request tracker
1098
1099L<http://rt.cpan.org/NoAuth/Bugs.html?Dist=Test-Harness>
1100
1101=item * Search CPAN
1102
1103L<http://search.cpan.org/dist/Test-Harness>
1104
1105=back
1106
1107=head1 SOURCE CODE
b82fa0b7 1108
20f9f807 1109The source code repository for Test::Harness is at
1110L<http://svn.perl.org/modules/Test-Harness>.
e4fc8a1e 1111
1112=head1 AUTHORS
1113
3c87ea76 1114Either Tim Bunce or Andreas Koenig, we don't know. What we know for
20f9f807 1115sure is, that it was inspired by Larry Wall's F<TEST> script that came
3c87ea76 1116with perl distributions for ages. Numerous anonymous contributors
1117exist. Andreas Koenig held the torch for many years, and then
1118Michael G Schwern.
1119
1120Current maintainer is Andy Lester C<< <andy at petdance.com> >>.
e4fc8a1e 1121
1122=head1 COPYRIGHT
1123
3c87ea76 1124Copyright 2002-2005
1125by Michael G Schwern C<< <schwern at pobox.com> >>,
1126Andy Lester C<< <andy at petdance.com> >>.
e4fc8a1e 1127
1128This program is free software; you can redistribute it and/or
1129modify it under the same terms as Perl itself.
1130
1131See L<http://www.perl.com/perl/misc/Artistic.html>.
1132
cb1a09d0 1133=cut