File Coverage

blib/lib/TAPx/Harness.pm
Criterion Covered Total %
statement 303 351 86.3
branch 111 160 69.3
condition 25 44 56.8
subroutine 37 39 94.8
pod 8 8 100.0
total 484 602 80.4


line stmt bran cond sub pod time code
1             package TAPx::Harness;
2              
3 2     2   36403 use strict;
  2         4  
  2         80  
4 2     2   10 use warnings;
  2         4  
  2         68  
5 2     2   3080 use Benchmark;
  2         30875  
  2         18  
6 2     2   509 use File::Spec;
  2         4  
  2         49  
7 2     2   13 use File::Path;
  2         3  
  2         153  
8              
9 2     2   557 use TAPx::Base;
  2         4  
  2         52  
10 2     2   541 use TAPx::Parser;
  2         4  
  2         55  
11 2     2   534 use TAPx::Parser::Aggregator;
  2         6  
  2         72  
12 2     2   518 use TAPx::Parser::YAML;
  2         4  
  2         117  
13              
14 2     2   13 use vars qw($VERSION @ISA);
  2         4  
  2         413  
15              
16             @ISA = qw(TAPx::Base);
17              
18             =head1 NAME
19              
20             TAPx::Harness - Run Perl test scripts with statistics
21              
22             =head1 VERSION
23              
24             Version 0.50_07
25              
26             =cut
27              
28             $VERSION = '0.50_07';
29              
30             $ENV{HARNESS_ACTIVE} = 1;
31             $ENV{HARNESS_VERSION} = $VERSION;
32              
33             END {
34              
35             # For VMS.
36 2     2   3756 delete $ENV{HARNESS_ACTIVE};
37 2         31 delete $ENV{HARNESS_VERSION};
38             }
39              
40             my $TIME_HIRES;
41              
42             BEGIN {
43 2     2   192 eval 'use Time::HiRes qw(time)';
  2     2   13  
  2         5  
  2         17  
44 2         1303 $TIME_HIRES = !$@;
45              
46             }
47              
48             =head1 DESCRIPTION
49              
50             This is a simple test harness which allows tests to be run and results
51             automatically aggregated and output to STDOUT.
52              
53             =head1 SYNOPSIS
54              
55             use TAPx::Harness;
56             my $harness = TAPx::Harness->new( \%args );
57             $harness->runtests(@tests);
58              
59             =cut
60              
61             my %VALIDATION_FOR;
62              
63             sub _error {
64 50     50   72 my $self = shift;
65 50 100       176 return $self->{error} unless @_;
66 6         18 $self->{error} = shift;
67             }
68              
69             BEGIN {
70             %VALIDATION_FOR = (
71             lib => sub {
72 8         12 my ( $self, $libs ) = @_;
73 8 100       32 $libs = [$libs] unless 'ARRAY' eq ref $libs;
74 8         11 my @bad_libs;
75 8         19 foreach my $lib (@$libs) {
76 12 100       209 unless ( -d $lib ) {
77 6         13 push @bad_libs, $lib;
78             }
79             }
80 8 100       26 if (@bad_libs) {
81 4         8 my $dirs = 'lib';
82 4 100       12 $dirs .= 's' if @bad_libs > 1;
83 4         30 $self->_error("No such $dirs (@bad_libs)");
84             }
85 8         16 return [ map {"-I$_"} @$libs ];
  12         46  
86             },
87             switches => sub {
88 6         12 my ( $self, $switches ) = @_;
89 6 100       25 $switches = [$switches] unless 'ARRAY' eq ref $switches;
90 6 100       116 my @switches = map { /^-/ ? $_ : "-$_" } @$switches;
  10         54  
91 6         9 my %found = map { $_ => 0 } @switches;
  10         33  
92 6         11 @switches = grep { !$found{$_}++ } @switches;
  10         32  
93 6         20 return \@switches;
94             },
95 1         3 directives => sub { shift; shift },
  1         3  
96 6         9 verbose => sub { shift; shift },
  6         12  
97 0         0 timer => sub { shift; shift },
  0         0  
98 4         8 failures => sub { shift; shift },
  4         6  
99 0         0 errors => sub { shift; shift },
  0         0  
100 3         5 quiet => sub { shift; shift },
  3         5  
101 3         7 really_quiet => sub { shift; shift },
  3         5  
102 3         6 exec => sub { shift; shift },
  3         7  
103             execrc => sub {
104 4         10 my ( $self, $execrc ) = @_;
105 4 100       112 unless ( -f $execrc ) {
106 2         13 $self->_error("Cannot find execrc ($execrc)");
107             }
108 4         11 return $execrc;
109             },
110 2     2   76 );
111 2         8 my @getter_setters = qw/
112             _curr_parser
113             _curr_test
114             _execrc
115             _longest
116             _newline_printed
117             _printed_summary_header
118             /;
119              
120 2         11 foreach my $method ( @getter_setters, keys %VALIDATION_FOR ) {
121 2     2   13 no strict 'refs';
  2         2  
  2         418  
122 34 100 100     126 if ( $method eq 'lib' || $method eq 'switches' ) {
123             *$method = sub {
124 60     60   98 my $self = shift;
125 60 100       149 unless (@_) {
126 50   100     206 $self->{$method} ||= [];
127             return
128 50 100       220 wantarray ? @{ $self->{$method} } : $self->{$method};
  20         62  
129             }
130 10 50       27 $self->_croak("Too many arguments to &\$method")
131             if @_ > 1;
132 10         15 my $args = shift;
133 10 50       24 $args = [$args] unless ref $args;
134 10         21 $self->{$method} = $args;
135 10         23 return $self;
136 4         29 };
137             }
138             else {
139             *$method = sub {
140 426     426   591 my $self = shift;
141 426 100       2087 return $self->{$method} unless @_;
142 123         336 $self->{$method} = shift;
143 30         23837 };
144             }
145             }
146             }
147              
148             ##############################################################################
149              
150             =head1 METHODS
151              
152             =head2 Class methods
153              
154             =head3 C
155              
156             my %args = (
157             verbose => 1,
158             lib => [ 'lib', 'blib/lib' ],
159             )
160             my $harness = TAPx::Harness->new( \%args );
161              
162             The constructor returns a new C object. It accepts an optional
163             hashref whose allowed keys are:
164              
165             =over 4
166              
167             =item * C
168              
169             Print individual test results to STDOUT.
170              
171             =item * C
172              
173             Append run time for each test to output. Uses Time::HiRes if available.
174              
175             =item * C
176              
177             Only show test failures (this is a no-op if C is selected).
178              
179             =item * C
180              
181             Accepts a scalar value or array ref of scalar values indicating which paths to
182             allowed libraries should be included if Perl tests are executed. Naturally,
183             this only makes sense in the context of tests written in Perl.
184              
185             =item * C
186              
187             Accepts a scalar value or array ref of scalar values indicating which switches
188             should be included if Perl tests are executed. Naturally, this only makes
189             sense in the context of tests written in Perl.
190              
191             =item * C
192              
193             Suppress some test output (mostly failures while tests are running).
194              
195             =item * C
196              
197             Suppress everything but the tests summary.
198              
199             =item * C
200              
201             Typically, Perl tests are run through this. However, anything which spits out
202             TAP is fine. You can use this argument to specify the name of the program
203             (and optional switches) to run your tests with:
204              
205             exec => '/usr/bin/ruby -w'
206              
207             =item * C
208              
209             Location of 'execrc' file. See L below.
210              
211             =item * C
212              
213             If parse errors are found in the TAP output, a note of this will be made
214             in the summary report. To see all of the parse errors, set this argument to
215             true:
216              
217             errors => 1
218              
219             =item * C
220              
221             If set to a true value, only test results with directives will be displayed.
222             This overrides other settings such as C or C.
223              
224             =back
225              
226             =cut
227              
228             # new supplied by TAPx::Base
229              
230             {
231             my @legal_callback = qw(
232             made_parser
233             );
234              
235             sub _initialize {
236 28     28   37 my ( $self, $arg_for ) = @_;
237 28   100     98 $arg_for ||= {};
238 28         122 $self->SUPER::_initialize( $arg_for, \@legal_callback );
239 28         91 my %arg_for = %$arg_for; # force a shallow copy
240              
241 28         110 foreach my $name ( keys %VALIDATION_FOR ) {
242 296         332 my $property = delete $arg_for{$name};
243 296 100       591 if ( defined $property ) {
244 38         57 my $validate = $VALIDATION_FOR{$name};
245              
246 38         96 my $value = $self->$validate($property);
247 38 100       114 if ( $self->_error ) {
248 6         15 $self->_croak;
249             }
250 32         111 $self->$name($value);
251             }
252             }
253 22 100       92 if ( my @props = keys %arg_for ) {
254 2         20 $self->_croak("Unknown arguments to TAPx::Harness::new (@props)");
255             }
256 20         59 $self->_read_execrc;
257 20 100       49 $self->quiet(0) unless $self->quiet; # suppress unit warnings
258 20 100       46 $self->really_quiet(0) unless $self->really_quiet;
259 20         105 return $self;
260             }
261             }
262              
263             sub _read_execrc {
264 20     20   33 my $self = shift;
265 20         61 $self->_execrc( {} );
266 20 100       58 my $execrc = $self->execrc or return;
267 2         1007 my $data = TAPx::Parser::YAML->read($execrc);
268 2         16 my $tests = $data->[0]{tests};
269              
270 2         4 my %exec_for;
271 2         6 foreach my $exec (@$tests) {
272 0 0       0 if ( '*' eq $exec->[-1] ) {
273 0         0 pop @$exec;
274              
275             # don't override command line
276 0 0       0 $self->exec($exec) unless $self->exec;
277             }
278             else {
279 0         0 $exec_for{ $exec->[-1] } = $exec;
280             }
281             }
282 2         16 $self->_execrc( \%exec_for );
283 2         16 return $self;
284             }
285              
286             ##############################################################################
287              
288             =head2 Instance Methods
289              
290             =head3 C
291              
292             $harness->runtests(@tests);
293              
294             Accepts and array of C<@tests> to be run. This should generally be the names
295             of test files, but this is not required. Each element in C<@tests> will be
296             passed to C as a C. See C for more
297             information.
298              
299             Tests will be run in the order found.
300              
301             If the environment variable PERL_TEST_HARNESS_DUMP_TAP is defined it
302             should name a directory into which a copy of the raw TAP for each test
303             will be written. TAP is written to files named for each test.
304             Subdirectories will be created as needed.
305              
306             =cut
307              
308             sub runtests {
309 9     9 1 16366 my ( $self, @tests ) = @_;
310              
311 9         137 my $aggregate = TAPx::Parser::Aggregator->new;
312              
313 9         40 my $results = $self->aggregate_tests( $aggregate, @tests );
314              
315 9         1152 $self->summary($results);
316             }
317              
318             =head3 C
319              
320             $harness->aggregate_tests( $aggregate, @tests );
321              
322             Tests will be run in the order found.
323              
324             =cut
325              
326             sub aggregate_tests {
327 9     9 1 28 my ( $self, $aggregate, @tests ) = @_;
328              
329 9         11 my $longest = 0;
330              
331 9         16 my $tests_without_extensions = 0;
332 9         22 foreach my $test (@tests) {
333 10 100       61 $longest = length $test if length $test > $longest;
334 10 50       52 if ( $test !~ /\.\w+$/ ) {
335 10         28 $tests_without_extensions = 1;
336             }
337             }
338 9         31 $self->_longest($longest);
339              
340 9         59 my $start_time = Benchmark->new;
341              
342 9         177 my $really_quiet = $self->really_quiet;
343 9         23 foreach my $test (@tests) {
344 10         16 my $extra = 0;
345 10         23 my $name = $test;
346 10 50       27 unless ($tests_without_extensions) {
347 0 0       0 if ( $name =~ s/(\.\w+)$// ) { # strip the .t or .pm
348 0         0 $extra = length $1;
349             }
350             }
351 10         45 my $periods = '.' x ( $longest + $extra + 4 - length $test );
352              
353 10         61 my $parser = $self->_runtest( "$name$periods", $test );
354 10         133 $aggregate->add( $test, $parser );
355             }
356              
357             return {
358 9         211 start => $start_time,
359             end => Benchmark->new,
360             aggregate => $aggregate,
361             tests => \@tests
362             };
363             }
364              
365             ##############################################################################
366              
367             =head1 SUBCLASSING
368              
369             C is designed to be (mostly) easy to subclass. If you don't
370             like how a particular feature functions, just override the desired methods.
371              
372             =head2 Methods
373              
374             The following methods are one's you may wish to override if you want to
375             subclass C.
376              
377             =head3 C
378              
379             $harness->summary( \%args );
380              
381             C prints the summary report after all tests are run. The argument is
382             a hashref with the following keys:
383              
384             =over 4
385              
386             =item * C
387              
388             This is created with C<< Benchmark->new >> and it the time the tests started.
389             You can print a useful summary time, if desired, with:
390              
391             $self->output(timestr( timediff( Benchmark->new, $start_time ), 'nop' ));
392              
393             =item * C
394              
395             This is the C object for all of the tests run.
396              
397             =item * C
398              
399             This is an array reference of all test names. To get the C
400             object for individual tests:
401              
402             my $aggregate = $args->{aggregate};
403             my $tests = $args->{tests};
404              
405             foreach my $name ( @$tests ) {
406             my ($parser) = $aggregate->parsers($test);
407             ... do something with $parser
408             }
409              
410             This is a bit clunky and will be cleaned up in a later release.
411              
412             =back
413              
414             =cut
415              
416             sub summary {
417 9     9 1 21 my ( $self, $arg_for ) = @_;
418 9         37 my ( $start_time, $aggregate, $tests )
419             = @$arg_for{qw< start aggregate tests >};
420              
421 9   33     41 my $end_time = $arg_for->{end} || Benchmark->new;
422              
423 9         156 my $runtime = timestr( timediff( $end_time, $start_time ), 'nop' );
424              
425 9         1802 my $total = $aggregate->total;
426 9         41 my $passed = $aggregate->passed;
427              
428             # TODO: Check this condition still works when all subtests pass but
429             # the exit status is nonzero
430              
431 9 100 66     143 if ( $total && $total == $passed && !$aggregate->has_problems ) {
      66        
432 5         23 $self->output("All tests successful.\n");
433             }
434 9 100 66     194 if ( $total != $passed
      100        
435             or $aggregate->has_problems
436             or $aggregate->skipped )
437             {
438 5         28 $self->output("\nTest Summary Report");
439 5         140 $self->output("\n-------------------\n");
440 5         105 foreach my $test (@$tests) {
441 5         17 $self->_printed_summary_header(0);
442 5         25 my ($parser) = $aggregate->parsers($test);
443 5         20 $self->_curr_test($test);
444 5         21 $self->_curr_parser($parser);
445 5         80 $self->_output_summary_failure( 'failed', " Failed tests: " );
446 5         14 $self->_output_summary_failure(
447             'todo_passed',
448             " TODO passed: "
449             );
450 5         17 $self->_output_summary_failure( 'skipped', " Tests skipped: " );
451              
452 5 50       15 if ( my $exit = $parser->exit ) {
453 0         0 $self->_summary_test_header( $test, $parser );
454 0         0 $self->failure_output(" Non-zero exit status: $exit\n");
455             }
456              
457 5 100       17 if ( my @errors = $parser->parse_errors ) {
458 1         7 $self->_summary_test_header( $test, $parser );
459 1 50 33     7 if ( $self->errors || 1 == @errors ) {
460 1         9 $self->failure_output(
461             sprintf " Parse errors: %s\n",
462             shift @errors
463             );
464 1         23 foreach my $error (@errors) {
465 0         0 my $spaces = ' ' x 16;
466 0         0 $self->failure_output("$spaces$error\n");
467             }
468             }
469             else {
470 0         0 $self->failure_output(
471             " Errors encountered while parsing tap\n");
472             }
473             }
474             }
475             }
476 9         34 my $files = @$tests;
477 9         65 $self->output("Files=$files, Tests=$total, $runtime\n");
478             }
479              
480             sub _output_summary_failure {
481 15     15   55 my ( $self, $method, $name ) = @_;
482              
483             # ugly hack. Must rethink this :(
484 15 100       52 my $output = $method eq 'failed' ? 'failure_output' : 'output';
485 15         35 my $test = $self->_curr_test;
486 15         34 my $parser = $self->_curr_parser;
487 15 100       44 if ( $parser->$method ) {
488 5         25 $self->_summary_test_header( $test, $parser );
489 5         15 $self->$output($name);
490 5         94 my @results = $self->balanced_range( 40, $parser->$method );
491 5         29 $self->$output( sprintf "%s\n" => shift @results );
492 5         61 my $spaces = ' ' x 16;
493 5         25 while (@results) {
494 0         0 $self->$output( sprintf "$spaces%s\n" => shift @results );
495             }
496             }
497             }
498              
499             sub _summary_test_header {
500 6     6   12 my ( $self, $test, $parser ) = @_;
501 6 100       14 return if $self->_printed_summary_header;
502 5         32 my $spaces = ' ' x ( $self->_longest - length $test );
503 5 50       17 $spaces = ' ' unless $spaces;
504 5         18 my $output = $self->_get_output_method($parser);
505 5         25 $self->$output(
506             sprintf "$test$spaces(Wstat: %d Tests: %d Failed: %d)\n",
507             $parser->wait, $parser->tests_run, scalar $parser->failed
508             );
509 5         144 $self->_printed_summary_header(1);
510             }
511              
512             ##############################################################################
513              
514             =head3 C
515              
516             $harness->output(@list_of_strings_to_output);
517              
518             All output from C is driven through this method. If you would
519             like to redirect output somewhere else, just override this method.
520              
521             =cut
522              
523             sub output {
524 0     0 1 0 my $self = shift;
525 0         0 print @_;
526             }
527              
528             ##############################################################################
529              
530             =head3 C
531              
532             $harness->failure_output(@list_of_strings_to_output);
533              
534             Identical to C, this method is called for any output which represents
535             a failure.
536              
537             =cut
538              
539             sub failure_output {
540 16     16 1 53 shift->output(@_);
541             }
542              
543             ##############################################################################
544              
545             =head3 C
546              
547             my @ranges = $harness->balanced_range( $limit, @numbers );
548              
549             Given a limit in the number of characters and a list of numbers, this method
550             first creates a range of numbers with C and then groups them into
551             individual strings which are roughly the length of C<$limit>. Returns an
552             array of strings.
553              
554             =cut
555              
556             sub balanced_range {
557 7     7 1 2436 my ( $self, $limit, @range ) = @_;
558 7         38 @range = $self->range(@range);
559 7         33 my $line = "";
560 7         11 my @lines;
561 7         15 my $curr = 0;
562 7         22 while (@range) {
563 13 100       52 if ( $curr < $limit ) {
    50          
564 11         22 my $range = ( shift @range ) . ", ";
565 11         22 $line .= $range;
566 11         34 $curr += length $range;
567             }
568             elsif (@range) {
569 2         12 $line =~ s/, $//;
570 2         4 push @lines => $line;
571 2         4 $line = '';
572 2         6 $curr = 0;
573             }
574             }
575 7 50       23 if ($line) {
576 7         69 $line =~ s/, $//;
577 7         20 push @lines => $line;
578             }
579 7         30 return @lines;
580             }
581              
582             ##############################################################################
583              
584             =head3 C
585              
586             my @range = $harness->range(@list_of_numbers);
587              
588             Taks a list of numbers, sorts them, and returns a list of ranged strings:
589              
590             print join ', ' $harness->range( 2, 7, 1, 3, 10, 9 );
591             # 1-3, 7, 9-10
592              
593             =cut
594              
595             sub range {
596 7     7 1 22 my ( $self, @numbers ) = @_;
597              
598             # shouldn't be needed, but subclasses might call this
599 7         28 @numbers = sort { $a <=> $b } @numbers;
  20         30  
600 7         13 my ( $min, @range );
601              
602 7         38 foreach my $i ( 0 .. $#numbers ) {
603 17         28 my $num = $numbers[$i];
604 17         27 my $next = $numbers[ $i + 1 ];
605 17 100 100     96 if ( defined $next && $next == $num + 1 ) {
    100          
606 6 100       15 if ( !defined $min ) {
607 4         11 $min = $num;
608             }
609             }
610             elsif ( defined $min ) {
611 4         11 push @range => "$min-$num";
612 4         14 undef $min;
613             }
614             else {
615 7         42 push @range => $num;
616             }
617             }
618 7         32 return @range;
619             }
620              
621             ##############################################################################
622              
623             =head3 C
624              
625             $harness->output_test_failure($parser);
626              
627             As individual test programs are run, if a test program fails, this method is
628             called to spit out the list of failed tests.
629              
630             =cut
631              
632             sub output_test_failure {
633 4     4 1 20 my ( $self, $parser ) = @_;
634 4 100       18 return if $self->really_quiet;
635              
636 3         19 my $tests_run = $parser->tests_run;
637 3         13 my $tests_planned = $parser->tests_planned;
638              
639 3 50       23 my $total =
640             defined $tests_planned
641             ? $tests_planned
642             : $tests_run;
643              
644 3         17 my $passed = $parser->passed;
645              
646             # The total number of fails includes any tests that were planned but
647             # didn't run
648 3         14 my $failed = $parser->failed + $total - $tests_run;
649 3         10 my $exit = $parser->exit;
650              
651             # TODO: $flist isn't used anywhere
652             # my $flist = join ", " => $self->range( $parser->failed );
653              
654 3 50       10 if ( my $exit = $parser->exit ) {
655 0         0 my $wstat = $parser->wait;
656 0         0 my $status = sprintf( "%d (wstat %d, 0x%x)", $exit, $wstat, $wstat );
657 0         0 $self->failure_output(" Dubious, test returned $status\n");
658             }
659              
660 3 50       33 if ( $failed == 0 ) {
661 0         0 $self->failure_output(" All $total subtests passed ");
662             }
663             else {
664 3         24 $self->failure_output(" Failed $failed/$total subtests ");
665 3 50       98 if ( !$total ) {
666 0         0 $self->failure_output("\nNo tests run!");
667             }
668             }
669              
670 3 50       16 if ( my $skipped = $parser->skipped ) {
671 0         0 $passed -= $skipped;
672 0 0       0 my $test = 'subtest' . ( $skipped != 1 ? 's' : '' );
673 0         0 $self->output("\n\t(less $skipped skipped $test: $passed okay)");
674             }
675              
676 3 50       11 if ( my $failed = $parser->todo_passed ) {
677 0 0       0 my $test = $failed > 1 ? 'tests' : 'test';
678 0         0 $self->output("\n\t($failed TODO $test unexpectedly succeeded)");
679             }
680              
681 3         15 $self->output("\n");
682             }
683              
684             sub _runtest {
685 10     10   20 my ( $self, $leader, $test ) = @_;
686              
687 10         64 my $execrc = $self->_execrc;
688 10         27 my $really_quiet = $self->really_quiet;
689 10         43 my $show_count = $self->_should_show_count;
690 10 100       88 $self->output($leader) unless $really_quiet;
691              
692 10         305 my %args = ( source => $test );
693 10 50       67 my @switches = $self->lib if $self->lib;
694 10 50       35 push @switches => $self->switches if $self->switches;
695 10         36 $args{switches} = \@switches;
696              
697 10 50       48 if ( my $exec = $execrc->{$test} ) {
    100          
698 0         0 $args{exec} = $exec;
699 0         0 delete $args{source};
700             }
701             elsif ( $exec = $self->exec ) {
702 2         12 $args{exec} = [ @$exec, $test ];
703 2         10 delete $args{source};
704             }
705              
706 10         40 $args{spool} = $self->_open_spool($test);
707              
708 10         90 my $parser = TAPx::Parser->new( \%args );
709              
710 10         190 $self->_make_callback( 'made_parser', $parser );
711              
712 10         52 my $plan = '';
713 10         108 $self->_newline_printed(0);
714 10         63 my $start_time = time();
715 10         51 my $output = 'output';
716 10         172 while ( defined( my $result = $parser->next ) ) {
717 27         291 $output = $self->_get_output_method($parser);
718 27 50       120 if ( $result->is_bailout ) {
719 0         0 $self->failure_output(
720             "Bailout called. Further testing stopped: "
721             . $result->explanation
722             . "\n" );
723 0         0 exit 1;
724             }
725 27 100       86 unless ($plan) {
726 10   50     38 $plan = '/' . ( $parser->tests_planned || 0 ) . ' ';
727             }
728 27 50 33     118 if ( $show_count && $result->is_test ) {
729 0 0       0 $self->$output( "\r$leader" . $result->number . $plan )
730             unless $really_quiet;
731 0         0 $self->_newline_printed(0);
732             }
733 27         165 $self->_process( $parser, $result );
734             }
735              
736 10         96 $self->_close_spool;
737              
738 10 50       21 if ($show_count) {
739 0         0 my $spaces = ' ' x (
740             1 + length($leader) + length($plan) + length( $parser->tests_run )
741             );
742 0 0       0 $self->$output("\r$spaces\r$leader") unless $really_quiet;
743             }
744 10 100       31 if ( !$parser->has_problems ) {
745 6 100       19 unless ($really_quiet) {
746 5         13 my $time_report = '';
747 5 50       25 if ( $self->timer ) {
748 0         0 my $elapsed = time - $start_time;
749 0 0 0     0 $time_report = $TIME_HIRES
750             ? sprintf( ' %8d ms', $elapsed * 1000 )
751             : sprintf( ' %8s s', $elapsed || '<1' );
752             }
753              
754 5         32 $self->output("ok$time_report\n");
755             }
756             }
757             else {
758 4         31 $self->output_test_failure($parser);
759             }
760 10         383 return $parser;
761             }
762              
763             sub _open_spool {
764 10     10   16 my $self = shift;
765 10         15 my $test = shift;
766              
767 10 50       138 if ( my $spool_dir = $ENV{PERL_TEST_HARNESS_DUMP_TAP} ) {
768 0         0 my $spool = File::Spec->catfile( $spool_dir, $test );
769              
770             # Make the directory
771 0         0 my ( $vol, $dir, $file ) = File::Spec->splitpath($spool);
772 0         0 my $path = File::Spec->catdir( $vol, $dir );
773 0         0 eval { mkpath($path) };
  0         0  
774 0 0       0 $self->_croak($@) if $@;
775              
776 0 0       0 open( my $spool_handle, '>', $spool )
777             or $self->_croak(" Can't write $spool ( $! ) ");
778 0         0 return $self->{spool} = $spool_handle;
779             }
780              
781 10         61 return;
782             }
783              
784             sub _close_spool {
785 10     10   15 my $self = shift;
786              
787 10 50       48 if ( my $spool_handle = delete $self->{spool} ) {
788 0 0       0 close($spool_handle)
789             or $self->_croak(" Error closing TAP spool file( $! ) \n ");
790             }
791             }
792              
793             sub _process {
794 27     27   79 my ( $self, $parser, $result ) = @_;
795 27 100       509 return if $self->really_quiet;
796 22 100       67 if ( $self->_should_display( $parser, $result ) ) {
797 15 100       37 unless ( $self->_newline_printed ) {
798 6 50       32 $self->output("\n") unless $self->quiet;
799 6         216 $self->_newline_printed(1);
800             }
801 15 50       32 $self->output( $result->as_string . "\n" ) unless $self->quiet;
802             }
803             }
804              
805             sub _get_output_method {
806 32     32   50 my ( $self, $parser ) = @_;
807 32 100       119 return $parser->has_problems ? 'failure_output' : 'output';
808             }
809              
810             # XXX this really needs some cleanup!
811             sub _should_display {
812 22     22   30 my ( $self, $parser, $result ) = @_;
813 22 100       375 if ( $self->directives ) {
814 4         66 return $result->has_directive;
815             }
816 18 50       44 return if $self->really_quiet;
817 18   33     66 return $self->verbose && !$self->failures
818             || ( $result->is_comment
819             && !$self->quiet
820             && ( $result->is_test || !$parser->in_todo ) )
821             || $self->_should_show_failure($result);
822             }
823              
824             sub _should_show_count {
825              
826             # we need this because if someone tries to redirect the output, it can get
827             # very garbled from the carriage returns (\r) in the count line.
828 0   0 0   0 return !shift->verbose && -t STDOUT;
829             }
830              
831             sub _should_show_failure {
832 5     5   16 my ( $self, $result ) = @_;
833 5 100       23 return if !$result->is_test;
834 3   33     23 return $self->failures && !$result->is_ok;
835             }
836              
837             sub _croak {
838 8     8   13 my ( $self, $message ) = @_;
839 8 100       21 unless ($message) {
840 6         13 $message = $self->_error;
841             }
842 8         31 $self->SUPER::_croak($message);
843             }
844              
845             =head1 USING EXECRC
846              
847             B: this functionality is still experimental. While we intend to
848             support it, the file format may change.
849              
850             Sometimes you want to use different executables to run different tests. If
851             that's the case, you'll need to create an C file. This file should be
852             a YAML file. This should be representative a hash with one key, C,
853             whose value is an array of array references. Each terminating array reference
854             should be a list of the exact arguments which eventually get executed.
855              
856             ---
857             tests:
858             # this is the default for all files
859             -
860             - /usr/bin/perl
861             - -wT
862             - *
863            
864             # whoops! We have a ruby test here!
865             -
866             - /usr/bin/ruby
867             - t/ruby.t
868            
869             # let's test some web pages
870             -
871             - /usr/bin/perl
872             - -w
873             - bin/test_html.pl
874             - http://www.google.com/
875             -
876             - /usr/bin/perl
877             - -w
878             - bin/test_html.pl
879             - http://www.yahoo.com/
880              
881             If the terminating element in an array is '*', then the rest of the array are
882             the default arguments used to run any test.
883              
884             Blank lines are allowed. Lines beginning with a '#' are comments (the '#' may
885             have spaces in front of it).
886              
887             So for the above C file, if it's named 'my_execrc' (as it is in the
888             C directory which comes with this distribution), then you could
889             potentially run it like this, if you're using the C utility:
890              
891             runtests --execrc my_execrc t/ - < list_of_urls.txt
892              
893             Then for a test named C, it will be executed
894             with:
895              
896             /usr/bin/ruby -w t/test_is_written_in_ruby.t
897              
898             If the list of urls contains "http://www.google.com/", it will be executed as
899             follows:
900              
901             /usr/bin/perl test_html.pl http://www.google.com/
902              
903             Of course, if C outputs anything other than TAP, this will fail.
904              
905             See the C in the C directory for a ready-to-run example.
906              
907             =head1 REPLACING
908              
909             If you like the C utility and L but you want your own
910             harness, all you need to do is write one and provide C and C
911             methods. Then you can use the C utility like so:
912              
913             runtests --harness My::Test::Harness
914              
915             Note that while C accepts a list of tests (or things to be tested),
916             C has a fairly rich set of arguments. You'll probably want to read over
917             this code carefully to see how all of them are being used.
918              
919             =head1 SEE ALSO
920              
921             L
922              
923             =cut
924              
925             1;