xref: /openbsd-src/gnu/usr.bin/perl/cpan/Test-Harness/lib/TAP/Harness.pm (revision 4c1e55dc91edd6e69ccc60ce855900fbc12cf34f)
1package TAP::Harness;
2
3use strict;
4use Carp;
5
6use File::Spec;
7use File::Path;
8use IO::Handle;
9
10use TAP::Base;
11
12use vars qw($VERSION @ISA);
13
14@ISA = qw(TAP::Base);
15
16=head1 NAME
17
18TAP::Harness - Run test scripts with statistics
19
20=head1 VERSION
21
22Version 3.17
23
24=cut
25
26$VERSION = '3.17';
27
28$ENV{HARNESS_ACTIVE}  = 1;
29$ENV{HARNESS_VERSION} = $VERSION;
30
31END {
32
33    # For VMS.
34    delete $ENV{HARNESS_ACTIVE};
35    delete $ENV{HARNESS_VERSION};
36}
37
38=head1 DESCRIPTION
39
40This is a simple test harness which allows tests to be run and results
41automatically aggregated and output to STDOUT.
42
43=head1 SYNOPSIS
44
45 use TAP::Harness;
46 my $harness = TAP::Harness->new( \%args );
47 $harness->runtests(@tests);
48
49=cut
50
51my %VALIDATION_FOR;
52my @FORMATTER_ARGS;
53
54sub _error {
55    my $self = shift;
56    return $self->{error} unless @_;
57    $self->{error} = shift;
58}
59
60BEGIN {
61
62    @FORMATTER_ARGS = qw(
63      directives verbosity timer failures comments errors stdout color
64      show_count normalize
65    );
66
67    %VALIDATION_FOR = (
68        lib => sub {
69            my ( $self, $libs ) = @_;
70            $libs = [$libs] unless 'ARRAY' eq ref $libs;
71
72            return [ map {"-I$_"} @$libs ];
73        },
74        switches          => sub { shift; shift },
75        exec              => sub { shift; shift },
76        merge             => sub { shift; shift },
77        aggregator_class  => sub { shift; shift },
78        formatter_class   => sub { shift; shift },
79        multiplexer_class => sub { shift; shift },
80        parser_class      => sub { shift; shift },
81        scheduler_class   => sub { shift; shift },
82        formatter         => sub { shift; shift },
83        jobs              => sub { shift; shift },
84        test_args         => sub { shift; shift },
85        ignore_exit       => sub { shift; shift },
86        rules             => sub { shift; shift },
87    );
88
89    for my $method ( sort keys %VALIDATION_FOR ) {
90        no strict 'refs';
91        if ( $method eq 'lib' || $method eq 'switches' ) {
92            *{$method} = sub {
93                my $self = shift;
94                unless (@_) {
95                    $self->{$method} ||= [];
96                    return wantarray
97                      ? @{ $self->{$method} }
98                      : $self->{$method};
99                }
100                $self->_croak("Too many arguments to method '$method'")
101                  if @_ > 1;
102                my $args = shift;
103                $args = [$args] unless ref $args;
104                $self->{$method} = $args;
105                return $self;
106            };
107        }
108        else {
109            *{$method} = sub {
110                my $self = shift;
111                return $self->{$method} unless @_;
112                $self->{$method} = shift;
113            };
114        }
115    }
116
117    for my $method (@FORMATTER_ARGS) {
118        no strict 'refs';
119        *{$method} = sub {
120            my $self = shift;
121            return $self->formatter->$method(@_);
122        };
123    }
124}
125
126##############################################################################
127
128=head1 METHODS
129
130=head2 Class Methods
131
132=head3 C<new>
133
134 my %args = (
135    verbosity => 1,
136    lib     => [ 'lib', 'blib/lib', 'blib/arch' ],
137 )
138 my $harness = TAP::Harness->new( \%args );
139
140The constructor returns a new C<TAP::Harness> object. It accepts an
141optional hashref whose allowed keys are:
142
143=over 4
144
145=item * C<verbosity>
146
147Set the verbosity level:
148
149     1   verbose        Print individual test results to STDOUT.
150     0   normal
151    -1   quiet          Suppress some test output (mostly failures
152                        while tests are running).
153    -2   really quiet   Suppress everything but the tests summary.
154    -3   silent         Suppress everything.
155
156=item * C<timer>
157
158Append run time for each test to output. Uses L<Time::HiRes> if
159available.
160
161=item * C<failures>
162
163Show test failures (this is a no-op if C<verbose> is selected).
164
165=item * C<comments>
166
167Show test comments (this is a no-op if C<verbose> is selected).
168
169=item * C<show_count>
170
171Update the running test count during testing.
172
173=item * C<normalize>
174
175Set to a true value to normalize the TAP that is emitted in verbose modes.
176
177=item * C<lib>
178
179Accepts a scalar value or array ref of scalar values indicating which
180paths to allowed libraries should be included if Perl tests are
181executed. Naturally, this only makes sense in the context of tests
182written in Perl.
183
184=item * C<switches>
185
186Accepts a scalar value or array ref of scalar values indicating which
187switches should be included if Perl tests are executed. Naturally, this
188only makes sense in the context of tests written in Perl.
189
190=item * C<test_args>
191
192A reference to an C<@INC> style array of arguments to be passed to each
193test program.
194
195=item * C<color>
196
197Attempt to produce color output.
198
199=item * C<exec>
200
201Typically, Perl tests are run through this. However, anything which
202spits out TAP is fine. You can use this argument to specify the name of
203the program (and optional switches) to run your tests with:
204
205  exec => ['/usr/bin/ruby', '-w']
206
207You can also pass a subroutine reference in order to determine and
208return the proper program to run based on a given test script. The
209subroutine reference should expect the TAP::Harness object itself as the
210first argument, and the file name as the second argument. It should
211return an array reference containing the command to be run and including
212the test file name. It can also simply return C<undef>, in which case
213TAP::Harness will fall back on executing the test script in Perl:
214
215    exec => sub {
216        my ( $harness, $test_file ) = @_;
217
218        # Let Perl tests run.
219        return undef if $test_file =~ /[.]t$/;
220        return [ qw( /usr/bin/ruby -w ), $test_file ]
221          if $test_file =~ /[.]rb$/;
222      }
223
224If the subroutine returns a scalar with a newline or a filehandle, it
225will be interpreted as raw TAP or as a TAP stream, respectively.
226
227=item * C<merge>
228
229If C<merge> is true the harness will create parsers that merge STDOUT
230and STDERR together for any processes they start.
231
232=item * C<aggregator_class>
233
234The name of the class to use to aggregate test results. The default is
235L<TAP::Parser::Aggregator>.
236
237=item * C<formatter_class>
238
239The name of the class to use to format output. The default is
240L<TAP::Formatter::Console>, or L<TAP::Formatter::File> if the output
241isn't a TTY.
242
243=item * C<multiplexer_class>
244
245The name of the class to use to multiplex tests during parallel testing.
246The default is L<TAP::Parser::Multiplexer>.
247
248=item * C<parser_class>
249
250The name of the class to use to parse TAP. The default is
251L<TAP::Parser>.
252
253=item * C<scheduler_class>
254
255The name of the class to use to schedule test execution. The default is
256L<TAP::Parser::Scheduler>.
257
258=item * C<formatter>
259
260If set C<formatter> must be an object that is capable of formatting the
261TAP output. See L<TAP::Formatter::Console> for an example.
262
263=item * C<errors>
264
265If parse errors are found in the TAP output, a note of this will be
266made in the summary report. To see all of the parse errors, set this
267argument to true:
268
269  errors => 1
270
271=item * C<directives>
272
273If set to a true value, only test results with directives will be
274displayed. This overrides other settings such as C<verbose> or
275C<failures>.
276
277=item * C<ignore_exit>
278
279If set to a true value instruct C<TAP::Parser> to ignore exit and wait
280status from test scripts.
281
282=item * C<jobs>
283
284The maximum number of parallel tests to run at any time.  Which tests
285can be run in parallel is controlled by C<rules>.  The default is to
286run only one test at a time.
287
288=item * C<rules>
289
290A reference to a hash of rules that control which tests may be
291executed in parallel. This is an experimental feature and the
292interface may change.
293
294    $harness->rules(
295        {   par => [
296                { seq => '../ext/DB_File/t/*' },
297                { seq => '../ext/IO_Compress_Zlib/t/*' },
298                { seq => '../lib/CPANPLUS/*' },
299                { seq => '../lib/ExtUtils/t/*' },
300                '*'
301            ]
302        }
303    );
304
305=item * C<stdout>
306
307A filehandle for catching standard output.
308
309=back
310
311Any keys for which the value is C<undef> will be ignored.
312
313=cut
314
315# new supplied by TAP::Base
316
317{
318    my @legal_callback = qw(
319      parser_args
320      made_parser
321      before_runtests
322      after_runtests
323      after_test
324    );
325
326    my %default_class = (
327        aggregator_class  => 'TAP::Parser::Aggregator',
328        formatter_class   => 'TAP::Formatter::Console',
329        multiplexer_class => 'TAP::Parser::Multiplexer',
330        parser_class      => 'TAP::Parser',
331        scheduler_class   => 'TAP::Parser::Scheduler',
332    );
333
334    sub _initialize {
335        my ( $self, $arg_for ) = @_;
336        $arg_for ||= {};
337
338        $self->SUPER::_initialize( $arg_for, \@legal_callback );
339        my %arg_for = %$arg_for;    # force a shallow copy
340
341        for my $name ( sort keys %VALIDATION_FOR ) {
342            my $property = delete $arg_for{$name};
343            if ( defined $property ) {
344                my $validate = $VALIDATION_FOR{$name};
345
346                my $value = $self->$validate($property);
347                if ( $self->_error ) {
348                    $self->_croak;
349                }
350                $self->$name($value);
351            }
352        }
353
354        $self->jobs(1) unless defined $self->jobs;
355
356        local $default_class{formatter_class} = 'TAP::Formatter::File'
357          unless -t ( $arg_for{stdout} || \*STDOUT ) && !$ENV{HARNESS_NOTTY};
358
359        while ( my ( $attr, $class ) = each %default_class ) {
360            $self->$attr( $self->$attr() || $class );
361        }
362
363        unless ( $self->formatter ) {
364
365            # This is a little bodge to preserve legacy behaviour. It's
366            # pretty horrible that we know which args are destined for
367            # the formatter.
368            my %formatter_args = ( jobs => $self->jobs );
369            for my $name (@FORMATTER_ARGS) {
370                if ( defined( my $property = delete $arg_for{$name} ) ) {
371                    $formatter_args{$name} = $property;
372                }
373            }
374
375            $self->formatter(
376                $self->_construct( $self->formatter_class, \%formatter_args )
377            );
378        }
379
380        if ( my @props = sort keys %arg_for ) {
381            $self->_croak("Unknown arguments to TAP::Harness::new (@props)");
382        }
383
384        return $self;
385    }
386}
387
388##############################################################################
389
390=head2 Instance Methods
391
392=head3 C<runtests>
393
394    $harness->runtests(@tests);
395
396Accepts and array of C<@tests> to be run. This should generally be the
397names of test files, but this is not required. Each element in C<@tests>
398will be passed to C<TAP::Parser::new()> as a C<source>. See
399L<TAP::Parser> for more information.
400
401It is possible to provide aliases that will be displayed in place of the
402test name by supplying the test as a reference to an array containing
403C<< [ $test, $alias ] >>:
404
405    $harness->runtests( [ 't/foo.t', 'Foo Once' ],
406                        [ 't/foo.t', 'Foo Twice' ] );
407
408Normally it is an error to attempt to run the same test twice. Aliases
409allow you to overcome this limitation by giving each run of the test a
410unique name.
411
412Tests will be run in the order found.
413
414If the environment variable C<PERL_TEST_HARNESS_DUMP_TAP> is defined it
415should name a directory into which a copy of the raw TAP for each test
416will be written. TAP is written to files named for each test.
417Subdirectories will be created as needed.
418
419Returns a L<TAP::Parser::Aggregator> containing the test results.
420
421=cut
422
423sub runtests {
424    my ( $self, @tests ) = @_;
425
426    my $aggregate = $self->_construct( $self->aggregator_class );
427
428    $self->_make_callback( 'before_runtests', $aggregate );
429    $aggregate->start;
430    $self->aggregate_tests( $aggregate, @tests );
431    $aggregate->stop;
432    $self->summary($aggregate);
433    $self->_make_callback( 'after_runtests', $aggregate );
434
435    return $aggregate;
436}
437
438=head3 C<summary>
439
440Output the summary for a TAP::Parser::Aggregator.
441
442=cut
443
444sub summary {
445    my ( $self, $aggregate ) = @_;
446    $self->formatter->summary($aggregate);
447}
448
449sub _after_test {
450    my ( $self, $aggregate, $job, $parser ) = @_;
451
452    $self->_make_callback( 'after_test', $job->as_array_ref, $parser );
453    $aggregate->add( $job->description, $parser );
454}
455
456sub _bailout {
457    my ( $self, $result ) = @_;
458    my $explanation = $result->explanation;
459    die "FAILED--Further testing stopped"
460      . ( $explanation ? ": $explanation\n" : ".\n" );
461}
462
463sub _aggregate_parallel {
464    my ( $self, $aggregate, $scheduler ) = @_;
465
466    my $jobs = $self->jobs;
467    my $mux  = $self->_construct( $self->multiplexer_class );
468
469    RESULT: {
470
471        # Keep multiplexer topped up
472        FILL:
473        while ( $mux->parsers < $jobs ) {
474            my $job = $scheduler->get_job;
475
476            # If we hit a spinner stop filling and start running.
477            last FILL if !defined $job || $job->is_spinner;
478
479            my ( $parser, $session ) = $self->make_parser($job);
480            $mux->add( $parser, [ $session, $job ] );
481        }
482
483        if ( my ( $parser, $stash, $result ) = $mux->next ) {
484            my ( $session, $job ) = @$stash;
485            if ( defined $result ) {
486                $session->result($result);
487                $self->_bailout($result) if $result->is_bailout;
488            }
489            else {
490
491                # End of parser. Automatically removed from the mux.
492                $self->finish_parser( $parser, $session );
493                $self->_after_test( $aggregate, $job, $parser );
494                $job->finish;
495            }
496            redo RESULT;
497        }
498    }
499
500    return;
501}
502
503sub _aggregate_single {
504    my ( $self, $aggregate, $scheduler ) = @_;
505
506    JOB:
507    while ( my $job = $scheduler->get_job ) {
508        next JOB if $job->is_spinner;
509
510        my ( $parser, $session ) = $self->make_parser($job);
511
512        while ( defined( my $result = $parser->next ) ) {
513            $session->result($result);
514            if ( $result->is_bailout ) {
515
516                # Keep reading until input is exhausted in the hope
517                # of allowing any pending diagnostics to show up.
518                1 while $parser->next;
519                $self->_bailout($result);
520            }
521        }
522
523        $self->finish_parser( $parser, $session );
524        $self->_after_test( $aggregate, $job, $parser );
525        $job->finish;
526    }
527
528    return;
529}
530
531=head3 C<aggregate_tests>
532
533  $harness->aggregate_tests( $aggregate, @tests );
534
535Run the named tests and display a summary of result. Tests will be run
536in the order found.
537
538Test results will be added to the supplied L<TAP::Parser::Aggregator>.
539C<aggregate_tests> may be called multiple times to run several sets of
540tests. Multiple C<Test::Harness> instances may be used to pass results
541to a single aggregator so that different parts of a complex test suite
542may be run using different C<TAP::Harness> settings. This is useful, for
543example, in the case where some tests should run in parallel but others
544are unsuitable for parallel execution.
545
546    my $formatter   = TAP::Formatter::Console->new;
547    my $ser_harness = TAP::Harness->new( { formatter => $formatter } );
548    my $par_harness = TAP::Harness->new(
549        {   formatter => $formatter,
550            jobs      => 9
551        }
552    );
553    my $aggregator = TAP::Parser::Aggregator->new;
554
555    $aggregator->start();
556    $ser_harness->aggregate_tests( $aggregator, @ser_tests );
557    $par_harness->aggregate_tests( $aggregator, @par_tests );
558    $aggregator->stop();
559    $formatter->summary($aggregator);
560
561Note that for simpler testing requirements it will often be possible to
562replace the above code with a single call to C<runtests>.
563
564Each elements of the @tests array is either
565
566=over
567
568=item * the file name of a test script to run
569
570=item * a reference to a [ file name, display name ] array
571
572=back
573
574When you supply a separate display name it becomes possible to run a
575test more than once; the display name is effectively the alias by which
576the test is known inside the harness. The harness doesn't care if it
577runs the same script more than once when each invocation uses a
578different name.
579
580=cut
581
582sub aggregate_tests {
583    my ( $self, $aggregate, @tests ) = @_;
584
585    my $jobs      = $self->jobs;
586    my $scheduler = $self->make_scheduler(@tests);
587
588    # #12458
589    local $ENV{HARNESS_IS_VERBOSE} = 1
590      if $self->formatter->verbosity > 0;
591
592    # Formatter gets only names.
593    $self->formatter->prepare( map { $_->description } $scheduler->get_all );
594
595    if ( $self->jobs > 1 ) {
596        $self->_aggregate_parallel( $aggregate, $scheduler );
597    }
598    else {
599        $self->_aggregate_single( $aggregate, $scheduler );
600    }
601
602    return;
603}
604
605sub _add_descriptions {
606    my $self = shift;
607
608    # Turn unwrapped scalars into anonymous arrays and copy the name as
609    # the description for tests that have only a name.
610    return map { @$_ == 1 ? [ $_->[0], $_->[0] ] : $_ }
611      map { 'ARRAY' eq ref $_ ? $_ : [$_] } @_;
612}
613
614=head3 C<make_scheduler>
615
616Called by the harness when it needs to create a
617L<TAP::Parser::Scheduler>. Override in a subclass to provide an
618alternative scheduler. C<make_scheduler> is passed the list of tests
619that was passed to C<aggregate_tests>.
620
621=cut
622
623sub make_scheduler {
624    my ( $self, @tests ) = @_;
625    return $self->_construct(
626        $self->scheduler_class,
627        tests => [ $self->_add_descriptions(@tests) ],
628        rules => $self->rules
629    );
630}
631
632=head3 C<jobs>
633
634Gets or sets the number of concurrent test runs the harness is
635handling.  By default, this value is 1 -- for parallel testing, this
636should be set higher.
637
638=cut
639
640##############################################################################
641
642=head1 SUBCLASSING
643
644C<TAP::Harness> is designed to be (mostly) easy to subclass. If you
645don't like how a particular feature functions, just override the
646desired methods.
647
648=head2 Methods
649
650TODO: This is out of date
651
652The following methods are ones you may wish to override if you want to
653subclass C<TAP::Harness>.
654
655=head3 C<summary>
656
657  $harness->summary( \%args );
658
659C<summary> prints the summary report after all tests are run. The
660argument is a hashref with the following keys:
661
662=over 4
663
664=item * C<start>
665
666This is created with C<< Benchmark->new >> and it the time the tests
667started. You can print a useful summary time, if desired, with:
668
669    $self->output(
670        timestr( timediff( Benchmark->new, $start_time ), 'nop' ) );
671
672=item * C<tests>
673
674This is an array reference of all test names. To get the L<TAP::Parser>
675object for individual tests:
676
677 my $aggregate = $args->{aggregate};
678 my $tests     = $args->{tests};
679
680 for my $name ( @$tests ) {
681     my ($parser) = $aggregate->parsers($test);
682     ... do something with $parser
683 }
684
685This is a bit clunky and will be cleaned up in a later release.
686
687=back
688
689=cut
690
691sub _get_parser_args {
692    my ( $self, $job ) = @_;
693    my $test_prog = $job->filename;
694    my %args      = ();
695    my @switches;
696    @switches = $self->lib if $self->lib;
697    push @switches => $self->switches if $self->switches;
698    $args{switches}    = \@switches;
699    $args{spool}       = $self->_open_spool($test_prog);
700    $args{merge}       = $self->merge;
701    $args{ignore_exit} = $self->ignore_exit;
702
703    if ( my $exec = $self->exec ) {
704        $args{exec}
705          = ref $exec eq 'CODE'
706          ? $exec->( $self, $test_prog )
707          : [ @$exec, $test_prog ];
708        if ( not defined $args{exec} ) {
709            $args{source} = $test_prog;
710        }
711        elsif ( ( ref( $args{exec} ) || "" ) ne "ARRAY" ) {
712            $args{source} = delete $args{exec};
713        }
714    }
715    else {
716        $args{source} = $test_prog;
717    }
718
719    if ( defined( my $test_args = $self->test_args ) ) {
720        $args{test_args} = $test_args;
721    }
722
723    return \%args;
724}
725
726=head3 C<make_parser>
727
728Make a new parser and display formatter session. Typically used and/or
729overridden in subclasses.
730
731    my ( $parser, $session ) = $harness->make_parser;
732
733=cut
734
735sub make_parser {
736    my ( $self, $job ) = @_;
737
738    my $args = $self->_get_parser_args($job);
739    $self->_make_callback( 'parser_args', $args, $job->as_array_ref );
740    my $parser = $self->_construct( $self->parser_class, $args );
741
742    $self->_make_callback( 'made_parser', $parser, $job->as_array_ref );
743    my $session = $self->formatter->open_test( $job->description, $parser );
744
745    return ( $parser, $session );
746}
747
748=head3 C<finish_parser>
749
750Terminate use of a parser. Typically used and/or overridden in
751subclasses. The parser isn't destroyed as a result of this.
752
753=cut
754
755sub finish_parser {
756    my ( $self, $parser, $session ) = @_;
757
758    $session->close_test;
759    $self->_close_spool($parser);
760
761    return $parser;
762}
763
764sub _open_spool {
765    my $self = shift;
766    my $test = shift;
767
768    if ( my $spool_dir = $ENV{PERL_TEST_HARNESS_DUMP_TAP} ) {
769
770        my $spool = File::Spec->catfile( $spool_dir, $test );
771
772        # Make the directory
773        my ( $vol, $dir, undef ) = File::Spec->splitpath($spool);
774        my $path = File::Spec->catpath( $vol, $dir, '' );
775        eval { mkpath($path) };
776        $self->_croak($@) if $@;
777
778        my $spool_handle = IO::Handle->new;
779        open( $spool_handle, ">$spool" )
780          or $self->_croak(" Can't write $spool ( $! ) ");
781
782        return $spool_handle;
783    }
784
785    return;
786}
787
788sub _close_spool {
789    my $self = shift;
790    my ($parser) = @_;
791
792    if ( my $spool_handle = $parser->delete_spool ) {
793        close($spool_handle)
794          or $self->_croak(" Error closing TAP spool file( $! ) \n ");
795    }
796
797    return;
798}
799
800sub _croak {
801    my ( $self, $message ) = @_;
802    unless ($message) {
803        $message = $self->_error;
804    }
805    $self->SUPER::_croak($message);
806
807    return;
808}
809
810=head1 REPLACING
811
812If you like the C<prove> utility and L<TAP::Parser> but you want your
813own harness, all you need to do is write one and provide C<new> and
814C<runtests> methods. Then you can use the C<prove> utility like so:
815
816 prove --harness My::Test::Harness
817
818Note that while C<prove> accepts a list of tests (or things to be
819tested), C<new> has a fairly rich set of arguments. You'll probably want
820to read over this code carefully to see how all of them are being used.
821
822=head1 SEE ALSO
823
824L<Test::Harness>
825
826=cut
827
8281;
829
830# vim:ts=4:sw=4:et:sta
831