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