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