1898184e3Ssthen#!/usr/bin/perl -w 2898184e3Ssthen 3898184e3SsthenBEGIN { 4898184e3Ssthen unshift @INC, 't/lib'; 5898184e3Ssthen} 6898184e3Ssthen 7898184e3Ssthenuse strict; 86fb12b70Safresh1use warnings; 9898184e3Ssthen 10*5486feefSafresh1use Test::More tests => 82; 11898184e3Ssthen 126fb12b70Safresh1use Config; 13898184e3Ssthenuse IO::File; 14898184e3Ssthenuse IO::Handle; 15898184e3Ssthenuse File::Spec; 16898184e3Ssthen 17898184e3Ssthenuse TAP::Parser::Source; 18898184e3Ssthenuse TAP::Parser::SourceHandler; 19898184e3Ssthen 20898184e3Ssthenmy $IS_WIN32 = ( $^O =~ /^(MS)?Win32$/ ); 21898184e3Ssthenmy $HAS_SH = -x '/bin/sh'; 22898184e3Ssthenmy $HAS_ECHO = -x '/bin/echo'; 23898184e3Ssthen 24898184e3Ssthenmy $dir = File::Spec->catdir( 25898184e3Ssthen 't', 26898184e3Ssthen 'source_tests' 27898184e3Ssthen); 28898184e3Ssthen 29898184e3Ssthenmy $perl = $^X; 30898184e3Ssthen 31898184e3Ssthenmy %file = map { $_ => File::Spec->catfile( $dir, $_ ) } 32898184e3Ssthen qw( source source.1 source.bat source.pl source.sh source_args.sh source.t 33898184e3Ssthen source.tap ); 34898184e3Ssthen 35898184e3Ssthen# Abstract base class tests 36898184e3Ssthen{ 37898184e3Ssthen my $class = 'TAP::Parser::SourceHandler'; 38898184e3Ssthen my $source = TAP::Parser::Source->new; 39898184e3Ssthen my $error; 40898184e3Ssthen 41898184e3Ssthen can_ok $class, 'can_handle'; 42898184e3Ssthen eval { $class->can_handle($source) }; 43898184e3Ssthen $error = $@; 44898184e3Ssthen like $error, qr/^Abstract method 'can_handle'/, 45898184e3Ssthen '... with an appropriate error message'; 46898184e3Ssthen 47898184e3Ssthen can_ok $class, 'make_iterator'; 48898184e3Ssthen eval { $class->make_iterator($source) }; 49898184e3Ssthen $error = $@; 50898184e3Ssthen like $error, qr/^Abstract method 'make_iterator'/, 51898184e3Ssthen '... with an appropriate error message'; 52898184e3Ssthen} 53898184e3Ssthen 54898184e3Ssthen# Executable source tests 55898184e3Ssthen{ 56898184e3Ssthen my $class = 'TAP::Parser::SourceHandler::Executable'; 57898184e3Ssthen my $tests = { 58898184e3Ssthen default_vote => 0, 59898184e3Ssthen can_handle => [ 60898184e3Ssthen { name => '.sh', 61898184e3Ssthen meta => { 62898184e3Ssthen is_file => 1, 63898184e3Ssthen file => { lc_ext => '.sh' } 64898184e3Ssthen }, 65898184e3Ssthen vote => 0, 66898184e3Ssthen }, 67898184e3Ssthen { name => '.bat', 68898184e3Ssthen meta => { 69898184e3Ssthen is_file => 1, 70898184e3Ssthen file => { lc_ext => '.bat' } 71898184e3Ssthen }, 72898184e3Ssthen vote => 0.8, 73898184e3Ssthen }, 74898184e3Ssthen { name => 'executable bit', 75898184e3Ssthen meta => { 76898184e3Ssthen is_file => 1, 77898184e3Ssthen file => { lc_ext => '', execute => 1 } 78898184e3Ssthen }, 79898184e3Ssthen vote => 0.25, 80898184e3Ssthen }, 81898184e3Ssthen { name => 'exec hash', 82898184e3Ssthen raw => { exec => 'foo' }, 83898184e3Ssthen meta => { is_hash => 1 }, 84898184e3Ssthen vote => 0.9, 85898184e3Ssthen }, 86898184e3Ssthen ], 87898184e3Ssthen make_iterator => [ 88898184e3Ssthen { name => "valid executable", 89898184e3Ssthen raw => [ 90898184e3Ssthen $perl, ( $ENV{PERL_CORE} ? '-I../../lib' : () ), 916fb12b70Safresh1 (map { "-I$_" } split /$Config{path_sep}/, $ENV{PERL5LIB} || ''), 92898184e3Ssthen '-It/lib', '-T', $file{source} 93898184e3Ssthen ], 94898184e3Ssthen iclass => 'TAP::Parser::Iterator::Process', 95898184e3Ssthen output => [ '1..1', 'ok 1 - source' ], 96898184e3Ssthen assemble_meta => 1, 97898184e3Ssthen }, 98898184e3Ssthen { name => "invalid source->raw", 99898184e3Ssthen raw => "$perl -It/lib $file{source}", 100898184e3Ssthen error => qr/^No command found/, 101898184e3Ssthen }, 102898184e3Ssthen { name => "non-existent source->raw", 103898184e3Ssthen raw => [], 104898184e3Ssthen error => qr/^No command found/, 105898184e3Ssthen }, 106898184e3Ssthen { name => $file{'source.sh'}, 107898184e3Ssthen raw => \$file{'source.sh'}, 108898184e3Ssthen skip => $HAS_SH && $HAS_ECHO ? 0 : 1, 109898184e3Ssthen skip_reason => 'no /bin/sh, /bin/echo', 110898184e3Ssthen iclass => 'TAP::Parser::Iterator::Process', 111898184e3Ssthen output => [ '1..1', 'ok 1 - source.sh' ], 112898184e3Ssthen assemble_meta => 1, 113898184e3Ssthen }, 114898184e3Ssthen { name => $file{'source_args.sh'}, 115898184e3Ssthen raw => { exec => [ $file{'source_args.sh'} ] }, 116898184e3Ssthen test_args => ['foo'], 117898184e3Ssthen skip => $HAS_SH && $HAS_ECHO ? 0 : 1, 118898184e3Ssthen skip_reason => 'no /bin/sh, /bin/echo', 119898184e3Ssthen iclass => 'TAP::Parser::Iterator::Process', 120898184e3Ssthen output => [ '1..1', 'ok 1 - source_args.sh foo' ], 121898184e3Ssthen assemble_meta => 1, 122898184e3Ssthen }, 123898184e3Ssthen { name => $file{'source.bat'}, 124898184e3Ssthen raw => \$file{'source.bat'}, 125898184e3Ssthen skip => $IS_WIN32 ? 0 : 1, 126898184e3Ssthen skip_reason => 'not running Win32', 127898184e3Ssthen iclass => 'TAP::Parser::Iterator::Process', 128898184e3Ssthen output => [ '1..1', 'ok 1 - source.bat' ], 129898184e3Ssthen assemble_meta => 1, 130898184e3Ssthen }, 131898184e3Ssthen ], 132898184e3Ssthen }; 133898184e3Ssthen 134898184e3Ssthen test_handler( $class, $tests ); 135898184e3Ssthen} 136898184e3Ssthen 137898184e3Ssthen# Perl source tests 138898184e3Ssthen{ 139898184e3Ssthen my $class = 'TAP::Parser::SourceHandler::Perl'; 140898184e3Ssthen my $tests = { 141898184e3Ssthen default_vote => 0, 142898184e3Ssthen can_handle => [ 143898184e3Ssthen { name => '.t', 144898184e3Ssthen meta => { 145898184e3Ssthen is_file => 1, 146898184e3Ssthen file => { lc_ext => '.t', dir => '' } 147898184e3Ssthen }, 148898184e3Ssthen vote => 0.8, 149898184e3Ssthen }, 150*5486feefSafresh1 { name => '.t (no shebang)', 151*5486feefSafresh1 meta => { 152*5486feefSafresh1 is_file => 1, 153*5486feefSafresh1 file => { 154*5486feefSafresh1 lc_ext => '.t', dir => '', shebang => 'use strict;' 155*5486feefSafresh1 } 156*5486feefSafresh1 }, 157*5486feefSafresh1 vote => 0.8, 158*5486feefSafresh1 }, 159898184e3Ssthen { name => '.pl', 160898184e3Ssthen meta => { 161898184e3Ssthen is_file => 1, 162898184e3Ssthen file => { lc_ext => '.pl', dir => '' } 163898184e3Ssthen }, 164898184e3Ssthen vote => 0.9, 165898184e3Ssthen }, 166898184e3Ssthen { name => 't/.../file', 167898184e3Ssthen meta => { 168898184e3Ssthen is_file => 1, 169898184e3Ssthen file => { lc_ext => '', dir => 't' } 170898184e3Ssthen }, 171898184e3Ssthen vote => 0.75, 172898184e3Ssthen }, 173898184e3Ssthen { name => '#!...perl', 174898184e3Ssthen meta => { 175898184e3Ssthen is_file => 1, 176898184e3Ssthen file => { 177898184e3Ssthen lc_ext => '', dir => '', shebang => '#!/usr/bin/perl' 178898184e3Ssthen } 179898184e3Ssthen }, 180898184e3Ssthen vote => 0.9, 181898184e3Ssthen }, 182*5486feefSafresh1 { name => '#!...sh', 183*5486feefSafresh1 meta => { 184*5486feefSafresh1 is_file => 1, 185*5486feefSafresh1 file => { 186*5486feefSafresh1 lc_ext => '', dir => '', shebang => '#!/bin/sh' 187*5486feefSafresh1 } 188*5486feefSafresh1 }, 189*5486feefSafresh1 vote => 0.3, 190*5486feefSafresh1 }, 191*5486feefSafresh1 { name => 'use strict; # first line not shebang', 192*5486feefSafresh1 meta => { 193*5486feefSafresh1 is_file => 1, 194*5486feefSafresh1 file => { 195*5486feefSafresh1 lc_ext => '', dir => '', shebang => 'use strict;' 196*5486feefSafresh1 } 197*5486feefSafresh1 }, 198*5486feefSafresh1 vote => 0.25, 199*5486feefSafresh1 }, 200898184e3Ssthen { name => 'file default', 201898184e3Ssthen meta => { 202898184e3Ssthen is_file => 1, 203898184e3Ssthen file => { lc_ext => '', dir => '' } 204898184e3Ssthen }, 205898184e3Ssthen vote => 0.25, 206898184e3Ssthen }, 207898184e3Ssthen ], 208898184e3Ssthen make_iterator => [ 209898184e3Ssthen { name => $file{source}, 210898184e3Ssthen raw => \$file{source}, 211898184e3Ssthen iclass => 'TAP::Parser::Iterator::Process', 212898184e3Ssthen output => [ '1..1', 'ok 1 - source' ], 213898184e3Ssthen assemble_meta => 1, 214898184e3Ssthen }, 215898184e3Ssthen ], 216898184e3Ssthen }; 217898184e3Ssthen 218898184e3Ssthen test_handler( $class, $tests ); 219898184e3Ssthen 220898184e3Ssthen # internals tests! 221898184e3Ssthen { 222898184e3Ssthen my $source = TAP::Parser::Source->new->raw( \$file{source} ); 223898184e3Ssthen $source->assemble_meta; 224898184e3Ssthen my $iterator = $class->make_iterator($source); 225898184e3Ssthen my @command = @{ $iterator->{command} }; 226898184e3Ssthen ok( grep( $_ =~ /^['"]?-T['"]?$/, @command ), 227898184e3Ssthen '... and it should find the taint switch' 228898184e3Ssthen ); 229898184e3Ssthen } 230898184e3Ssthen} 231898184e3Ssthen 232898184e3Ssthen# Raw TAP source tests 233898184e3Ssthen{ 234898184e3Ssthen my $class = 'TAP::Parser::SourceHandler::RawTAP'; 235898184e3Ssthen my $tests = { 236898184e3Ssthen default_vote => 0, 237898184e3Ssthen can_handle => [ 238898184e3Ssthen { name => 'file', 239898184e3Ssthen meta => { is_file => 1 }, 240898184e3Ssthen raw => \'', 241898184e3Ssthen vote => 0, 242898184e3Ssthen }, 243898184e3Ssthen { name => 'scalar w/newlines', 244898184e3Ssthen raw => \"hello\nworld\n", 245898184e3Ssthen vote => 0.3, 246898184e3Ssthen assemble_meta => 1, 247898184e3Ssthen }, 248898184e3Ssthen { name => '1..10', 249898184e3Ssthen raw => \"1..10\n", 250898184e3Ssthen vote => 0.9, 251898184e3Ssthen assemble_meta => 1, 252898184e3Ssthen }, 253898184e3Ssthen { name => 'array', 254898184e3Ssthen raw => [ '1..1', 'ok 1' ], 255898184e3Ssthen vote => 0.5, 256898184e3Ssthen assemble_meta => 1, 257898184e3Ssthen }, 258898184e3Ssthen ], 259898184e3Ssthen make_iterator => [ 260898184e3Ssthen { name => 'valid scalar', 261898184e3Ssthen raw => \"1..1\nok 1 - raw\n", 262898184e3Ssthen iclass => 'TAP::Parser::Iterator::Array', 263898184e3Ssthen output => [ '1..1', 'ok 1 - raw' ], 264898184e3Ssthen assemble_meta => 1, 265898184e3Ssthen }, 266898184e3Ssthen { name => 'valid array', 267898184e3Ssthen raw => [ '1..1', 'ok 1 - raw' ], 268898184e3Ssthen iclass => 'TAP::Parser::Iterator::Array', 269898184e3Ssthen output => [ '1..1', 'ok 1 - raw' ], 270898184e3Ssthen assemble_meta => 1, 271898184e3Ssthen }, 272898184e3Ssthen ], 273898184e3Ssthen }; 274898184e3Ssthen 275898184e3Ssthen test_handler( $class, $tests ); 276898184e3Ssthen} 277898184e3Ssthen 278898184e3Ssthen# Text file TAP source tests 279898184e3Ssthen{ 280898184e3Ssthen my $class = 'TAP::Parser::SourceHandler::File'; 281898184e3Ssthen my $tests = { 282898184e3Ssthen default_vote => 0, 283898184e3Ssthen can_handle => [ 284898184e3Ssthen { name => '.tap', 285898184e3Ssthen meta => { 286898184e3Ssthen is_file => 1, 287898184e3Ssthen file => { lc_ext => '.tap' } 288898184e3Ssthen }, 289898184e3Ssthen vote => 0.9, 290898184e3Ssthen }, 291898184e3Ssthen { name => '.foo with config', 292898184e3Ssthen meta => { 293898184e3Ssthen is_file => 1, 294898184e3Ssthen file => { lc_ext => '.foo' } 295898184e3Ssthen }, 296898184e3Ssthen config => { File => { extensions => ['.foo'] } }, 297898184e3Ssthen vote => 0.9, 298898184e3Ssthen }, 299898184e3Ssthen ], 300898184e3Ssthen make_iterator => [ 301898184e3Ssthen { name => $file{'source.tap'}, 302898184e3Ssthen raw => \$file{'source.tap'}, 303898184e3Ssthen iclass => 'TAP::Parser::Iterator::Stream', 304898184e3Ssthen output => [ '1..1', 'ok 1 - source.tap' ], 305898184e3Ssthen assemble_meta => 1, 306898184e3Ssthen }, 307898184e3Ssthen { name => $file{'source.1'}, 308898184e3Ssthen raw => \$file{'source.1'}, 309898184e3Ssthen config => { File => { extensions => ['.1'] } }, 310898184e3Ssthen iclass => 'TAP::Parser::Iterator::Stream', 311898184e3Ssthen output => [ '1..1', 'ok 1 - source.1' ], 312898184e3Ssthen assemble_meta => 1, 313898184e3Ssthen }, 314898184e3Ssthen ], 315898184e3Ssthen }; 316898184e3Ssthen 317898184e3Ssthen test_handler( $class, $tests ); 318898184e3Ssthen} 319898184e3Ssthen 320898184e3Ssthen# IO::Handle TAP source tests 321898184e3Ssthen{ 322898184e3Ssthen my $class = 'TAP::Parser::SourceHandler::Handle'; 323898184e3Ssthen my $tests = { 324898184e3Ssthen default_vote => 0, 325898184e3Ssthen can_handle => [ 326898184e3Ssthen { name => 'glob', 327898184e3Ssthen meta => { is_glob => 1 }, 328898184e3Ssthen vote => 0.8, 329898184e3Ssthen }, 330898184e3Ssthen { name => 'IO::Handle', 331898184e3Ssthen raw => IO::Handle->new, 332898184e3Ssthen vote => 0.9, 333898184e3Ssthen assemble_meta => 1, 334898184e3Ssthen }, 335898184e3Ssthen ], 336898184e3Ssthen make_iterator => [ 337898184e3Ssthen { name => 'IO::Handle', 338898184e3Ssthen raw => IO::File->new( $file{'source.tap'} ), 339898184e3Ssthen iclass => 'TAP::Parser::Iterator::Stream', 340898184e3Ssthen output => [ '1..1', 'ok 1 - source.tap' ], 341898184e3Ssthen assemble_meta => 1, 342898184e3Ssthen }, 343898184e3Ssthen ], 344898184e3Ssthen }; 345898184e3Ssthen 346898184e3Ssthen test_handler( $class, $tests ); 347898184e3Ssthen} 348898184e3Ssthen 349898184e3Ssthen############################################################################### 350898184e3Ssthen# helper sub 351898184e3Ssthen 352898184e3Ssthensub test_handler { 353898184e3Ssthen my ( $class, $tests ) = @_; 354898184e3Ssthen my ($short_class) = ( $class =~ /\:\:(\w+)$/ ); 355898184e3Ssthen 356898184e3Ssthen use_ok $class; 357898184e3Ssthen can_ok $class, 'can_handle', 'make_iterator'; 358898184e3Ssthen 359898184e3Ssthen { 360898184e3Ssthen my $default_vote = $tests->{default_vote} || 0; 361898184e3Ssthen my $source = TAP::Parser::Source->new; 362898184e3Ssthen is( $class->can_handle($source), $default_vote, 363898184e3Ssthen '... can_handle default vote' 364898184e3Ssthen ); 365898184e3Ssthen } 366898184e3Ssthen 367898184e3Ssthen for my $test ( @{ $tests->{can_handle} } ) { 368898184e3Ssthen my $source = TAP::Parser::Source->new; 369898184e3Ssthen $source->raw( $test->{raw} ) if $test->{raw}; 370898184e3Ssthen $source->meta( $test->{meta} ) if $test->{meta}; 371898184e3Ssthen $source->config( $test->{config} ) if $test->{config}; 372898184e3Ssthen $source->assemble_meta if $test->{assemble_meta}; 373898184e3Ssthen my $vote = $test->{vote} || 0; 374898184e3Ssthen my $name = $test->{name} || 'unnamed test'; 375898184e3Ssthen $name = "$short_class->can_handle( $name )"; 376898184e3Ssthen is( $class->can_handle($source), $vote, $name ); 377898184e3Ssthen } 378898184e3Ssthen 379898184e3Ssthen for my $test ( @{ $tests->{make_iterator} } ) { 380898184e3Ssthen my $name = $test->{name} || 'unnamed test'; 381898184e3Ssthen $name = "$short_class->make_iterator( $name )"; 382898184e3Ssthen 383898184e3Ssthen SKIP: 384898184e3Ssthen { 385898184e3Ssthen my $planned = 1; 386898184e3Ssthen $planned += 1 + scalar @{ $test->{output} } if $test->{output}; 387898184e3Ssthen skip $test->{skip_reason}, $planned if $test->{skip}; 388898184e3Ssthen 389898184e3Ssthen my $source = TAP::Parser::Source->new; 390898184e3Ssthen $source->raw( $test->{raw} ) if $test->{raw}; 391898184e3Ssthen $source->test_args( $test->{test_args} ) if $test->{test_args}; 392898184e3Ssthen $source->meta( $test->{meta} ) if $test->{meta}; 393898184e3Ssthen $source->config( $test->{config} ) if $test->{config}; 394898184e3Ssthen $source->assemble_meta if $test->{assemble_meta}; 395898184e3Ssthen 396898184e3Ssthen my $iterator = eval { $class->make_iterator($source) }; 397898184e3Ssthen my $e = $@; 398898184e3Ssthen if ( my $error = $test->{error} ) { 399898184e3Ssthen $e = '' unless defined $e; 400898184e3Ssthen like $e, $error, "$name threw expected error"; 401898184e3Ssthen next; 402898184e3Ssthen } 403898184e3Ssthen elsif ($e) { 404898184e3Ssthen fail("$name threw an unexpected error"); 405898184e3Ssthen diag($e); 406898184e3Ssthen next; 407898184e3Ssthen } 408898184e3Ssthen 409898184e3Ssthen isa_ok $iterator, $test->{iclass}, $name; 410898184e3Ssthen if ( $test->{output} ) { 411898184e3Ssthen my $i = 1; 412898184e3Ssthen for my $line ( @{ $test->{output} } ) { 413898184e3Ssthen is $iterator->next, $line, "... line $i"; 414898184e3Ssthen $i++; 415898184e3Ssthen } 416898184e3Ssthen ok !$iterator->next, '... and we should have no more results'; 417898184e3Ssthen } 418898184e3Ssthen } 419898184e3Ssthen } 420898184e3Ssthen} 421