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