xref: /openbsd-src/gnu/usr.bin/perl/cpan/Test-Harness/lib/Test/Harness.pm (revision d13be5d47e4149db2549a9828e244d59dbc43f15)
1package Test::Harness;
2
3require 5.00405;
4
5use strict;
6
7use constant IS_WIN32 => ( $^O =~ /^(MS)?Win32$/ );
8use constant IS_VMS => ( $^O eq 'VMS' );
9
10use TAP::Harness              ();
11use TAP::Parser::Aggregator   ();
12use TAP::Parser::Source::Perl ();
13
14use TAP::Parser::Utils qw( split_shell );
15
16use Config;
17use Exporter;
18
19# TODO: Emulate at least some of these
20use vars qw(
21  $VERSION
22  @ISA @EXPORT @EXPORT_OK
23  $Verbose $Switches $Debug
24  $verbose $switches $debug
25  $Columns
26  $Color
27  $Directives
28  $Timer
29  $Strap
30  $has_time_hires
31  $IgnoreExit
32);
33
34# $ML $Last_ML_Print
35
36BEGIN {
37    eval q{use Time::HiRes 'time'};
38    $has_time_hires = !$@;
39}
40
41=head1 NAME
42
43Test::Harness - Run Perl standard test scripts with statistics
44
45=head1 VERSION
46
47Version 3.17
48
49=cut
50
51$VERSION = '3.17';
52
53# Backwards compatibility for exportable variable names.
54*verbose  = *Verbose;
55*switches = *Switches;
56*debug    = *Debug;
57
58$ENV{HARNESS_ACTIVE}  = 1;
59$ENV{HARNESS_VERSION} = $VERSION;
60
61END {
62
63    # For VMS.
64    delete $ENV{HARNESS_ACTIVE};
65    delete $ENV{HARNESS_VERSION};
66}
67
68@ISA       = ('Exporter');
69@EXPORT    = qw(&runtests);
70@EXPORT_OK = qw(&execute_tests $verbose $switches);
71
72$Verbose = $ENV{HARNESS_VERBOSE} || 0;
73$Debug   = $ENV{HARNESS_DEBUG}   || 0;
74$Switches = '-w';
75$Columns = $ENV{HARNESS_COLUMNS} || $ENV{COLUMNS} || 80;
76$Columns--;    # Some shells have trouble with a full line of text.
77$Timer      = $ENV{HARNESS_TIMER}       || 0;
78$Color      = $ENV{HARNESS_COLOR}       || 0;
79$IgnoreExit = $ENV{HARNESS_IGNORE_EXIT} || 0;
80
81=head1 SYNOPSIS
82
83  use Test::Harness;
84
85  runtests(@test_files);
86
87=head1 DESCRIPTION
88
89Although, for historical reasons, the L<Test::Harness> distribution
90takes its name from this module it now exists only to provide
91L<TAP::Harness> with an interface that is somewhat backwards compatible
92with L<Test::Harness> 2.xx. If you're writing new code consider using
93L<TAP::Harness> directly instead.
94
95Emulation is provided for C<runtests> and C<execute_tests> but the
96pluggable 'Straps' interface that previous versions of L<Test::Harness>
97supported is not reproduced here. Straps is now available as a stand
98alone module: L<Test::Harness::Straps>.
99
100See L<TAP::Parser>, L<TAP::Harness> for the main documentation for this
101distribution.
102
103=head1 FUNCTIONS
104
105The following functions are available.
106
107=head2 runtests( @test_files )
108
109This runs all the given I<@test_files> and divines whether they passed
110or failed based on their output to STDOUT (details above).  It prints
111out each individual test which failed along with a summary report and
112a how long it all took.
113
114It returns true if everything was ok.  Otherwise it will C<die()> with
115one of the messages in the DIAGNOSTICS section.
116
117=cut
118
119sub _has_taint {
120    my $test = shift;
121    return TAP::Parser::Source::Perl->get_taint(
122        TAP::Parser::Source::Perl->shebang($test) );
123}
124
125sub _aggregate {
126    my ( $harness, $aggregate, @tests ) = @_;
127
128    # Don't propagate to our children
129    local $ENV{HARNESS_OPTIONS};
130
131    _apply_extra_INC($harness);
132    _aggregate_tests( $harness, $aggregate, @tests );
133}
134
135# Make sure the child seens all the extra junk in @INC
136sub _apply_extra_INC {
137    my $harness = shift;
138
139    $harness->callback(
140        parser_args => sub {
141            my ( $args, $test ) = @_;
142            push @{ $args->{switches} }, map {"-I$_"} _filtered_inc();
143        }
144    );
145}
146
147sub _aggregate_tests {
148    my ( $harness, $aggregate, @tests ) = @_;
149    $aggregate->start();
150    $harness->aggregate_tests( $aggregate, @tests );
151    $aggregate->stop();
152
153}
154
155sub runtests {
156    my @tests = @_;
157
158    # shield against -l
159    local ( $\, $, );
160
161    my $harness   = _new_harness();
162    my $aggregate = TAP::Parser::Aggregator->new();
163
164    _aggregate( $harness, $aggregate, @tests );
165
166    $harness->formatter->summary($aggregate);
167
168    my $total  = $aggregate->total;
169    my $passed = $aggregate->passed;
170    my $failed = $aggregate->failed;
171
172    my @parsers = $aggregate->parsers;
173
174    my $num_bad = 0;
175    for my $parser (@parsers) {
176        $num_bad++ if $parser->has_problems;
177    }
178
179    die(sprintf(
180            "Failed %d/%d test programs. %d/%d subtests failed.\n",
181            $num_bad, scalar @parsers, $failed, $total
182        )
183    ) if $num_bad;
184
185    return $total && $total == $passed;
186}
187
188sub _canon {
189    my @list   = sort { $a <=> $b } @_;
190    my @ranges = ();
191    my $count  = scalar @list;
192    my $pos    = 0;
193
194    while ( $pos < $count ) {
195        my $end = $pos + 1;
196        $end++ while $end < $count && $list[$end] <= $list[ $end - 1 ] + 1;
197        push @ranges, ( $end == $pos + 1 )
198          ? $list[$pos]
199          : join( '-', $list[$pos], $list[ $end - 1 ] );
200        $pos = $end;
201    }
202
203    return join( ' ', @ranges );
204}
205
206sub _new_harness {
207    my $sub_args = shift || {};
208
209    my ( @lib, @switches );
210    my @opt = split_shell( $Switches, $ENV{HARNESS_PERL_SWITCHES} );
211    while ( my $opt = shift @opt ) {
212        if ( $opt =~ /^ -I (.*) $ /x ) {
213            push @lib, length($1) ? $1 : shift @opt;
214        }
215        else {
216            push @switches, $opt;
217        }
218    }
219
220    # Do things the old way on VMS...
221    push @lib, _filtered_inc() if IS_VMS;
222
223    # If $Verbose isn't numeric default to 1. This helps core.
224    my $verbosity = ( $Verbose ? ( $Verbose !~ /\d/ ) ? 1 : $Verbose : 0 );
225
226    my $args = {
227        timer       => $Timer,
228        directives  => $Directives,
229        lib         => \@lib,
230        switches    => \@switches,
231        color       => $Color,
232        verbosity   => $verbosity,
233        ignore_exit => $IgnoreExit,
234    };
235
236    $args->{stdout} = $sub_args->{out}
237      if exists $sub_args->{out};
238
239    if ( defined( my $env_opt = $ENV{HARNESS_OPTIONS} ) ) {
240        for my $opt ( split /:/, $env_opt ) {
241            if ( $opt =~ /^j(\d*)$/ ) {
242                $args->{jobs} = $1 || 9;
243            }
244            elsif ( $opt eq 'c' ) {
245                $args->{color} = 1;
246            }
247            else {
248                die "Unknown HARNESS_OPTIONS item: $opt\n";
249            }
250        }
251    }
252
253    return TAP::Harness->new($args);
254}
255
256# Get the parts of @INC which are changed from the stock list AND
257# preserve reordering of stock directories.
258sub _filtered_inc {
259    my @inc = grep { !ref } @INC;    #28567
260
261    if (IS_VMS) {
262
263        # VMS has a 255-byte limit on the length of %ENV entries, so
264        # toss the ones that involve perl_root, the install location
265        @inc = grep !/perl_root/i, @inc;
266
267    }
268    elsif (IS_WIN32) {
269
270        # Lose any trailing backslashes in the Win32 paths
271        s/[\\\/]+$// foreach @inc;
272    }
273
274    my @default_inc = _default_inc();
275
276    my @new_inc;
277    my %seen;
278    for my $dir (@inc) {
279        next if $seen{$dir}++;
280
281        if ( $dir eq ( $default_inc[0] || '' ) ) {
282            shift @default_inc;
283        }
284        else {
285            push @new_inc, $dir;
286        }
287
288        shift @default_inc while @default_inc and $seen{ $default_inc[0] };
289    }
290
291    return @new_inc;
292}
293
294{
295
296    # Cache this to avoid repeatedly shelling out to Perl.
297    my @inc;
298
299    sub _default_inc {
300        return @inc if @inc;
301
302        local $ENV{PERL5LIB};
303        local $ENV{PERLLIB};
304
305        my $perl = $ENV{HARNESS_PERL} || $^X;
306
307        # Avoid using -l for the benefit of Perl 6
308        chomp( @inc = `$perl -e "print join qq[\\n], \@INC, q[]"` );
309        return @inc;
310    }
311}
312
313sub _check_sequence {
314    my @list = @_;
315    my $prev;
316    while ( my $next = shift @list ) {
317        return if defined $prev && $next <= $prev;
318        $prev = $next;
319    }
320
321    return 1;
322}
323
324sub execute_tests {
325    my %args = @_;
326
327    my $harness   = _new_harness( \%args );
328    my $aggregate = TAP::Parser::Aggregator->new();
329
330    my %tot = (
331        bonus       => 0,
332        max         => 0,
333        ok          => 0,
334        bad         => 0,
335        good        => 0,
336        files       => 0,
337        tests       => 0,
338        sub_skipped => 0,
339        todo        => 0,
340        skipped     => 0,
341        bench       => undef,
342    );
343
344    # Install a callback so we get to see any plans the
345    # harness executes.
346    $harness->callback(
347        made_parser => sub {
348            my $parser = shift;
349            $parser->callback(
350                plan => sub {
351                    my $plan = shift;
352                    if ( $plan->directive eq 'SKIP' ) {
353                        $tot{skipped}++;
354                    }
355                }
356            );
357        }
358    );
359
360    _aggregate( $harness, $aggregate, @{ $args{tests} } );
361
362    $tot{bench} = $aggregate->elapsed;
363    my @tests = $aggregate->descriptions;
364
365    # TODO: Work out the circumstances under which the files
366    # and tests totals can differ.
367    $tot{files} = $tot{tests} = scalar @tests;
368
369    my %failedtests = ();
370    my %todo_passed = ();
371
372    for my $test (@tests) {
373        my ($parser) = $aggregate->parsers($test);
374
375        my @failed = $parser->failed;
376
377        my $wstat         = $parser->wait;
378        my $estat         = $parser->exit;
379        my $planned       = $parser->tests_planned;
380        my @errors        = $parser->parse_errors;
381        my $passed        = $parser->passed;
382        my $actual_passed = $parser->actual_passed;
383
384        my $ok_seq = _check_sequence( $parser->actual_passed );
385
386        # Duplicate exit, wait status semantics of old version
387        $estat ||= '' unless $wstat;
388        $wstat ||= '';
389
390        $tot{max} += ( $planned || 0 );
391        $tot{bonus} += $parser->todo_passed;
392        $tot{ok} += $passed > $actual_passed ? $passed : $actual_passed;
393        $tot{sub_skipped} += $parser->skipped;
394        $tot{todo}        += $parser->todo;
395
396        if ( @failed || $estat || @errors ) {
397            $tot{bad}++;
398
399            my $huh_planned = $planned ? undef : '??';
400            my $huh_errors  = $ok_seq  ? undef : '??';
401
402            $failedtests{$test} = {
403                'canon' => $huh_planned
404                  || $huh_errors
405                  || _canon(@failed)
406                  || '??',
407                'estat'  => $estat,
408                'failed' => $huh_planned
409                  || $huh_errors
410                  || scalar @failed,
411                'max' => $huh_planned || $planned,
412                'name'  => $test,
413                'wstat' => $wstat
414            };
415        }
416        else {
417            $tot{good}++;
418        }
419
420        my @todo = $parser->todo_passed;
421        if (@todo) {
422            $todo_passed{$test} = {
423                'canon'  => _canon(@todo),
424                'estat'  => $estat,
425                'failed' => scalar @todo,
426                'max'    => scalar $parser->todo,
427                'name'   => $test,
428                'wstat'  => $wstat
429            };
430        }
431    }
432
433    return ( \%tot, \%failedtests, \%todo_passed );
434}
435
436=head2 execute_tests( tests => \@test_files, out => \*FH )
437
438Runs all the given C<@test_files> (just like C<runtests()>) but
439doesn't generate the final report.  During testing, progress
440information will be written to the currently selected output
441filehandle (usually C<STDOUT>), or to the filehandle given by the
442C<out> parameter.  The I<out> is optional.
443
444Returns a list of two values, C<$total> and C<$failed>, describing the
445results.  C<$total> is a hash ref summary of all the tests run.  Its
446keys and values are this:
447
448    bonus           Number of individual todo tests unexpectedly passed
449    max             Number of individual tests ran
450    ok              Number of individual tests passed
451    sub_skipped     Number of individual tests skipped
452    todo            Number of individual todo tests
453
454    files           Number of test files ran
455    good            Number of test files passed
456    bad             Number of test files failed
457    tests           Number of test files originally given
458    skipped         Number of test files skipped
459
460If C<< $total->{bad} == 0 >> and C<< $total->{max} > 0 >>, you've
461got a successful test.
462
463C<$failed> is a hash ref of all the test scripts that failed.  Each key
464is the name of a test script, each value is another hash representing
465how that script failed.  Its keys are these:
466
467    name        Name of the test which failed
468    estat       Script's exit value
469    wstat       Script's wait status
470    max         Number of individual tests
471    failed      Number which failed
472    canon       List of tests which failed (as string).
473
474C<$failed> should be empty if everything passed.
475
476=cut
477
4781;
479__END__
480
481=head1 EXPORT
482
483C<&runtests> is exported by C<Test::Harness> by default.
484
485C<&execute_tests>, C<$verbose>, C<$switches> and C<$debug> are
486exported upon request.
487
488=head1 ENVIRONMENT VARIABLES THAT TAP::HARNESS::COMPATIBLE SETS
489
490C<Test::Harness> sets these before executing the individual tests.
491
492=over 4
493
494=item C<HARNESS_ACTIVE>
495
496This is set to a true value.  It allows the tests to determine if they
497are being executed through the harness or by any other means.
498
499=item C<HARNESS_VERSION>
500
501This is the version of C<Test::Harness>.
502
503=back
504
505=head1 ENVIRONMENT VARIABLES THAT AFFECT TEST::HARNESS
506
507=over 4
508
509=item C<HARNESS_TIMER>
510
511Setting this to true will make the harness display the number of
512milliseconds each test took.  You can also use F<prove>'s C<--timer>
513switch.
514
515=item C<HARNESS_VERBOSE>
516
517If true, C<Test::Harness> will output the verbose results of running
518its tests.  Setting C<$Test::Harness::verbose> will override this,
519or you can use the C<-v> switch in the F<prove> utility.
520
521=item C<HARNESS_OPTIONS>
522
523Provide additional options to the harness. Currently supported options are:
524
525=over
526
527=item C<< j<n> >>
528
529Run <n> (default 9) parallel jobs.
530
531=item C<< f >>
532
533Use forked parallelism.
534
535=back
536
537Multiple options may be separated by colons:
538
539    HARNESS_OPTIONS=j9:f make test
540
541=back
542
543=head1 Taint Mode
544
545Normally when a Perl program is run in taint mode the contents of the
546C<PERL5LIB> environment variable do not appear in C<@INC>.
547
548Because C<PERL5LIB> is often used during testing to add build
549directories to C<@INC> C<Test::Harness> (actually
550L<TAP::Parser::Source::Perl>) passes the names of any directories found
551in C<PERL5LIB> as -I switches. The net effect of this is that
552C<PERL5LIB> is honoured even in taint mode.
553
554=head1 SEE ALSO
555
556L<TAP::Harness>
557
558=head1 BUGS
559
560Please report any bugs or feature requests to
561C<bug-test-harness at rt.cpan.org>, or through the web interface at
562L<http://rt.cpan.org/NoAuth/ReportBug.html?Queue=Test-Harness>.  I will be
563notified, and then you'll automatically be notified of progress on your bug
564as I make changes.
565
566=head1 AUTHORS
567
568Andy Armstrong  C<< <andy@hexten.net> >>
569
570L<Test::Harness> 2.64 (maintained by Andy Lester and on which this
571module is based) has this attribution:
572
573    Either Tim Bunce or Andreas Koenig, we don't know. What we know for
574    sure is, that it was inspired by Larry Wall's F<TEST> script that came
575    with perl distributions for ages. Numerous anonymous contributors
576    exist.  Andreas Koenig held the torch for many years, and then
577    Michael G Schwern.
578
579=head1 LICENCE AND COPYRIGHT
580
581Copyright (c) 2007-2008, Andy Armstrong C<< <andy@hexten.net> >>. All rights reserved.
582
583This module is free software; you can redistribute it and/or
584modify it under the same terms as Perl itself. See L<perlartistic>.
585
586