14 my $HARNESS = 'TAP::Harness';
16 my $source_tests = 't/source_tests';
17 my $sample_tests = 't/sample-tests';
21 # note that this test will always pass when run through 'prove'
22 ok $ENV{HARNESS_ACTIVE}, 'HARNESS_ACTIVE env variable should be set';
23 ok $ENV{HARNESS_VERSION}, 'HARNESS_VERSION env variable should be set';
25 #### For color tests ####
29 sub new { bless {}, shift }
33 my ( $self, $output, $color ) = @_;
34 $output->("[[$color]]");
41 $harness->formatter->_colorizer( Colorizer->new );
44 can_ok $HARNESS, 'new';
46 eval { $HARNESS->new( { no_such_key => 1 } ) };
47 like $@, qr/\QUnknown arguments to TAP::Harness::new (no_such_key)/,
48 '... and calling it with bad keys should fail';
50 eval { $HARNESS->new( { lib => 'aint_no_such_lib' } ) };
51 is $@, '', '... and calling it with a non-existent lib is fine';
53 eval { $HARNESS->new( { lib => [qw/bad_lib_1 bad_lib_2/] } ) };
54 is $@, '', '... and calling it with non-existent libs is fine';
56 ok my $harness = $HARNESS->new,
57 'Calling new() without arguments should succeed';
59 foreach my $test_args ( get_arg_sets() ) {
60 my %args = %$test_args;
61 foreach my $key ( sort keys %args ) {
62 $args{$key} = $args{$key}{in};
64 ok my $harness = $HARNESS->new( {%args} ),
65 'Calling new() with valid arguments should succeed';
66 isa_ok $harness, $HARNESS, '... and the object it returns';
68 while ( my ( $property, $test ) = each %$test_args ) {
69 my $value = $test->{out};
70 can_ok $harness, $property;
71 is_deeply scalar $harness->$property(), $value, $test->{test_name};
78 local *TAP::Formatter::Base::_output = sub {
80 push @output => grep { $_ ne '' }
87 my $harness = TAP::Harness->new(
88 { verbosity => 1, formatter_class => "TAP::Formatter::Console" } );
89 my $harness_whisper = TAP::Harness->new(
90 { verbosity => -1, formatter_class => "TAP::Formatter::Console" } );
91 my $harness_mute = TAP::Harness->new(
92 { verbosity => -2, formatter_class => "TAP::Formatter::Console" } );
93 my $harness_directives = TAP::Harness->new(
94 { directives => 1, formatter_class => "TAP::Formatter::Console" } );
95 my $harness_failures = TAP::Harness->new(
96 { failures => 1, formatter_class => "TAP::Formatter::Console" } );
100 can_ok $harness, 'runtests';
102 # normal tests in verbose mode
104 ok my $aggregate = _runtests( $harness, "$source_tests/harness" ),
105 '... runtests returns the aggregate';
107 isa_ok $aggregate, 'TAP::Parser::Aggregator';
112 "$source_tests/harness ..",
115 'ok 1 - this is a test',
119 'All tests successful.',
122 my $status = pop @output;
123 my $expected_status = qr{^Result: PASS$};
124 my $summary = pop @output;
125 my $expected_summary = qr{^Files=1, Tests=1, \d+ wallclock secs};
127 is_deeply \@output, \@expected, '... and the output should be correct';
128 like $status, $expected_status,
129 '... and the status line should be correct';
130 like $summary, $expected_summary,
131 '... and the report summary should look correct';
133 # use an alias for test name
137 = _runtests( $harness, [ "$source_tests/harness", 'My Nice Test' ] ),
138 '... runtests returns the aggregate';
140 isa_ok $aggregate, 'TAP::Parser::Aggregator';
148 'ok 1 - this is a test',
152 'All tests successful.',
155 $status = pop @output;
156 $expected_status = qr{^Result: PASS$};
157 $summary = pop @output;
158 $expected_summary = qr{^Files=1, Tests=1, \d+ wallclock secs};
160 is_deeply \@output, \@expected, '... and the output should be correct';
161 like $status, $expected_status,
162 '... and the status line should be correct';
163 like $summary, $expected_summary,
164 '... and the report summary should look correct';
166 # run same test twice
169 ok $aggregate = _runtests(
170 $harness, [ "$source_tests/harness", 'My Nice Test' ],
171 [ "$source_tests/harness", 'My Nice Test Again' ]
173 '... runtests returns the aggregate';
175 isa_ok $aggregate, 'TAP::Parser::Aggregator';
180 'My Nice Test ........',
183 'ok 1 - this is a test',
186 'My Nice Test Again ..',
189 'ok 1 - this is a test',
193 'All tests successful.',
196 $status = pop @output;
197 $expected_status = qr{^Result: PASS$};
198 $summary = pop @output;
199 $expected_summary = qr{^Files=2, Tests=2, \d+ wallclock secs};
201 is_deeply \@output, \@expected, '... and the output should be correct';
202 like $status, $expected_status,
203 '... and the status line should be correct';
204 like $summary, $expected_summary,
205 '... and the report summary should look correct';
207 # normal tests in quiet mode
210 _runtests( $harness_whisper, "$source_tests/harness" );
214 "$source_tests/harness ..",
216 'All tests successful.',
219 $status = pop @output;
220 $expected_status = qr{^Result: PASS$};
221 $summary = pop @output;
222 $expected_summary = qr/^Files=1, Tests=1, \d+ wallclock secs/;
224 is_deeply \@output, \@expected, '... and the output should be correct';
225 like $status, $expected_status,
226 '... and the status line should be correct';
227 like $summary, $expected_summary,
228 '... and the report summary should look correct';
230 # normal tests in really_quiet mode
233 _runtests( $harness_mute, "$source_tests/harness" );
237 'All tests successful.',
240 $status = pop @output;
241 $expected_status = qr{^Result: PASS$};
242 $summary = pop @output;
243 $expected_summary = qr/^Files=1, Tests=1, \d+ wallclock secs/;
245 is_deeply \@output, \@expected, '... and the output should be correct';
246 like $status, $expected_status,
247 '... and the status line should be correct';
248 like $summary, $expected_summary,
249 '... and the report summary should look correct';
251 # normal tests with failures
254 _runtests( $harness, "$source_tests/harness_failure" );
256 $status = pop @output;
257 $summary = pop @output;
259 like $status, qr{^Result: FAIL$},
260 '... and the status line should be correct';
262 my @summary = @output[ 18 .. $#output ];
263 @output = @output[ 0 .. 17 ];
266 "$source_tests/harness_failure ..",
269 'ok 1 - this is a test',
272 'not ok 2 - this is another test',
274 q{# Failed test 'this is another test'},
276 '# in harness_failure.t at line 5.',
280 q{# expected: 'yarblokos'},
283 'Failed 1/2 subtests',
286 is_deeply \@output, \@expected,
287 '... and failing test output should be correct';
289 my @expected_summary = (
291 'Test Summary Report',
292 '-------------------',
294 "$source_tests/harness_failure (Wstat: 0 Tests: 2 Failed: 1)",
304 is_deeply \@summary, \@expected_summary,
305 '... and the failure summary should also be correct';
307 # quiet tests with failures
310 _runtests( $harness_whisper, "$source_tests/harness_failure" );
312 $status = pop @output;
313 $summary = pop @output;
315 "$source_tests/harness_failure ..",
316 'Failed 1/2 subtests',
317 'Test Summary Report',
318 '-------------------',
319 "$source_tests/harness_failure (Wstat: 0 Tests: 2 Failed: 1)",
324 like $status, qr{^Result: FAIL$},
325 '... and the status line should be correct';
327 is_deeply \@output, \@expected,
328 '... and failing test output should be correct';
330 # really quiet tests with failures
333 _runtests( $harness_mute, "$source_tests/harness_failure" );
335 $status = pop @output;
336 $summary = pop @output;
338 'Test Summary Report',
339 '-------------------',
340 "$source_tests/harness_failure (Wstat: 0 Tests: 2 Failed: 1)",
345 like $status, qr{^Result: FAIL$},
346 '... and the status line should be correct';
348 is_deeply \@output, \@expected,
349 '... and failing test output should be correct';
351 # only show directives
356 "$source_tests/harness_directives"
362 "$source_tests/harness_directives ..",
363 'not ok 2 - we have a something # TODO some output',
364 "ok 3 houston, we don't have liftoff # SKIP no funding",
366 'All tests successful.',
368 # ~TODO {{{ this should be an option
369 #'Test Summary Report',
370 #'-------------------',
371 #"$source_tests/harness_directives (Wstat: 0 Tests: 3 Failed: 0)",
377 $status = pop @output;
378 $summary = pop @output;
379 $expected_summary = qr/^Files=1, Tests=3, \d+ wallclock secs/;
381 is_deeply \@output, \@expected, '... and the output should be correct';
382 like $summary, $expected_summary,
383 '... and the report summary should look correct';
385 like $status, qr{^Result: PASS$},
386 '... and the status line should be correct';
388 # normal tests with bad tap
390 # install callback handler
392 my $callback_count = 0;
394 my @callback_log = ();
396 for my $evt (qw(parser_args made_parser before_runtests after_runtests)) {
399 push @callback_log, $evt;
412 _runtests( $harness, "$source_tests/harness_badtap" );
415 @output = map { trim($_) } @output;
416 $status = pop @output;
417 @summary = @output[ 12 .. ( $#output - 1 ) ];
418 @output = @output[ 0 .. 11 ];
420 "$source_tests/harness_badtap ..",
423 'ok 1 - this is a test',
426 'not ok 2 - this is another test',
431 'Failed 1/2 subtests',
433 is_deeply \@output, \@expected,
434 '... and failing test output should be correct';
435 like $status, qr{^Result: FAIL$},
436 '... and the status line should be correct';
437 @expected_summary = (
439 'Test Summary Report',
440 '-------------------',
442 "$source_tests/harness_badtap (Wstat: 0 Tests: 2 Failed: 1)",
451 'Parse errors: More than one plan found in TAP output',
454 is_deeply \@summary, \@expected_summary,
455 '... and the badtap summary should also be correct';
457 cmp_ok( $callback_count, '==', 1, 'callback called once' );
460 [ 'before_runtests', 'parser_args', 'made_parser', 'after_runtests' ],
461 'callback log matches'
463 isa_ok $parser, 'TAP::Parser';
465 # coverage testing for _should_show_failures
469 _runtests( $harness_failures, "$source_tests/harness_failure" );
474 "$source_tests/harness_failure ..",
475 'not ok 2 - this is another test',
476 'Failed 1/2 subtests',
477 'Test Summary Report',
478 '-------------------',
479 "$source_tests/harness_failure (Wstat: 0 Tests: 2 Failed: 1)",
484 $status = pop @output;
485 $summary = pop @output;
487 like $status, qr{^Result: FAIL$},
488 '... and the status line should be correct';
489 $expected_summary = qr/^Files=1, Tests=2, \d+ wallclock secs/;
490 is_deeply \@output, \@expected, '... and the output should be correct';
492 # check the status output for no tests
495 _runtests( $harness_failures, "$sample_tests/no_output" );
500 "$sample_tests/no_output ..",
502 'Test Summary Report',
503 '-------------------',
504 "$sample_tests/no_output (Wstat: 0 Tests: 0 Failed: 0)",
505 'Parse errors: No plan found in TAP output',
508 $status = pop @output;
509 $summary = pop @output;
511 like $status, qr{^Result: FAIL$},
512 '... and the status line should be correct';
513 $expected_summary = qr/^Files=1, Tests=2, \d+ wallclock secs/;
514 is_deeply \@output, \@expected, '... and the output should be correct';
519 # make sure we can exec something ... anything!
522 my $cat = '/bin/cat';
527 my $capture = IO::c55Capture->new_handle;
528 my $harness = TAP::Harness->new(
542 my @output = tied($$capture)->dump;
543 my $status = pop @output;
544 like $status, qr{^Result: PASS$},
545 '... and the status line should be correct';
546 pop @output; # get rid of summary line
547 my $answer = pop @output;
548 is( $answer, "All tests successful.\n", 'cat meows' );
551 # make sure that we can exec with a code ref.
553 my $capture = IO::c55Capture->new_handle;
554 my $harness = TAP::Harness->new(
561 _runtests( $harness, "$source_tests/harness" );
563 my @output = tied($$capture)->dump;
564 my $status = pop @output;
565 like $status, qr{^Result: PASS$},
566 '... and the status line should be correct';
567 pop @output; # get rid of summary line
568 my $answer = pop @output;
569 is( $answer, "All tests successful.\n", 'cat meows' );
572 # Exec with a coderef that returns an arrayref
574 my $cat = '/bin/cat';
579 my $capture = IO::c55Capture->new_handle;
580 my $harness = TAP::Harness->new(
592 _runtests( $harness, "$source_tests/harness" );
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' );
603 # Exec with a coderef that returns raw TAP
605 my $capture = IO::c55Capture->new_handle;
606 my $harness = TAP::Harness->new(
610 return "1..1\nok 1 - raw TAP\n";
615 _runtests( $harness, "$source_tests/harness" );
617 my @output = tied($$capture)->dump;
618 my $status = pop @output;
619 like $status, qr{^Result: PASS$},
620 '... and the status line should be correct';
621 pop @output; # get rid of summary line
622 my $answer = pop @output;
623 is( $answer, "All tests successful.\n", 'cat meows' );
626 # Exec with a coderef that returns a filehandle
628 my $capture = IO::c55Capture->new_handle;
629 my $harness = TAP::Harness->new(
633 open my $fh, 't/data/catme.1';
639 _runtests( $harness, "$source_tests/harness" );
641 my @output = tied($$capture)->dump;
642 my $status = pop @output;
643 like $status, qr{^Result: PASS$},
644 '... and the status line should be correct';
645 pop @output; # get rid of summary line
646 my $answer = pop @output;
647 is( $answer, "All tests successful.\n", 'cat meows' );
650 # catches "exec accumulates arguments" issue (r77)
652 my $capture = IO::c55Capture->new_handle;
653 my $harness = TAP::Harness->new(
662 "$source_tests/harness_complain"
663 , # will get mad if run with args
664 "$source_tests/harness",
667 my @output = tied($$capture)->dump;
668 my $status = pop @output;
669 like $status, qr{^Result: PASS$},
670 '... and the status line should be correct';
671 pop @output; # get rid of summary line
672 is( $output[-1], "All tests successful.\n",
673 'No exec accumulation'
678 $_[0] =~ s/^\s+|\s+$//g;
683 return [ map {"-I$_"} @_ ];
688 # keys are keys to new()
692 out => liblist('lib'),
693 test_name => '... a single lib switch should be correct'
698 test_name => '... and we should be able to set verbosity to 1'
704 # test_name => '... and we should be able to set verbose to true'
708 in => [ 'lib', 't' ],
709 out => liblist( 'lib', 't' ),
710 test_name => '... multiple lib dirs should be correct'
715 test_name => '... and we should be able to set verbosity to 0'
721 # test_name => '... and we should be able to set verbose to false'
725 in => [ '-T', '-w', '-T' ],
726 out => [ '-T', '-w', '-T' ],
727 test_name => '... duplicate switches should remain',
733 '... and we should be able to set failures to true',
738 test_name => '... and we should be able to set verbosity to -1'
744 # test_name => '... and we should be able to set quiet to false'
751 test_name => '... and we should be able to set verbosity to -2'
758 # '... and we should be able to set really_quiet to true',
764 '... and we should be able to set the executable',
771 '... leading dashes (-) on switches are not optional',
777 test_name => '... we should be able to set switches',
782 test_name => '... and we should be able to set failures to true'
788 my ( $harness, @tests ) = @_;
789 local $ENV{PERL_TEST_HARNESS_DUMP_TAP} = 0;
790 my $aggregate = $harness->runtests(@tests);
796 # coverage tests for ctor
798 my $harness = TAP::Harness->new(
807 is $harness->timer(), 0, 'timer getter';
808 is $harness->timer(10), 10, 'timer setter';
809 is $harness->errors(), 1, 'errors getter';
810 is $harness->errors(10), 10, 'errors setter';
811 is $harness->merge(), 2, 'merge getter';
812 is $harness->merge(10), 10, 'merge setter';
815 is $harness->jobs(), 1, 'jobs';
820 # coverage tests for the stdout key of VALIDATON_FOR, used by _initialize() in the ctor
822 # the coverage tests are
823 # 1. ref $ref => false
824 # 2. ref => ! GLOB and ref->can(print)
825 # 3. ref $ref => GLOB
832 local $SIG{__DIE__} = sub { push @die, @_ };
834 my $harness = TAP::Harness->new(
835 { stdout => bless {}, '0', # how evil is THAT !!!
840 is @die, 1, 'bad filehandle to stdout';
841 like pop @die, qr/option 'stdout' needs a filehandle/,
842 '... and we died as expected';
850 sub new { return bless {}, shift }
856 my $harness = TAP::Harness->new(
857 { stdout => Printable->new(),
861 isa_ok $harness, 'TAP::Harness';
867 $harness = TAP::Harness->new(
868 { stdout => bless {}, 'GLOB', # again with the evil
872 isa_ok $harness, 'TAP::Harness';
877 # coverage testing of lib/switches accessor
878 my $harness = TAP::Harness->new;
883 local $SIG{__DIE__} = sub { push @die, @_ };
885 $harness->switches(qw( too many arguments));
888 is @die, 1, 'too many arguments to accessor';
890 like pop @die, qr/Too many arguments to method 'switches'/,
891 '...and we died as expected';
893 $harness->switches('simple scalar');
895 my $arrref = $harness->switches;
896 is_deeply $arrref, ['simple scalar'], 'scalar wrapped in arr ref';
901 # coverage tests for the basically untested T::H::_open_spool
906 $ENV{PERL_TEST_HARNESS_DUMP_TAP} = File::Spec->catfile(@spool);
908 # now given that we're going to be writing stuff to the file system, make sure we have
914 # remove the tree if we made it this far
915 rmtree( $ENV{PERL_TEST_HARNESS_DUMP_TAP} )
916 if $ENV{PERL_TEST_HARNESS_DUMP_TAP};
919 my $harness = TAP::Harness->new( { verbosity => -2 } );
921 can_ok $harness, 'runtests';
923 # normal tests in verbose mode
926 = $harness->runtests( File::Spec->catfile( $source_tests, 'harness' ) );
928 isa_ok $parser, 'TAP::Parser::Aggregator',
929 '... runtests returns the aggregate';
931 ok -e File::Spec->catfile(
932 $ENV{PERL_TEST_HARNESS_DUMP_TAP},
933 $source_tests, 'harness'
941 { name => 'all the same',
942 input => [ 'foo.t', 'bar.t', 'fletz.t' ],
944 [ 'foo.t', 'foo.t' ], [ 'bar.t', 'bar.t' ],
945 [ 'fletz.t', 'fletz.t' ]
948 { name => 'all the same, already cooked',
949 input => [ 'foo.t', [ 'bar.t', 'brip' ], 'fletz.t' ],
951 [ 'foo.t', 'foo.t' ], [ 'bar.t', 'brip' ],
952 [ 'fletz.t', 'fletz.t' ]
955 { name => 'different exts',
956 input => [ 'foo.t', 'bar.u', 'fletz.v' ],
958 [ 'foo.t', 'foo.t' ], [ 'bar.u', 'bar.u' ],
959 [ 'fletz.v', 'fletz.v' ]
962 { name => 'different exts, one already cooked',
963 input => [ 'foo.t', [ 'bar.u', 'bam' ], 'fletz.v' ],
965 [ 'foo.t', 'foo.t' ], [ 'bar.u', 'bam' ],
966 [ 'fletz.v', 'fletz.v' ]
969 { name => 'different exts, two already cooked',
970 input => [ 'foo.t', [ 'bar.u', 'bam.q' ], [ 'fletz.v', 'boo' ] ],
972 [ 'foo.t', 'foo.t' ], [ 'bar.u', 'bam.q' ],
978 for my $case (@cases) {
979 is_deeply [ TAP::Harness->_add_descriptions( @{ $case->{input} } ) ],
980 $case->{output}, '_add_descriptions: ' . $case->{name};