%PDF- %PDF-
Direktori : /home/opti/optisoftcom/.cpanm/work/1544535425.21555/Test-Harness-3.42/t/ |
Current File : /home/opti/optisoftcom/.cpanm/work/1544535425.21555/Test-Harness-3.42/t/harness.t |
#!/usr/bin/perl -w BEGIN { unshift @INC, 't/lib'; } use strict; use warnings; use Test::More; use IO::c55Capture; use TAP::Harness; # This is done to prevent the colors environment variables from # interfering. local $ENV{HARNESS_SUMMARY_COLOR_FAIL}; local $ENV{HARNESS_SUMMARY_COLOR_SUCCESS}; delete $ENV{HARNESS_SUMMARY_COLOR_FAIL}; delete $ENV{HARNESS_SUMMARY_COLOR_SUCCESS}; my $HARNESS = 'TAP::Harness'; my $source_tests = 't/source_tests'; my $sample_tests = 't/sample-tests'; plan tests => 132; # note that this test will always pass when run through 'prove' ok $ENV{HARNESS_ACTIVE}, 'HARNESS_ACTIVE env variable should be set'; ok $ENV{HARNESS_VERSION}, 'HARNESS_VERSION env variable should be set'; #### For color tests #### package Colorizer; sub new { bless {}, shift } sub can_color {1} sub set_color { my ( $self, $output, $color ) = @_; $output->("[[$color]]"); } package main; sub colorize { my $harness = shift; $harness->formatter->_colorizer( Colorizer->new ); } can_ok $HARNESS, 'new'; eval { $HARNESS->new( { no_such_key => 1 } ) }; like $@, qr/\QUnknown arguments to TAP::Harness::new (no_such_key)/, '... and calling it with bad keys should fail'; eval { $HARNESS->new( { lib => 'aint_no_such_lib' } ) }; is $@, '', '... and calling it with a non-existent lib is fine'; eval { $HARNESS->new( { lib => [qw/bad_lib_1 bad_lib_2/] } ) }; is $@, '', '... and calling it with non-existent libs is fine'; ok my $harness = $HARNESS->new, 'Calling new() without arguments should succeed'; for my $test_args ( get_arg_sets() ) { my %args = %$test_args; for my $key ( sort keys %args ) { $args{$key} = $args{$key}{in}; } ok my $harness = $HARNESS->new( {%args} ), 'Calling new() with valid arguments should succeed'; isa_ok $harness, $HARNESS, '... and the object it returns'; while ( my ( $property, $test ) = each %$test_args ) { my $value = $test->{out}; can_ok $harness, $property; is_deeply scalar $harness->$property(), $value, $test->{test_name}; } } { my @output; no warnings 'redefine'; local *TAP::Formatter::Base::_output = sub { my $self = shift; push @output => grep { $_ ne '' } map { local $_ = $_; chomp; trim($_) } @_; }; my $harness = TAP::Harness->new( { verbosity => 1, formatter_class => "TAP::Formatter::Console" } ); my $harness_whisper = TAP::Harness->new( { verbosity => -1, formatter_class => "TAP::Formatter::Console" } ); my $harness_mute = TAP::Harness->new( { verbosity => -2, formatter_class => "TAP::Formatter::Console" } ); my $harness_directives = TAP::Harness->new( { directives => 1, formatter_class => "TAP::Formatter::Console" } ); my $harness_failures = TAP::Harness->new( { failures => 1, formatter_class => "TAP::Formatter::Console" } ); colorize($harness); can_ok $harness, 'runtests'; # normal tests in verbose mode ok my $aggregate = _runtests( $harness, "$source_tests/harness" ), '... runtests returns the aggregate'; isa_ok $aggregate, 'TAP::Parser::Aggregator'; chomp(@output); my @expected = ( "$source_tests/harness ..", '1..1', '[[reset]]', 'ok 1 - this is a test', '[[reset]]', 'ok', '[[green]]', 'All tests successful.', '[[reset]]', ); my $status = pop @output; my $expected_status = qr{^Result: PASS$}; my $summary = pop @output; my $expected_summary = qr{^Files=1, Tests=1, +\d+ wallclock secs}; is_deeply \@output, \@expected, '... and the output should be correct'; like $status, $expected_status, '... and the status line should be correct'; like $summary, $expected_summary, '... and the report summary should look correct'; # use an alias for test name @output = (); ok $aggregate = _runtests( $harness, [ "$source_tests/harness", 'My Nice Test' ] ), '... runtests returns the aggregate'; isa_ok $aggregate, 'TAP::Parser::Aggregator'; chomp(@output); @expected = ( 'My Nice Test ..', '1..1', '[[reset]]', 'ok 1 - this is a test', '[[reset]]', 'ok', '[[green]]', 'All tests successful.', '[[reset]]', ); $status = pop @output; $expected_status = qr{^Result: PASS$}; $summary = pop @output; $expected_summary = qr{^Files=1, Tests=1, +\d+ wallclock secs}; is_deeply \@output, \@expected, '... and the output should be correct'; like $status, $expected_status, '... and the status line should be correct'; like $summary, $expected_summary, '... and the report summary should look correct'; # run same test twice @output = (); ok $aggregate = _runtests( $harness, [ "$source_tests/harness", 'My Nice Test' ], [ "$source_tests/harness", 'My Nice Test Again' ] ), '... runtests returns the aggregate'; isa_ok $aggregate, 'TAP::Parser::Aggregator'; chomp(@output); @expected = ( 'My Nice Test ........', '1..1', '[[reset]]', 'ok 1 - this is a test', '[[reset]]', 'ok', 'My Nice Test Again ..', '1..1', '[[reset]]', 'ok 1 - this is a test', '[[reset]]', 'ok', '[[green]]', 'All tests successful.', '[[reset]]', ); $status = pop @output; $expected_status = qr{^Result: PASS$}; $summary = pop @output; $expected_summary = qr{^Files=2, Tests=2, +\d+ wallclock secs}; is_deeply \@output, \@expected, '... and the output should be correct'; like $status, $expected_status, '... and the status line should be correct'; like $summary, $expected_summary, '... and the report summary should look correct'; # normal tests in quiet mode @output = (); _runtests( $harness_whisper, "$source_tests/harness" ); chomp(@output); @expected = ( "$source_tests/harness ..", 'ok', 'All tests successful.', ); $status = pop @output; $expected_status = qr{^Result: PASS$}; $summary = pop @output; $expected_summary = qr/^Files=1, Tests=1, +\d+ wallclock secs/; is_deeply \@output, \@expected, '... and the output should be correct'; like $status, $expected_status, '... and the status line should be correct'; like $summary, $expected_summary, '... and the report summary should look correct'; # normal tests in really_quiet mode @output = (); _runtests( $harness_mute, "$source_tests/harness" ); chomp(@output); @expected = ( 'All tests successful.', ); $status = pop @output; $expected_status = qr{^Result: PASS$}; $summary = pop @output; $expected_summary = qr/^Files=1, Tests=1, +\d+ wallclock secs/; is_deeply \@output, \@expected, '... and the output should be correct'; like $status, $expected_status, '... and the status line should be correct'; like $summary, $expected_summary, '... and the report summary should look correct'; # normal tests with failures @output = (); _runtests( $harness, "$source_tests/harness_failure" ); $status = pop @output; $summary = pop @output; like $status, qr{^Result: FAIL$}, '... and the status line should be correct'; my @summary = @output[ 18 .. $#output ]; @output = @output[ 0 .. 17 ]; @expected = ( "$source_tests/harness_failure ..", '1..2', '[[reset]]', 'ok 1 - this is a test', '[[reset]]', '[[red]]', 'not ok 2 - this is another test', '[[reset]]', q{# Failed test 'this is another test'}, '[[reset]]', '# in harness_failure.t at line 5.', '[[reset]]', q{# got: 'waffle'}, '[[reset]]', q{# expected: 'yarblokos'}, '[[reset]]', '[[red]]', 'Failed 1/2 subtests', ); is_deeply \@output, \@expected, '... and failing test output should be correct'; my @expected_summary = ( '[[reset]]', 'Test Summary Report', '-------------------', '[[red]]', "$source_tests/harness_failure (Wstat: 0 Tests: 2 Failed: 1)", '[[reset]]', '[[red]]', 'Failed test:', '[[reset]]', '[[red]]', '2', '[[reset]]', ); is_deeply \@summary, \@expected_summary, '... and the failure summary should also be correct'; # quiet tests with failures @output = (); _runtests( $harness_whisper, "$source_tests/harness_failure" ); $status = pop @output; $summary = pop @output; @expected = ( "$source_tests/harness_failure ..", 'Failed 1/2 subtests', 'Test Summary Report', '-------------------', "$source_tests/harness_failure (Wstat: 0 Tests: 2 Failed: 1)", 'Failed test:', '2', ); like $status, qr{^Result: FAIL$}, '... and the status line should be correct'; is_deeply \@output, \@expected, '... and failing test output should be correct'; # really quiet tests with failures @output = (); _runtests( $harness_mute, "$source_tests/harness_failure" ); $status = pop @output; $summary = pop @output; @expected = ( 'Test Summary Report', '-------------------', "$source_tests/harness_failure (Wstat: 0 Tests: 2 Failed: 1)", 'Failed test:', '2', ); like $status, qr{^Result: FAIL$}, '... and the status line should be correct'; is_deeply \@output, \@expected, '... and failing test output should be correct'; # only show directives @output = (); _runtests( $harness_directives, "$source_tests/harness_directives" ); chomp(@output); @expected = ( "$source_tests/harness_directives ..", 'not ok 2 - we have a something # TODO some output', "ok 3 houston, we don't have liftoff # SKIP no funding", 'ok', 'All tests successful.', # ~TODO {{{ this should be an option #'Test Summary Report', #'-------------------', #"$source_tests/harness_directives (Wstat: 0 Tests: 3 Failed: 0)", #'Tests skipped:', #'3', # }}} ); $status = pop @output; $summary = pop @output; $expected_summary = qr/^Files=1, Tests=3, +\d+ wallclock secs/; is_deeply \@output, \@expected, '... and the output should be correct'; like $summary, $expected_summary, '... and the report summary should look correct'; like $status, qr{^Result: PASS$}, '... and the status line should be correct'; # normal tests with bad tap # install callback handler my $parser; my $callback_count = 0; my @callback_log = (); for my $evt (qw(parser_args made_parser before_runtests after_runtests)) { $harness->callback( $evt => sub { push @callback_log, $evt; } ); } $harness->callback( made_parser => sub { $parser = shift; $callback_count++; } ); @output = (); _runtests( $harness, "$source_tests/harness_badtap" ); chomp(@output); @output = map { trim($_) } @output; $status = pop @output; @summary = @output[ 12 .. ( $#output - 1 ) ]; @output = @output[ 0 .. 11 ]; @expected = ( "$source_tests/harness_badtap ..", '1..2', '[[reset]]', 'ok 1 - this is a test', '[[reset]]', '[[red]]', 'not ok 2 - this is another test', '[[reset]]', '1..2', '[[reset]]', '[[red]]', 'Failed 1/2 subtests', ); is_deeply \@output, \@expected, '... and failing test output should be correct'; like $status, qr{^Result: FAIL$}, '... and the status line should be correct'; @expected_summary = ( '[[reset]]', 'Test Summary Report', '-------------------', '[[red]]', "$source_tests/harness_badtap (Wstat: 0 Tests: 2 Failed: 1)", '[[reset]]', '[[red]]', 'Failed test:', '[[reset]]', '[[red]]', '2', '[[reset]]', '[[red]]', 'Parse errors: More than one plan found in TAP output', '[[reset]]', ); is_deeply \@summary, \@expected_summary, '... and the badtap summary should also be correct'; cmp_ok( $callback_count, '==', 1, 'callback called once' ); is_deeply( \@callback_log, [ 'before_runtests', 'parser_args', 'made_parser', 'after_runtests' ], 'callback log matches' ); isa_ok $parser, 'TAP::Parser'; # coverage testing for _should_show_failures # only show failures @output = (); _runtests( $harness_failures, "$source_tests/harness_failure" ); chomp(@output); @expected = ( "$source_tests/harness_failure ..", 'not ok 2 - this is another test', 'Failed 1/2 subtests', 'Test Summary Report', '-------------------', "$source_tests/harness_failure (Wstat: 0 Tests: 2 Failed: 1)", 'Failed test:', '2', ); $status = pop @output; $summary = pop @output; like $status, qr{^Result: FAIL$}, '... and the status line should be correct'; $expected_summary = qr/^Files=1, Tests=2, +\d+ wallclock secs/; is_deeply \@output, \@expected, '... and the output should be correct'; # check the status output for no tests @output = (); _runtests( $harness_failures, "$sample_tests/no_output" ); chomp(@output); @expected = ( "$sample_tests/no_output ..", 'No subtests run', 'Test Summary Report', '-------------------', "$sample_tests/no_output (Wstat: 0 Tests: 0 Failed: 0)", 'Parse errors: No plan found in TAP output', ); $status = pop @output; $summary = pop @output; like $status, qr{^Result: FAIL$}, '... and the status line should be correct'; $expected_summary = qr/^Files=1, Tests=2, +\d+ wallclock secs/; is_deeply \@output, \@expected, '... and the output should be correct'; #XXXX } # make sure we can exec something ... anything! SKIP: { my $cat = '/bin/cat'; # TODO: use TYPE on win32? unless ( -e $cat ) { skip "no '$cat'", 2; } my $capture = IO::c55Capture->new_handle; my $harness = TAP::Harness->new( { verbosity => -2, stdout => $capture, exec => [$cat], } ); eval { _runtests( $harness, 't/data/catme.1' ); }; my @output = tied($$capture)->dump; my $status = pop @output; like $status, qr{^Result: PASS$}, '... and the status line should be correct'; pop @output; # get rid of summary line my $answer = pop @output; is( $answer, "All tests successful.\n", 'cat meows' ); } # make sure that we can exec with a code ref. { my $capture = IO::c55Capture->new_handle; my $harness = TAP::Harness->new( { verbosity => -2, stdout => $capture, exec => sub {undef}, } ); _runtests( $harness, "$source_tests/harness" ); my @output = tied($$capture)->dump; my $status = pop @output; like $status, qr{^Result: PASS$}, '... and the status line should be correct'; pop @output; # get rid of summary line my $answer = pop @output; is( $answer, "All tests successful.\n", 'cat meows' ); } # Exec with a coderef that returns an arrayref SKIP: { my $cat = '/bin/cat'; unless ( -e $cat ) { skip "no '$cat'", 2; } my $capture = IO::c55Capture->new_handle; my $harness = TAP::Harness->new( { verbosity => -2, stdout => $capture, exec => sub { return [ $cat, 't/data/catme.1' ]; }, } ); _runtests( $harness, "$source_tests/harness" ); my @output = tied($$capture)->dump; my $status = pop @output; like $status, qr{^Result: PASS$}, '... and the status line should be correct'; pop @output; # get rid of summary line my $answer = pop @output; is( $answer, "All tests successful.\n", 'cat meows' ); } # Exec with a coderef that returns raw TAP { my $capture = IO::c55Capture->new_handle; my $harness = TAP::Harness->new( { verbosity => -2, stdout => $capture, exec => sub { return "1..1\nok 1 - raw TAP\n"; }, } ); _runtests( $harness, "$source_tests/harness" ); my @output = tied($$capture)->dump; my $status = pop @output; like $status, qr{^Result: PASS$}, '... and the status line should be correct'; pop @output; # get rid of summary line my $answer = pop @output; is( $answer, "All tests successful.\n", 'cat meows' ); } # Exec with a coderef that returns a filehandle { my $capture = IO::c55Capture->new_handle; my $harness = TAP::Harness->new( { verbosity => -2, stdout => $capture, exec => sub { open my $fh, 't/data/catme.1'; return $fh; }, } ); _runtests( $harness, "$source_tests/harness" ); my @output = tied($$capture)->dump; my $status = pop @output; like $status, qr{^Result: PASS$}, '... and the status line should be correct'; pop @output; # get rid of summary line my $answer = pop @output; is( $answer, "All tests successful.\n", 'cat meows' ); } # catches "exec accumulates arguments" issue (r77) { my $capture = IO::c55Capture->new_handle; my $harness = TAP::Harness->new( { verbosity => -2, stdout => $capture, exec => [$^X] } ); _runtests( $harness, "$source_tests/harness_complain" , # will get mad if run with args "$source_tests/harness", ); my @output = tied($$capture)->dump; my $status = pop @output; like $status, qr{^Result: PASS$}, '... and the status line should be correct'; pop @output; # get rid of summary line is( $output[-1], "All tests successful.\n", 'No exec accumulation' ); } # customize default File source { my $capture = IO::c55Capture->new_handle; my $harness = TAP::Harness->new( { verbosity => -2, stdout => $capture, sources => { File => { extensions => ['.1'] }, }, } ); _runtests( $harness, "$source_tests/source.1" ); my @output = tied($$capture)->dump; my $status = pop @output; like $status, qr{^Result: PASS$}, 'customized File source has correct status line'; pop @output; # get rid of summary line my $answer = pop @output; is( $answer, "All tests successful.\n", '... all tests passed' ); } # load a custom source { my $capture = IO::c55Capture->new_handle; my $harness = TAP::Harness->new( { verbosity => -2, stdout => $capture, sources => { MyFileSourceHandler => { extensions => ['.1'] }, }, } ); my $source_test = "$source_tests/source.1"; eval { _runtests( $harness, "$source_tests/source.1" ); }; my $e = $@; ok( !$e, 'no error on load custom source' ) || diag($e); no warnings 'once'; can_ok( 'MyFileSourceHandler', 'make_iterator' ); ok( $MyFileSourceHandler::CAN_HANDLE, '... MyFileSourceHandler->can_handle was called' ); ok( $MyFileSourceHandler::MAKE_ITER, '... MyFileSourceHandler->make_iterator was called' ); my $raw_source = eval { ${ $MyFileSourceHandler::LAST_SOURCE->raw } }; is( $raw_source, $source_test, '... used the right source' ); my @output = tied($$capture)->dump; my $status = pop(@output) || ''; like $status, qr{^Result: PASS$}, '... and test has correct status line'; pop @output; # get rid of summary line my $answer = pop @output; is( $answer, "All tests successful.\n", '... all tests passed' ); } sub trim { $_[0] =~ s/^\s+|\s+$//g; return $_[0]; } sub liblist { return [ map {"-I$_"} @_ ]; } sub get_arg_sets { # keys are keys to new() return { lib => { in => 'lib', out => liblist('lib'), test_name => '... a single lib switch should be correct' }, verbosity => { in => 1, out => 1, test_name => '... and we should be able to set verbosity to 1' }, # verbose => { # in => 1, # out => 1, # test_name => '... and we should be able to set verbose to true' # }, }, { lib => { in => [ 'lib', 't' ], out => liblist( 'lib', 't' ), test_name => '... multiple lib dirs should be correct' }, verbosity => { in => 0, out => 0, test_name => '... and we should be able to set verbosity to 0' }, # verbose => { # in => 0, # out => 0, # test_name => '... and we should be able to set verbose to false' # }, }, { switches => { in => [ '-T', '-w', '-T' ], out => [ '-T', '-w', '-T' ], test_name => '... duplicate switches should remain', }, failures => { in => 1, out => 1, test_name => '... and we should be able to set failures to true', }, verbosity => { in => -1, out => -1, test_name => '... and we should be able to set verbosity to -1' }, # quiet => { # in => 1, # out => 1, # test_name => '... and we should be able to set quiet to false' # }, }, { verbosity => { in => -2, out => -2, test_name => '... and we should be able to set verbosity to -2' }, # really_quiet => { # in => 1, # out => 1, # test_name => # '... and we should be able to set really_quiet to true', # }, exec => { in => $^X, out => $^X, test_name => '... and we should be able to set the executable', }, }, { switches => { in => 'T', out => ['T'], test_name => '... leading dashes (-) on switches are not optional', }, }, { switches => { in => '-T', out => ['-T'], test_name => '... we should be able to set switches', }, failures => { in => 1, out => 1, test_name => '... and we should be able to set failures to true' }, }; } sub _runtests { my ( $harness, @tests ) = @_; local $ENV{PERL_TEST_HARNESS_DUMP_TAP} = 0; my $aggregate = $harness->runtests(@tests); return $aggregate; } { # coverage tests for ctor my $harness = TAP::Harness->new( { timer => 0, errors => 1, merge => 2, # formatter => 3, } ); is $harness->timer(), 0, 'timer getter'; is $harness->timer(10), 10, 'timer setter'; is $harness->errors(), 1, 'errors getter'; is $harness->errors(10), 10, 'errors setter'; is $harness->merge(), 2, 'merge getter'; is $harness->merge(10), 10, 'merge setter'; # jobs accessor is $harness->jobs(), 1, 'jobs'; } { # coverage tests for the stdout key of VALIDATON_FOR, used by _initialize() in the ctor { # ref $ref => false my @die; eval { local $SIG{__DIE__} = sub { push @die, @_ }; my $harness = TAP::Harness->new( { stdout => bless {}, '0', # how evil is THAT !!! } ); }; is @die, 1, 'bad filehandle to stdout'; like pop @die, qr/option 'stdout' needs a filehandle/, '... and we died as expected'; } { # ref => ! GLOB and ref->can(print) package Printable; sub new { return bless {}, shift } sub print {return} package main; my $harness = TAP::Harness->new( { stdout => Printable->new(), } ); isa_ok $harness, 'TAP::Harness'; } { # ref $ref => GLOB my $harness = TAP::Harness->new( { stdout => bless {}, 'GLOB', # again with the evil } ); isa_ok $harness, 'TAP::Harness'; } { # bare glob my $harness = TAP::Harness->new( { stdout => *STDOUT } ); isa_ok $harness, 'TAP::Harness'; } { # string filehandle my $string = ''; open my $fh, ">", \$string or die $!; my $harness = TAP::Harness->new( { stdout => $fh } ); isa_ok $harness, 'TAP::Harness'; } { # lexical filehandle reference my $string = ''; open my $fh, ">", \$string or die $!; ok !eval { TAP::Harness->new( { stdout => \$fh } ); }; like $@, qr/^option 'stdout' needs a filehandle /; } } { # coverage testing of lib/switches accessor my $harness = TAP::Harness->new; my @die; eval { local $SIG{__DIE__} = sub { push @die, @_ }; $harness->switches(qw( too many arguments)); }; is @die, 1, 'too many arguments to accessor'; like pop @die, qr/Too many arguments to method 'switches'/, '...and we died as expected'; $harness->switches('simple scalar'); my $arrref = $harness->switches; is_deeply $arrref, ['simple scalar'], 'scalar wrapped in arr ref'; } { # coverage tests for the basically untested T::H::_open_spool my @spool = ( 't', 'spool' ); $ENV{PERL_TEST_HARNESS_DUMP_TAP} = File::Spec->catfile(@spool); # now given that we're going to be writing stuff to the file system, make sure we have # a cleanup hook END { use File::Path; # remove the tree if we made it this far rmtree( $ENV{PERL_TEST_HARNESS_DUMP_TAP} ) if $ENV{PERL_TEST_HARNESS_DUMP_TAP}; } my $harness = TAP::Harness->new( { verbosity => -2 } ); can_ok $harness, 'runtests'; # normal tests in verbose mode my $parser = $harness->runtests( File::Spec->catfile( $source_tests, 'harness' ) ); isa_ok $parser, 'TAP::Parser::Aggregator', '... runtests returns the aggregate'; ok -e File::Spec->catfile( $ENV{PERL_TEST_HARNESS_DUMP_TAP}, $source_tests, 'harness' ); } { # test name munging my @cases = ( { name => 'all the same', input => [ 'foo.t', 'bar.t', 'fletz.t' ], output => [ [ 'foo.t', 'foo.t' ], [ 'bar.t', 'bar.t' ], [ 'fletz.t', 'fletz.t' ] ], }, { name => 'all the same, already cooked', input => [ 'foo.t', [ 'bar.t', 'brip' ], 'fletz.t' ], output => [ [ 'foo.t', 'foo.t' ], [ 'bar.t', 'brip' ], [ 'fletz.t', 'fletz.t' ] ], }, { name => 'different exts', input => [ 'foo.t', 'bar.u', 'fletz.v' ], output => [ [ 'foo.t', 'foo.t' ], [ 'bar.u', 'bar.u' ], [ 'fletz.v', 'fletz.v' ] ], }, { name => 'different exts, one already cooked', input => [ 'foo.t', [ 'bar.u', 'bam' ], 'fletz.v' ], output => [ [ 'foo.t', 'foo.t' ], [ 'bar.u', 'bam' ], [ 'fletz.v', 'fletz.v' ] ], }, { name => 'different exts, two already cooked', input => [ 'foo.t', [ 'bar.u', 'bam.q' ], [ 'fletz.v', 'boo' ] ], output => [ [ 'foo.t', 'foo.t' ], [ 'bar.u', 'bam.q' ], [ 'fletz.v', 'boo' ] ], }, ); for my $case (@cases) { is_deeply [ TAP::Harness->_add_descriptions( @{ $case->{input} } ) ], $case->{output}, '_add_descriptions: ' . $case->{name}; } }