bring Test::Harness up to 3.06
[p5sagit/p5-mst-13.2.git] / lib / TAP / Harness.pm
CommitLineData
b965d173 1package TAP::Harness;
2
3use strict;
4use Carp;
5
6use File::Spec;
7use File::Path;
8use IO::Handle;
9
10use TAP::Base;
11use TAP::Parser;
12use TAP::Parser::Aggregator;
13use TAP::Parser::Multiplexer;
14
15use vars qw($VERSION @ISA);
16
17@ISA = qw(TAP::Base);
18
19=head1 NAME
20
21TAP::Harness - Run test scripts with statistics
22
23=head1 VERSION
24
69f36734 25Version 3.06
b965d173 26
27=cut
28
69f36734 29$VERSION = '3.06';
b965d173 30
31$ENV{HARNESS_ACTIVE} = 1;
32$ENV{HARNESS_VERSION} = $VERSION;
33
34END {
35
36 # For VMS.
37 delete $ENV{HARNESS_ACTIVE};
38 delete $ENV{HARNESS_VERSION};
39}
40
41=head1 DESCRIPTION
42
43This is a simple test harness which allows tests to be run and results
44automatically aggregated and output to STDOUT.
45
46=head1 SYNOPSIS
47
48 use TAP::Harness;
49 my $harness = TAP::Harness->new( \%args );
50 $harness->runtests(@tests);
51
52=cut
53
54my %VALIDATION_FOR;
55my @FORMATTER_ARGS;
56
57sub _error {
58 my $self = shift;
59 return $self->{error} unless @_;
60 $self->{error} = shift;
61}
62
63BEGIN {
64
65 @FORMATTER_ARGS = qw(
66 directives verbosity timer failures errors stdout color
67 );
68
69 %VALIDATION_FOR = (
70 lib => sub {
71 my ( $self, $libs ) = @_;
72 $libs = [$libs] unless 'ARRAY' eq ref $libs;
73
74 return [ map {"-I$_"} @$libs ];
75 },
76 switches => sub { shift; shift },
77 exec => sub { shift; shift },
78 merge => sub { shift; shift },
79 formatter_class => sub { shift; shift },
80 formatter => sub { shift; shift },
81 jobs => sub { shift; shift },
82 fork => sub { shift; shift },
83 test_args => sub { shift; shift },
84 );
85
86 for my $method ( sort keys %VALIDATION_FOR ) {
87 no strict 'refs';
88 if ( $method eq 'lib' || $method eq 'switches' ) {
89 *{$method} = sub {
90 my $self = shift;
91 unless (@_) {
92 $self->{$method} ||= [];
93 return wantarray
94 ? @{ $self->{$method} }
95 : $self->{$method};
96 }
97 $self->_croak("Too many arguments to method '$method'")
98 if @_ > 1;
99 my $args = shift;
100 $args = [$args] unless ref $args;
101 $self->{$method} = $args;
102 return $self;
103 };
104 }
105 else {
106 *{$method} = sub {
107 my $self = shift;
108 return $self->{$method} unless @_;
109 $self->{$method} = shift;
110 };
111 }
112 }
113
114 for my $method (@FORMATTER_ARGS) {
115 no strict 'refs';
116 *{$method} = sub {
117 my $self = shift;
118 return $self->formatter->$method(@_);
119 };
120 }
121}
122
123##############################################################################
124
125=head1 METHODS
126
127=head2 Class Methods
128
129=head3 C<new>
130
131 my %args = (
132 verbosity => 1,
133 lib => [ 'lib', 'blib/lib' ],
134 )
135 my $harness = TAP::Harness->new( \%args );
136
137The constructor returns a new C<TAP::Harness> object. It accepts an optional
138hashref whose allowed keys are:
139
140=over 4
141
142=item * C<verbosity>
143
144Set the verbosity level:
145
146 1 verbose Print individual test results to STDOUT.
147 0 normal
148 -1 quiet Suppress some test output (mostly failures
149 while tests are running).
150 -2 really quiet Suppress everything but the tests summary.
151
152=item * C<timer>
153
154Append run time for each test to output. Uses L<Time::HiRes> if available.
155
156=item * C<failures>
157
158Only show test failures (this is a no-op if C<verbose> is selected).
159
160=item * C<lib>
161
162Accepts a scalar value or array ref of scalar values indicating which paths to
163allowed libraries should be included if Perl tests are executed. Naturally,
164this only makes sense in the context of tests written in Perl.
165
166=item * C<switches>
167
168Accepts a scalar value or array ref of scalar values indicating which switches
169should be included if Perl tests are executed. Naturally, this only makes
170sense in the context of tests written in Perl.
171
172=item * C<test_args>
173
174A reference to an C<@INC> style array of arguments to be passed to each
175test program.
176
177=item * C<color>
178
179Attempt to produce color output.
180
181=item * C<exec>
182
183Typically, Perl tests are run through this. However, anything which spits out
184TAP is fine. You can use this argument to specify the name of the program
185(and optional switches) to run your tests with:
186
187 exec => ['/usr/bin/ruby', '-w']
188
189=item * C<merge>
190
191If C<merge> is true the harness will create parsers that merge STDOUT
192and STDERR together for any processes they start.
193
194=item * C<formatter_class>
195
196The name of the class to use to format output. The default is
197L<TAP::Formatter::Console>.
198
199=item * C<formatter>
200
201If set C<formatter> must be an object that is capable of formatting the
202TAP output. See L<TAP::Formatter::Console> for an example.
203
204=item * C<errors>
205
206If parse errors are found in the TAP output, a note of this will be made
207in the summary report. To see all of the parse errors, set this argument to
208true:
209
210 errors => 1
211
212=item * C<directives>
213
214If set to a true value, only test results with directives will be displayed.
215This overrides other settings such as C<verbose> or C<failures>.
216
217=item * C<stdout>
218
219A filehandle for catching standard output.
220
221=back
222
223Any keys for which the value is C<undef> will be ignored.
224
225=cut
226
227# new supplied by TAP::Base
228
229{
230 my @legal_callback = qw(
231 parser_args
232 made_parser
233 before_runtests
234 after_runtests
235 after_test
236 );
237
238 sub _initialize {
239 my ( $self, $arg_for ) = @_;
240 $arg_for ||= {};
241
242 $self->SUPER::_initialize( $arg_for, \@legal_callback );
243 my %arg_for = %$arg_for; # force a shallow copy
244
245 for my $name ( sort keys %VALIDATION_FOR ) {
246 my $property = delete $arg_for{$name};
247 if ( defined $property ) {
248 my $validate = $VALIDATION_FOR{$name};
249
250 my $value = $self->$validate($property);
251 if ( $self->_error ) {
252 $self->_croak;
253 }
254 $self->$name($value);
255 }
256 }
257
258 $self->jobs(1) unless defined $self->jobs;
259
260 unless ( $self->formatter ) {
261
262 $self->formatter_class( my $class = $self->formatter_class
263 || 'TAP::Formatter::Console' );
264
265 croak "Bad module name $class"
266 unless $class =~ /^ \w+ (?: :: \w+ ) *$/x;
267
268 eval "require $class";
269 $self->_croak("Can't load $class") if $@;
270
271 # This is a little bodge to preserve legacy behaviour. It's
272 # pretty horrible that we know which args are destined for
273 # the formatter.
274 my %formatter_args = ( jobs => $self->jobs );
275 for my $name (@FORMATTER_ARGS) {
276 if ( defined( my $property = delete $arg_for{$name} ) ) {
277 $formatter_args{$name} = $property;
278 }
279 }
280
281 $self->formatter( $class->new( \%formatter_args ) );
282 }
283
284 if ( my @props = sort keys %arg_for ) {
285 $self->_croak("Unknown arguments to TAP::Harness::new (@props)");
286 }
287
288 return $self;
289 }
290}
291
292##############################################################################
293
294=head2 Instance Methods
295
296=head3 C<runtests>
297
298 $harness->runtests(@tests);
299
300Accepts and array of C<@tests> to be run. This should generally be the names
301of test files, but this is not required. Each element in C<@tests> will be
302passed to C<TAP::Parser::new()> as a C<source>. See L<TAP::Parser> for more
303information.
304
305It is possible to provide aliases that will be displayed in place of the
306test name by supplying the test as a reference to an array containing
307C<< [ $test, $alias ] >>:
308
309 $harness->runtests( [ 't/foo.t', 'Foo Once' ],
310 [ 't/foo.t', 'Foo Twice' ] );
311
312Normally it is an error to attempt to run the same test twice. Aliases
313allow you to overcome this limitation by giving each run of the test a
314unique name.
315
316Tests will be run in the order found.
317
318If the environment variable C<PERL_TEST_HARNESS_DUMP_TAP> is defined it
319should name a directory into which a copy of the raw TAP for each test
320will be written. TAP is written to files named for each test.
321Subdirectories will be created as needed.
322
323Returns a L<TAP::Parser::Aggregator> containing the test results.
324
325=cut
326
327sub runtests {
328 my ( $self, @tests ) = @_;
329
330 my $aggregate = TAP::Parser::Aggregator->new;
331
332 $self->_make_callback( 'before_runtests', $aggregate );
333 $self->aggregate_tests( $aggregate, @tests );
334 $self->formatter->summary($aggregate);
335 $self->_make_callback( 'after_runtests', $aggregate );
336
337 return $aggregate;
338}
339
340=head3 C<aggregate_tests>
341
342 $harness->aggregate_tests( $aggregate, @tests );
343
344Tests will be run in the order found.
345
346=cut
347
348sub _after_test {
349 my ( $self, $aggregate, $test, $parser ) = @_;
350
351 $self->_make_callback( 'after_test', $test, $parser );
352 $aggregate->add( $test->[1], $parser );
353}
354
355sub _aggregate_forked {
356 my ( $self, $aggregate, @tests ) = @_;
357
358 eval { require Parallel::Iterator };
359
360 croak "Parallel::Iterator required for --fork option ($@)"
361 if $@;
362
363 my $iter = Parallel::Iterator::iterate(
364 { workers => $self->jobs || 0 },
365 sub {
366 my ( $id, $test ) = @_;
367
368 my ( $parser, $session ) = $self->make_parser($test);
369
370 while ( defined( my $result = $parser->next ) ) {
371 exit 1 if $result->is_bailout;
372 }
373
374 $self->finish_parser( $parser, $session );
375
376 # Can't serialise coderefs...
377 delete $parser->{_iter};
378 delete $parser->{_stream};
379 delete $parser->{_grammar};
380 return $parser;
381 },
382 \@tests
383 );
384
385 while ( my ( $id, $parser ) = $iter->() ) {
386 $self->_after_test( $aggregate, $tests[$id], $parser );
387 }
388
389 return;
390}
391
392sub _aggregate_parallel {
393 my ( $self, $aggregate, @tests ) = @_;
394
395 my $jobs = $self->jobs;
396 my $mux = TAP::Parser::Multiplexer->new;
397
398 RESULT: {
399
400 # Keep multiplexer topped up
401 while ( @tests && $mux->parsers < $jobs ) {
402 my $test = shift @tests;
403 my ( $parser, $session ) = $self->make_parser($test);
404 $mux->add( $parser, [ $session, $test ] );
405 }
406
407 if ( my ( $parser, $stash, $result ) = $mux->next ) {
408 my ( $session, $test ) = @$stash;
409 if ( defined $result ) {
410 $session->result($result);
411 exit 1 if $result->is_bailout;
412 }
413 else {
414
415 # End of parser. Automatically removed from the mux.
416 $self->finish_parser( $parser, $session );
417 $self->_after_test( $aggregate, $test, $parser );
418 }
419 redo RESULT;
420 }
421 }
422
423 return;
424}
425
426sub _aggregate_single {
427 my ( $self, $aggregate, @tests ) = @_;
428
429 for my $test (@tests) {
430 my ( $parser, $session ) = $self->make_parser($test);
431
432 while ( defined( my $result = $parser->next ) ) {
433 $session->result($result);
69f36734 434 if ( $result->is_bailout ) {
435
436 # Keep reading until input is exhausted in the hope
437 # of allowing any pending diagnostics to show up.
438 1 while $parser->next;
439 exit 1;
440 }
b965d173 441 }
442
443 $self->finish_parser( $parser, $session );
444 $self->_after_test( $aggregate, $test, $parser );
445 }
446
447 return;
448}
449
450sub aggregate_tests {
451 my ( $self, $aggregate, @tests ) = @_;
452
453 my $jobs = $self->jobs;
454
455 my @expanded = map { 'ARRAY' eq ref $_ ? $_ : [ $_, $_ ] } @tests;
456
457 # Formatter gets only names
458 $self->formatter->prepare( map { $_->[1] } @expanded );
459 $aggregate->start;
460
461 if ( $self->jobs > 1 ) {
462 if ( $self->fork ) {
463 $self->_aggregate_forked( $aggregate, @expanded );
464 }
465 else {
466 $self->_aggregate_parallel( $aggregate, @expanded );
467 }
468 }
469 else {
470 $self->_aggregate_single( $aggregate, @expanded );
471 }
472
473 $aggregate->stop;
474
475 return;
476}
477
478=head3 C<jobs>
479
480Returns the number of concurrent test runs the harness is handling. For the default
481harness this value is always 1. A parallel harness such as L<TAP::Harness::Parallel>
482will override this to return the number of jobs it is handling.
483
484=head3 C<fork>
485
486If true the harness will attempt to fork and run the parser for each
487test in a separate process. Currently this option requires
488L<Parallel::Iterator> to be installed.
489
490=cut
491
492##############################################################################
493
494=head1 SUBCLASSING
495
496C<TAP::Harness> is designed to be (mostly) easy to subclass. If you don't
497like how a particular feature functions, just override the desired methods.
498
499=head2 Methods
500
501TODO: This is out of date
502
503The following methods are ones you may wish to override if you want to
504subclass C<TAP::Harness>.
505
506=head3 C<summary>
507
508 $harness->summary( \%args );
509
510C<summary> prints the summary report after all tests are run. The argument is
511a hashref with the following keys:
512
513=over 4
514
515=item * C<start>
516
517This is created with C<< Benchmark->new >> and it the time the tests started.
518You can print a useful summary time, if desired, with:
519
520 $self->output(timestr( timediff( Benchmark->new, $start_time ), 'nop' ));
521
522=item * C<tests>
523
524This is an array reference of all test names. To get the L<TAP::Parser>
525object for individual tests:
526
527 my $aggregate = $args->{aggregate};
528 my $tests = $args->{tests};
529
530 for my $name ( @$tests ) {
531 my ($parser) = $aggregate->parsers($test);
532 ... do something with $parser
533 }
534
535This is a bit clunky and will be cleaned up in a later release.
536
537=back
538
539=cut
540
541sub _get_parser_args {
542 my ( $self, $test ) = @_;
543 my $test_prog = $test->[0];
544 my %args = ();
545 my @switches;
546 @switches = $self->lib if $self->lib;
547 push @switches => $self->switches if $self->switches;
548 $args{switches} = \@switches;
549 $args{spool} = $self->_open_spool($test_prog);
550 $args{merge} = $self->merge;
551 $args{exec} = $self->exec;
552
553 if ( my $exec = $self->exec ) {
554 $args{exec} = [ @$exec, $test_prog ];
555 }
556 else {
557 $args{source} = $test_prog;
558 }
559
560 if ( defined( my $test_args = $self->test_args ) ) {
561 $args{test_args} = $test_args;
562 }
563
564 return \%args;
565}
566
567=head3 C<make_parser>
568
569Make a new parser and display formatter session. Typically used and/or
570overridden in subclasses.
571
572 my ( $parser, $session ) = $harness->make_parser;
573
574
575=cut
576
577sub make_parser {
578 my ( $self, $test ) = @_;
579
580 my $args = $self->_get_parser_args($test);
581 $self->_make_callback( 'parser_args', $args, $test );
582 my $parser = TAP::Parser->new($args);
583
584 $self->_make_callback( 'made_parser', $parser, $test );
585 my $session = $self->formatter->open_test( $test->[1], $parser );
586
587 return ( $parser, $session );
588}
589
590=head3 C<finish_parser>
591
592Terminate use of a parser. Typically used and/or overridden in
593subclasses. The parser isn't destroyed as a result of this.
594
595=cut
596
597sub finish_parser {
598 my ( $self, $parser, $session ) = @_;
599
600 $session->close_test;
601 $self->_close_spool($parser);
602
603 return $parser;
604}
605
606sub _open_spool {
607 my $self = shift;
608 my $test = shift;
609
610 if ( my $spool_dir = $ENV{PERL_TEST_HARNESS_DUMP_TAP} ) {
611
612 my $spool = File::Spec->catfile( $spool_dir, $test );
613
614 # Make the directory
615 my ( $vol, $dir, undef ) = File::Spec->splitpath($spool);
616 my $path = File::Spec->catpath( $vol, $dir, '' );
617 eval { mkpath($path) };
618 $self->_croak($@) if $@;
619
620 my $spool_handle = IO::Handle->new;
621 open( $spool_handle, ">$spool" )
622 or $self->_croak(" Can't write $spool ( $! ) ");
623
624 return $spool_handle;
625 }
626
627 return;
628}
629
630sub _close_spool {
631 my $self = shift;
632 my ($parser) = @_;
633
634 if ( my $spool_handle = $parser->delete_spool ) {
635 close($spool_handle)
636 or $self->_croak(" Error closing TAP spool file( $! ) \n ");
637 }
638
639 return;
640}
641
642sub _croak {
643 my ( $self, $message ) = @_;
644 unless ($message) {
645 $message = $self->_error;
646 }
647 $self->SUPER::_croak($message);
648
649 return;
650}
651
652=head1 REPLACING
653
654If you like the C<prove> utility and L<TAP::Parser> but you want your
655own harness, all you need to do is write one and provide C<new> and
656C<runtests> methods. Then you can use the C<prove> utility like so:
657
658 prove --harness My::Test::Harness
659
660Note that while C<prove> accepts a list of tests (or things to be
661tested), C<new> has a fairly rich set of arguments. You'll probably want
662to read over this code carefully to see how all of them are being used.
663
664=head1 SEE ALSO
665
666L<Test::Harness>
667
668=cut
669
6701;
671
672# vim:ts=4:sw=4:et:sta