xref: /openbsd-src/gnu/usr.bin/perl/cpan/Test-Harness/t/harness.t (revision 5486feefcc8cb79b19e014ab332cc5dfd05b3b33)
1#!/usr/bin/perl -w
2
3BEGIN {
4    unshift @INC, 't/lib';
5}
6
7use strict;
8use warnings;
9
10use Test::More;
11use IO::c55Capture;
12
13use Config;
14use POSIX;
15
16use TAP::Harness;
17
18# This is done to prevent the colors environment variables from
19# interfering.
20local $ENV{HARNESS_SUMMARY_COLOR_FAIL};
21local $ENV{HARNESS_SUMMARY_COLOR_SUCCESS};
22delete $ENV{HARNESS_SUMMARY_COLOR_FAIL};
23delete $ENV{HARNESS_SUMMARY_COLOR_SUCCESS};
24
25my $HARNESS = 'TAP::Harness';
26
27my $source_tests = 't/source_tests';
28my $sample_tests = 't/sample-tests';
29
30plan tests => 133;
31
32# note that this test will always pass when run through 'prove'
33ok $ENV{HARNESS_ACTIVE},  'HARNESS_ACTIVE env variable should be set';
34ok $ENV{HARNESS_VERSION}, 'HARNESS_VERSION env variable should be set';
35
36#### For color tests ####
37
38package Colorizer;
39
40sub new { bless {}, shift }
41sub can_color {1}
42
43sub set_color {
44    my ( $self, $output, $color ) = @_;
45    $output->("[[$color]]");
46}
47
48package main;
49
50sub colorize {
51    my $harness = shift;
52    $harness->formatter->_colorizer( Colorizer->new );
53}
54
55can_ok $HARNESS, 'new';
56
57eval { $HARNESS->new( { no_such_key => 1 } ) };
58like $@, qr/\QUnknown arguments to TAP::Harness::new (no_such_key)/,
59  '... and calling it with bad keys should fail';
60
61eval { $HARNESS->new( { lib => 'aint_no_such_lib' } ) };
62is $@, '', '... and calling it with a non-existent lib is fine';
63
64eval { $HARNESS->new( { lib => [qw/bad_lib_1 bad_lib_2/] } ) };
65is $@, '', '... and calling it with non-existent libs is fine';
66
67ok my $harness = $HARNESS->new,
68  'Calling new() without arguments should succeed';
69
70for my $test_args ( get_arg_sets() ) {
71    my %args = %$test_args;
72    for my $key ( sort keys %args ) {
73        $args{$key} = $args{$key}{in};
74    }
75    ok my $harness = $HARNESS->new( {%args} ),
76      'Calling new() with valid arguments should succeed';
77    isa_ok $harness, $HARNESS, '... and the object it returns';
78
79    while ( my ( $property, $test ) = each %$test_args ) {
80        my $value = $test->{out};
81        can_ok $harness, $property;
82        is_deeply scalar $harness->$property(), $value, $test->{test_name};
83    }
84}
85
86{
87    my @output;
88    no warnings 'redefine';
89    local *TAP::Formatter::Base::_output = sub {
90        my $self = shift;
91        push @output => grep { $_ ne '' }
92          map {
93            local $_ = $_;
94            chomp;
95            trim($_)
96          } @_;
97    };
98    my $harness = TAP::Harness->new(
99        { verbosity => 1, formatter_class => "TAP::Formatter::Console" } );
100    my $harness_whisper = TAP::Harness->new(
101        { verbosity => -1, formatter_class => "TAP::Formatter::Console" } );
102    my $harness_mute = TAP::Harness->new(
103        { verbosity => -2, formatter_class => "TAP::Formatter::Console" } );
104    my $harness_directives = TAP::Harness->new(
105        { directives => 1, formatter_class => "TAP::Formatter::Console" } );
106    my $harness_failures = TAP::Harness->new(
107        { failures => 1, formatter_class => "TAP::Formatter::Console" } );
108
109    colorize($harness);
110
111    can_ok $harness, 'runtests';
112
113    # normal tests in verbose mode
114
115    ok my $aggregate = _runtests( $harness, "$source_tests/harness" ),
116      '... runtests returns the aggregate';
117
118    isa_ok $aggregate, 'TAP::Parser::Aggregator';
119
120    chomp(@output);
121
122    my @expected = (
123        "$source_tests/harness ..",
124        '1..1',
125        '[[reset]]',
126        'ok 1 - this is a test',
127        '[[reset]]',
128        '[[green]]',
129        'ok',
130        '[[reset]]',
131        '[[green]]',
132        'All tests successful.',
133        '[[reset]]',
134    );
135    my $status           = pop @output;
136    my $expected_status  = qr{^Result: PASS$};
137    my $summary          = pop @output;
138    my $expected_summary = qr{^Files=1, Tests=1, +\d+ wallclock secs};
139
140    is_deeply \@output, \@expected, '... and the output should be correct';
141    like $status, $expected_status,
142      '... and the status line should be correct';
143    like $summary, $expected_summary,
144      '... and the report summary should look correct';
145
146    # use an alias for test name
147
148    @output = ();
149    ok $aggregate
150      = _runtests( $harness, [ "$source_tests/harness", 'My Nice Test' ] ),
151      '... runtests returns the aggregate';
152
153    isa_ok $aggregate, 'TAP::Parser::Aggregator';
154
155    chomp(@output);
156
157    @expected = (
158        'My Nice Test ..',
159        '1..1',
160        '[[reset]]',
161        'ok 1 - this is a test',
162        '[[reset]]',
163        '[[green]]',
164        'ok',
165        '[[reset]]',
166        '[[green]]',
167        'All tests successful.',
168        '[[reset]]',
169    );
170    $status           = pop @output;
171    $expected_status  = qr{^Result: PASS$};
172    $summary          = pop @output;
173    $expected_summary = qr{^Files=1, Tests=1, +\d+ wallclock secs};
174
175    is_deeply \@output, \@expected, '... and the output should be correct';
176    like $status, $expected_status,
177      '... and the status line should be correct';
178    like $summary, $expected_summary,
179      '... and the report summary should look correct';
180
181    # run same test twice
182
183    @output = ();
184    ok $aggregate = _runtests(
185        $harness, [ "$source_tests/harness", 'My Nice Test' ],
186        [ "$source_tests/harness", 'My Nice Test Again' ]
187      ),
188      '... runtests returns the aggregate';
189
190    isa_ok $aggregate, 'TAP::Parser::Aggregator';
191
192    chomp(@output);
193
194    @expected = (
195        'My Nice Test ........',
196        '1..1',
197        '[[reset]]',
198        'ok 1 - this is a test',
199        '[[reset]]',
200        '[[green]]',
201        'ok',
202        '[[reset]]',
203        'My Nice Test Again ..',
204        '1..1',
205        '[[reset]]',
206        'ok 1 - this is a test',
207        '[[reset]]',
208        '[[green]]',
209        'ok',
210        '[[reset]]',
211        '[[green]]',
212        'All tests successful.',
213        '[[reset]]',
214    );
215    $status           = pop @output;
216    $expected_status  = qr{^Result: PASS$};
217    $summary          = pop @output;
218    $expected_summary = qr{^Files=2, Tests=2, +\d+ wallclock secs};
219
220    is_deeply \@output, \@expected, '... and the output should be correct';
221    like $status, $expected_status,
222      '... and the status line should be correct';
223    like $summary, $expected_summary,
224      '... and the report summary should look correct';
225
226    # normal tests in quiet mode
227
228    @output = ();
229    _runtests( $harness_whisper, "$source_tests/harness" );
230
231    chomp(@output);
232    @expected = (
233        "$source_tests/harness ..",
234        'ok',
235        'All tests successful.',
236    );
237
238    $status           = pop @output;
239    $expected_status  = qr{^Result: PASS$};
240    $summary          = pop @output;
241    $expected_summary = qr/^Files=1, Tests=1, +\d+ wallclock secs/;
242
243    is_deeply \@output, \@expected, '... and the output should be correct';
244    like $status, $expected_status,
245      '... and the status line should be correct';
246    like $summary, $expected_summary,
247      '... and the report summary should look correct';
248
249    # normal tests in really_quiet mode
250
251    @output = ();
252    _runtests( $harness_mute, "$source_tests/harness" );
253
254    chomp(@output);
255    @expected = (
256        'All tests successful.',
257    );
258
259    $status           = pop @output;
260    $expected_status  = qr{^Result: PASS$};
261    $summary          = pop @output;
262    $expected_summary = qr/^Files=1, Tests=1, +\d+ wallclock secs/;
263
264    is_deeply \@output, \@expected, '... and the output should be correct';
265    like $status, $expected_status,
266      '... and the status line should be correct';
267    like $summary, $expected_summary,
268      '... and the report summary should look correct';
269
270    # normal tests with failures
271
272    @output = ();
273    _runtests( $harness, "$source_tests/harness_failure" );
274
275    $status  = pop @output;
276    $summary = pop @output;
277
278    like $status, qr{^Result: FAIL$},
279      '... and the status line should be correct';
280
281    my @summary = @output[ 18 .. $#output ];
282    @output = @output[ 0 .. 17 ];
283
284    @expected = (
285        "$source_tests/harness_failure ..",
286        '1..2',
287        '[[reset]]',
288        'ok 1 - this is a test',
289        '[[reset]]',
290        '[[red]]',
291        'not ok 2 - this is another test',
292        '[[reset]]',
293        q{#   Failed test 'this is another test'},
294        '[[reset]]',
295        '#   in harness_failure.t at line 5.',
296        '[[reset]]',
297        q{#          got: 'waffle'},
298        '[[reset]]',
299        q{#     expected: 'yarblokos'},
300        '[[reset]]',
301        '[[red]]',
302        'Failed 1/2 subtests',
303    );
304
305    is_deeply \@output, \@expected,
306      '... and failing test output should be correct';
307
308    my @expected_summary = (
309        '[[reset]]',
310        'Test Summary Report',
311        '-------------------',
312        '[[red]]',
313        "$source_tests/harness_failure (Wstat: 0 Tests: 2 Failed: 1)",
314        '[[reset]]',
315        '[[red]]',
316        'Failed test:',
317        '[[reset]]',
318        '[[red]]',
319        '2',
320        '[[reset]]',
321    );
322
323    is_deeply \@summary, \@expected_summary,
324      '... and the failure summary should also be correct';
325
326    # quiet tests with failures
327
328    @output = ();
329    _runtests( $harness_whisper, "$source_tests/harness_failure" );
330
331    $status   = pop @output;
332    $summary  = pop @output;
333    @expected = (
334        "$source_tests/harness_failure ..",
335        'Failed 1/2 subtests',
336        'Test Summary Report',
337        '-------------------',
338        "$source_tests/harness_failure (Wstat: 0 Tests: 2 Failed: 1)",
339        'Failed test:',
340        '2',
341    );
342
343    like $status, qr{^Result: FAIL$},
344      '... and the status line should be correct';
345
346    is_deeply \@output, \@expected,
347      '... and failing test output should be correct';
348
349    # really quiet tests with failures
350
351    @output = ();
352    _runtests( $harness_mute, "$source_tests/harness_failure" );
353
354    $status   = pop @output;
355    $summary  = pop @output;
356    @expected = (
357        'Test Summary Report',
358        '-------------------',
359        "$source_tests/harness_failure (Wstat: 0 Tests: 2 Failed: 1)",
360        'Failed test:',
361        '2',
362    );
363
364    like $status, qr{^Result: FAIL$},
365      '... and the status line should be correct';
366
367    is_deeply \@output, \@expected,
368      '... and failing test output should be correct';
369
370    # only show directives
371
372    @output = ();
373    _runtests(
374        $harness_directives,
375        "$source_tests/harness_directives"
376    );
377
378    chomp(@output);
379
380    @expected = (
381        "$source_tests/harness_directives ..",
382        'not ok 2 - we have a something # TODO some output',
383        "ok 3 houston, we don't have liftoff # SKIP no funding",
384        'ok',
385        'All tests successful.',
386
387        # ~TODO {{{ this should be an option
388        #'Test Summary Report',
389        #'-------------------',
390        #"$source_tests/harness_directives (Wstat: 0 Tests: 3 Failed: 0)",
391        #'Tests skipped:',
392        #'3',
393        # }}}
394    );
395
396    $status           = pop @output;
397    $summary          = pop @output;
398    $expected_summary = qr/^Files=1, Tests=3, +\d+ wallclock secs/;
399
400    is_deeply \@output, \@expected, '... and the output should be correct';
401    like $summary, $expected_summary,
402      '... and the report summary should look correct';
403
404    like $status, qr{^Result: PASS$},
405      '... and the status line should be correct';
406
407    # normal tests with bad tap
408
409    # install callback handler
410    my $parser;
411    my $callback_count = 0;
412
413    my @callback_log = ();
414
415    for my $evt (qw(parser_args made_parser before_runtests after_runtests)) {
416        $harness->callback(
417            $evt => sub {
418                push @callback_log, $evt;
419            }
420        );
421    }
422
423    $harness->callback(
424        made_parser => sub {
425            $parser = shift;
426            $callback_count++;
427        }
428    );
429
430    @output = ();
431    _runtests( $harness, "$source_tests/harness_badtap" );
432    chomp(@output);
433
434    @output   = map { trim($_) } @output;
435    $status   = pop @output;
436    @summary  = @output[ 12 .. ( $#output - 1 ) ];
437    @output   = @output[ 0 .. 11 ];
438    @expected = (
439        "$source_tests/harness_badtap ..",
440        '1..2',
441        '[[reset]]',
442        'ok 1 - this is a test',
443        '[[reset]]',
444        '[[red]]',
445        'not ok 2 - this is another test',
446        '[[reset]]',
447        '1..2',
448        '[[reset]]',
449        '[[red]]',
450        'Failed 1/2 subtests',
451    );
452    is_deeply \@output, \@expected,
453      '... and failing test output should be correct';
454    like $status, qr{^Result: FAIL$},
455      '... and the status line should be correct';
456    @expected_summary = (
457        '[[reset]]',
458        'Test Summary Report',
459        '-------------------',
460        '[[red]]',
461        "$source_tests/harness_badtap (Wstat: 0 Tests: 2 Failed: 1)",
462        '[[reset]]',
463        '[[red]]',
464        'Failed test:',
465        '[[reset]]',
466        '[[red]]',
467        '2',
468        '[[reset]]',
469        '[[red]]',
470        'Parse errors: More than one plan found in TAP output',
471        '[[reset]]',
472    );
473    is_deeply \@summary, \@expected_summary,
474      '... and the badtap summary should also be correct';
475
476    cmp_ok( $callback_count, '==', 1, 'callback called once' );
477    is_deeply(
478        \@callback_log,
479        [ 'before_runtests', 'parser_args', 'made_parser', 'after_runtests' ],
480        'callback log matches'
481    );
482    isa_ok $parser, 'TAP::Parser';
483
484    # coverage testing for _should_show_failures
485    # only show failures
486
487    @output = ();
488    _runtests( $harness_failures, "$source_tests/harness_failure" );
489
490    chomp(@output);
491
492    @expected = (
493        "$source_tests/harness_failure ..",
494        'not ok 2 - this is another test',
495        'Failed 1/2 subtests',
496        'Test Summary Report',
497        '-------------------',
498        "$source_tests/harness_failure (Wstat: 0 Tests: 2 Failed: 1)",
499        'Failed test:',
500        '2',
501    );
502
503    $status  = pop @output;
504    $summary = pop @output;
505
506    like $status, qr{^Result: FAIL$},
507      '... and the status line should be correct';
508    $expected_summary = qr/^Files=1, Tests=2, +\d+ wallclock secs/;
509    is_deeply \@output, \@expected, '... and the output should be correct';
510
511    # check the status output for no tests
512
513    @output = ();
514    _runtests( $harness_failures, "$sample_tests/no_output" );
515
516    chomp(@output);
517
518    @expected = (
519        "$sample_tests/no_output ..",
520        'No subtests run',
521        'Test Summary Report',
522        '-------------------',
523        "$sample_tests/no_output (Wstat: 0 Tests: 0 Failed: 0)",
524        'Parse errors: No plan found in TAP output',
525    );
526
527    $status  = pop @output;
528    $summary = pop @output;
529
530    like $status, qr{^Result: FAIL$},
531      '... and the status line should be correct';
532    $expected_summary = qr/^Files=1, Tests=2, +\d+ wallclock secs/;
533    is_deeply \@output, \@expected, '... and the output should be correct';
534
535    SKIP: {
536        skip "No SIGSEGV on $^O", 1 if $^O eq 'MSWin32' or $Config::Config{'sig_name'} !~ m/SEGV/;
537
538        # some people -Dcc="somecc -fsanitize=..." or -Doptimize="-fsanitize=..."
539        skip "ASAN doesn't passthrough SEGV", 1
540          if "$Config{cc} $Config{ccflags} $Config{optimize}" =~ /-fsanitize\b/;
541
542        @output = ();
543        _runtests( $harness_failures, "$sample_tests/segfault" );
544
545        my $out_str = join q<>, @output;
546
547        like( $out_str, qr<SEGV>, 'SIGSEGV is parsed out' );
548    }
549
550    #XXXX
551}
552
553# make sure we can exec something ... anything!
554SKIP: {
555
556    my $cat = '/bin/cat';
557
558    # TODO: use TYPE on win32?
559    unless ( -e $cat ) {
560        skip "no '$cat'", 2;
561    }
562
563    my $capture = IO::c55Capture->new_handle;
564    my $harness = TAP::Harness->new(
565        {   verbosity => -2,
566            stdout    => $capture,
567            exec      => [$cat],
568        }
569    );
570
571    eval { _runtests( $harness, 't/data/catme.1' ); };
572
573    my @output = tied($$capture)->dump;
574    my $status = pop @output;
575    like $status, qr{^Result: PASS$},
576      '... and the status line should be correct';
577    pop @output;    # get rid of summary line
578    my $answer = pop @output;
579    is( $answer, "All tests successful.\n", 'cat meows' );
580}
581
582# make sure that we can exec with a code ref.
583{
584    my $capture = IO::c55Capture->new_handle;
585    my $harness = TAP::Harness->new(
586        {   verbosity => -2,
587            stdout    => $capture,
588            exec      => sub {undef},
589        }
590    );
591
592    _runtests( $harness, "$source_tests/harness" );
593
594    my @output = tied($$capture)->dump;
595    my $status = pop @output;
596    like $status, qr{^Result: PASS$},
597      '... and the status line should be correct';
598    pop @output;    # get rid of summary line
599    my $answer = pop @output;
600    is( $answer, "All tests successful.\n", 'cat meows' );
601}
602
603# Exec with a coderef that returns an arrayref
604SKIP: {
605    my $cat = '/bin/cat';
606    unless ( -e $cat ) {
607        skip "no '$cat'", 2;
608    }
609
610    my $capture = IO::c55Capture->new_handle;
611    my $harness = TAP::Harness->new(
612        {   verbosity => -2,
613            stdout    => $capture,
614            exec      => sub {
615                return [
616                    $cat,
617                    't/data/catme.1'
618                ];
619            },
620        }
621    );
622
623    _runtests( $harness, "$source_tests/harness" );
624
625    my @output = tied($$capture)->dump;
626    my $status = pop @output;
627    like $status, qr{^Result: PASS$},
628      '... and the status line should be correct';
629    pop @output;    # get rid of summary line
630    my $answer = pop @output;
631    is( $answer, "All tests successful.\n", 'cat meows' );
632}
633
634# Exec with a coderef that returns raw TAP
635{
636    my $capture = IO::c55Capture->new_handle;
637    my $harness = TAP::Harness->new(
638        {   verbosity => -2,
639            stdout    => $capture,
640            exec      => sub {
641                return "1..1\nok 1 - raw TAP\n";
642            },
643        }
644    );
645
646    _runtests( $harness, "$source_tests/harness" );
647
648    my @output = tied($$capture)->dump;
649    my $status = pop @output;
650    like $status, qr{^Result: PASS$},
651      '... and the status line should be correct';
652    pop @output;    # get rid of summary line
653    my $answer = pop @output;
654    is( $answer, "All tests successful.\n", 'cat meows' );
655}
656
657# Exec with a coderef that returns a filehandle
658{
659    my $capture = IO::c55Capture->new_handle;
660    my $harness = TAP::Harness->new(
661        {   verbosity => -2,
662            stdout    => $capture,
663            exec      => sub {
664                open my $fh, 't/data/catme.1';
665                return $fh;
666            },
667        }
668    );
669
670    _runtests( $harness, "$source_tests/harness" );
671
672    my @output = tied($$capture)->dump;
673    my $status = pop @output;
674    like $status, qr{^Result: PASS$},
675      '... and the status line should be correct';
676    pop @output;    # get rid of summary line
677    my $answer = pop @output;
678    is( $answer, "All tests successful.\n", 'cat meows' );
679}
680
681# catches "exec accumulates arguments" issue (r77)
682{
683    my $capture = IO::c55Capture->new_handle;
684    my $harness = TAP::Harness->new(
685        {   verbosity => -2,
686            stdout    => $capture,
687            exec      => [$^X]
688        }
689    );
690
691    _runtests(
692        $harness,
693        "$source_tests/harness_complain"
694        ,    # will get mad if run with args
695        "$source_tests/harness",
696    );
697
698    my @output = tied($$capture)->dump;
699    my $status = pop @output;
700    like $status, qr{^Result: PASS$},
701      '... and the status line should be correct';
702    pop @output;    # get rid of summary line
703    is( $output[-1], "All tests successful.\n",
704        'No exec accumulation'
705    );
706}
707
708# customize default File source
709{
710    my $capture = IO::c55Capture->new_handle;
711    my $harness = TAP::Harness->new(
712        {   verbosity => -2,
713            stdout    => $capture,
714            sources   => {
715                File => { extensions => ['.1'] },
716            },
717        }
718    );
719
720    _runtests( $harness, "$source_tests/source.1" );
721
722    my @output = tied($$capture)->dump;
723    my $status = pop @output;
724    like $status, qr{^Result: PASS$},
725      'customized File source has correct status line';
726    pop @output;    # get rid of summary line
727    my $answer = pop @output;
728    is( $answer, "All tests successful.\n", '... all tests passed' );
729}
730
731# load a custom source
732{
733    my $capture = IO::c55Capture->new_handle;
734    my $harness = TAP::Harness->new(
735        {   verbosity => -2,
736            stdout    => $capture,
737            sources   => {
738                MyFileSourceHandler => { extensions => ['.1'] },
739            },
740        }
741    );
742
743    my $source_test = "$source_tests/source.1";
744    eval { _runtests( $harness, "$source_tests/source.1" ); };
745    my $e = $@;
746    ok( !$e, 'no error on load custom source' ) || diag($e);
747
748    no warnings 'once';
749    can_ok( 'MyFileSourceHandler', 'make_iterator' );
750    ok( $MyFileSourceHandler::CAN_HANDLE,
751        '... MyFileSourceHandler->can_handle was called'
752    );
753    ok( $MyFileSourceHandler::MAKE_ITER,
754        '... MyFileSourceHandler->make_iterator was called'
755    );
756
757    my $raw_source = eval { ${ $MyFileSourceHandler::LAST_SOURCE->raw } };
758    is( $raw_source, $source_test, '... used the right source' );
759
760    my @output = tied($$capture)->dump;
761    my $status = pop(@output) || '';
762    like $status, qr{^Result: PASS$}, '... and test has correct status line';
763    pop @output;    # get rid of summary line
764    my $answer = pop @output;
765    is( $answer, "All tests successful.\n", '... all tests passed' );
766}
767
768sub trim {
769    $_[0] =~ s/^\s+|\s+$//g;
770    return $_[0];
771}
772
773sub liblist {
774    return [ map {"-I$_"} @_ ];
775}
776
777sub get_arg_sets {
778
779    # keys are keys to new()
780    return {
781        lib => {
782            in        => 'lib',
783            out       => liblist('lib'),
784            test_name => '... a single lib switch should be correct'
785        },
786        verbosity => {
787            in        => 1,
788            out       => 1,
789            test_name => '... and we should be able to set verbosity to 1'
790        },
791
792        # verbose => {
793        #     in        => 1,
794        #     out       => 1,
795        #     test_name => '... and we should be able to set verbose to true'
796        # },
797      },
798      { lib => {
799            in        => [ 'lib',        't' ],
800            out       => liblist( 'lib', 't' ),
801            test_name => '... multiple lib dirs should be correct'
802        },
803        verbosity => {
804            in        => 0,
805            out       => 0,
806            test_name => '... and we should be able to set verbosity to 0'
807        },
808
809        # verbose => {
810        #     in        => 0,
811        #     out       => 0,
812        #     test_name => '... and we should be able to set verbose to false'
813        # },
814      },
815      { switches => {
816            in        => [ '-T', '-w', '-T' ],
817            out       => [ '-T', '-w', '-T' ],
818            test_name => '... duplicate switches should remain',
819        },
820        failures => {
821            in  => 1,
822            out => 1,
823            test_name =>
824              '... and we should be able to set failures to true',
825        },
826        verbosity => {
827            in        => -1,
828            out       => -1,
829            test_name => '... and we should be able to set verbosity to -1'
830        },
831
832        # quiet => {
833        #     in        => 1,
834        #     out       => 1,
835        #     test_name => '... and we should be able to set quiet to false'
836        # },
837      },
838
839      { verbosity => {
840            in        => -2,
841            out       => -2,
842            test_name => '... and we should be able to set verbosity to -2'
843        },
844
845        # really_quiet => {
846        #     in  => 1,
847        #     out => 1,
848        #     test_name =>
849        #       '... and we should be able to set really_quiet to true',
850        # },
851        exec => {
852            in  => $^X,
853            out => $^X,
854            test_name =>
855              '... and we should be able to set the executable',
856        },
857      },
858      { switches => {
859            in  => 'T',
860            out => ['T'],
861            test_name =>
862              '... leading dashes (-) on switches are not optional',
863        },
864      },
865      { switches => {
866            in        => '-T',
867            out       => ['-T'],
868            test_name => '... we should be able to set switches',
869        },
870        failures => {
871            in        => 1,
872            out       => 1,
873            test_name => '... and we should be able to set failures to true'
874        },
875      };
876}
877
878sub _runtests {
879    my ( $harness, @tests ) = @_;
880    local $ENV{PERL_TEST_HARNESS_DUMP_TAP} = 0;
881    my $aggregate = $harness->runtests(@tests);
882    return $aggregate;
883}
884
885{
886
887    # coverage tests for ctor
888
889    my $harness = TAP::Harness->new(
890        {   timer  => 0,
891            errors => 1,
892            merge  => 2,
893
894            # formatter => 3,
895        }
896    );
897
898    is $harness->timer(), 0, 'timer getter';
899    is $harness->timer(10), 10, 'timer setter';
900    is $harness->errors(), 1, 'errors getter';
901    is $harness->errors(10), 10, 'errors setter';
902    is $harness->merge(), 2, 'merge getter';
903    is $harness->merge(10), 10, 'merge setter';
904
905    # jobs accessor
906    is $harness->jobs(), 1, 'jobs';
907}
908
909{
910
911# coverage tests for the stdout key of VALIDATON_FOR, used by _initialize() in the ctor
912
913    {
914
915        # ref $ref => false
916        my @die;
917
918        eval {
919            local $SIG{__DIE__} = sub { push @die, @_ };
920
921            my $harness = TAP::Harness->new(
922                {   stdout => bless {}, '0',    # how evil is THAT !!!
923                }
924            );
925        };
926
927        is @die, 1, 'bad filehandle to stdout';
928        like pop @die, qr/option 'stdout' needs a filehandle/,
929          '... and we died as expected';
930    }
931
932    {
933
934        # ref => ! GLOB and ref->can(print)
935
936        package Printable;
937
938        sub new { return bless {}, shift }
939
940        sub print {return}
941
942        package main;
943
944        my $harness = TAP::Harness->new(
945            {   stdout => Printable->new(),
946            }
947        );
948
949        isa_ok $harness, 'TAP::Harness';
950    }
951
952    {
953
954        # ref $ref => GLOB
955
956        my $harness = TAP::Harness->new(
957            {   stdout => bless {}, 'GLOB',    # again with the evil
958            }
959        );
960
961        isa_ok $harness, 'TAP::Harness';
962    }
963
964    {
965
966        # bare glob
967
968        my $harness = TAP::Harness->new( { stdout => *STDOUT } );
969
970        isa_ok $harness, 'TAP::Harness';
971    }
972
973    {
974
975        # string filehandle
976
977        my $string = '';
978        open my $fh, ">", \$string or die $!;
979        my $harness = TAP::Harness->new( { stdout => $fh } );
980
981        isa_ok $harness, 'TAP::Harness';
982    }
983
984    {
985
986        # lexical filehandle reference
987
988        my $string = '';
989        open my $fh, ">", \$string or die $!;
990        ok !eval { TAP::Harness->new( { stdout => \$fh } ); };
991        like $@, qr/^option 'stdout' needs a filehandle /;
992    }
993}
994
995{
996
997    # coverage testing of lib/switches accessor
998    my $harness = TAP::Harness->new;
999
1000    my @die;
1001
1002    eval {
1003        local $SIG{__DIE__} = sub { push @die, @_ };
1004
1005        $harness->switches(qw( too many arguments));
1006    };
1007
1008    is @die, 1, 'too many arguments to accessor';
1009
1010    like pop @die, qr/Too many arguments to method 'switches'/,
1011      '...and we died as expected';
1012
1013    $harness->switches('simple scalar');
1014
1015    my $arrref = $harness->switches;
1016    is_deeply $arrref, ['simple scalar'], 'scalar wrapped in arr ref';
1017}
1018
1019{
1020
1021    # coverage tests for the basically untested T::H::_open_spool
1022
1023    my @spool = ( 't', 'spool' );
1024    $ENV{PERL_TEST_HARNESS_DUMP_TAP} = File::Spec->catfile(@spool);
1025
1026# now given that we're going to be writing stuff to the file system, make sure we have
1027# a cleanup hook
1028
1029    END {
1030        use File::Path;
1031
1032        # remove the tree if we made it this far
1033        rmtree( $ENV{PERL_TEST_HARNESS_DUMP_TAP} )
1034          if $ENV{PERL_TEST_HARNESS_DUMP_TAP};
1035    }
1036
1037    my $harness = TAP::Harness->new( { verbosity => -2 } );
1038
1039    can_ok $harness, 'runtests';
1040
1041    # normal tests in verbose mode
1042
1043    my $parser
1044      = $harness->runtests( File::Spec->catfile( $source_tests, 'harness' ) );
1045
1046    isa_ok $parser, 'TAP::Parser::Aggregator',
1047      '... runtests returns the aggregate';
1048
1049    ok -e File::Spec->catfile(
1050        $ENV{PERL_TEST_HARNESS_DUMP_TAP},
1051        $source_tests, 'harness'
1052    );
1053}
1054
1055{
1056
1057    # test name munging
1058    my @cases = (
1059        {   name   => 'all the same',
1060            input  => [ 'foo.t', 'bar.t', 'fletz.t' ],
1061            output => [
1062                [ 'foo.t', 'foo.t' ], [ 'bar.t', 'bar.t' ],
1063                [ 'fletz.t', 'fletz.t' ]
1064            ],
1065        },
1066        {   name   => 'all the same, already cooked',
1067            input  => [ 'foo.t', [ 'bar.t', 'brip' ], 'fletz.t' ],
1068            output => [
1069                [ 'foo.t', 'foo.t' ], [ 'bar.t', 'brip' ],
1070                [ 'fletz.t', 'fletz.t' ]
1071            ],
1072        },
1073        {   name   => 'different exts',
1074            input  => [ 'foo.t', 'bar.u', 'fletz.v' ],
1075            output => [
1076                [ 'foo.t', 'foo.t' ], [ 'bar.u', 'bar.u' ],
1077                [ 'fletz.v', 'fletz.v' ]
1078            ],
1079        },
1080        {   name   => 'different exts, one already cooked',
1081            input  => [ 'foo.t', [ 'bar.u', 'bam' ], 'fletz.v' ],
1082            output => [
1083                [ 'foo.t', 'foo.t' ], [ 'bar.u', 'bam' ],
1084                [ 'fletz.v', 'fletz.v' ]
1085            ],
1086        },
1087        {   name   => 'different exts, two already cooked',
1088            input  => [ 'foo.t', [ 'bar.u', 'bam.q' ], [ 'fletz.v', 'boo' ] ],
1089            output => [
1090                [ 'foo.t', 'foo.t' ], [ 'bar.u', 'bam.q' ],
1091                [ 'fletz.v', 'boo' ]
1092            ],
1093        },
1094    );
1095
1096    for my $case (@cases) {
1097        is_deeply [ TAP::Harness->_add_descriptions( @{ $case->{input} } ) ],
1098          $case->{output}, '_add_descriptions: ' . $case->{name};
1099    }
1100}
1101