1#!/usr/bin/perl -w 2 3BEGIN { 4 unshift @INC, 't/lib'; 5} 6 7use strict; 8 9use Test::More tests => 79; 10 11use IO::File; 12use IO::Handle; 13use File::Spec; 14 15use TAP::Parser::Source; 16use TAP::Parser::SourceHandler; 17 18my $IS_WIN32 = ( $^O =~ /^(MS)?Win32$/ ); 19my $HAS_SH = -x '/bin/sh'; 20my $HAS_ECHO = -x '/bin/echo'; 21 22my $dir = File::Spec->catdir( 23 't', 24 'source_tests' 25); 26 27my $perl = $^X; 28 29my %file = map { $_ => File::Spec->catfile( $dir, $_ ) } 30 qw( source source.1 source.bat source.pl source.sh source_args.sh source.t 31 source.tap ); 32 33# Abstract base class tests 34{ 35 my $class = 'TAP::Parser::SourceHandler'; 36 my $source = TAP::Parser::Source->new; 37 my $error; 38 39 can_ok $class, 'can_handle'; 40 eval { $class->can_handle($source) }; 41 $error = $@; 42 like $error, qr/^Abstract method 'can_handle'/, 43 '... with an appropriate error message'; 44 45 can_ok $class, 'make_iterator'; 46 eval { $class->make_iterator($source) }; 47 $error = $@; 48 like $error, qr/^Abstract method 'make_iterator'/, 49 '... with an appropriate error message'; 50} 51 52# Executable source tests 53{ 54 my $class = 'TAP::Parser::SourceHandler::Executable'; 55 my $tests = { 56 default_vote => 0, 57 can_handle => [ 58 { name => '.sh', 59 meta => { 60 is_file => 1, 61 file => { lc_ext => '.sh' } 62 }, 63 vote => 0, 64 }, 65 { name => '.bat', 66 meta => { 67 is_file => 1, 68 file => { lc_ext => '.bat' } 69 }, 70 vote => 0.8, 71 }, 72 { name => 'executable bit', 73 meta => { 74 is_file => 1, 75 file => { lc_ext => '', execute => 1 } 76 }, 77 vote => 0.25, 78 }, 79 { name => 'exec hash', 80 raw => { exec => 'foo' }, 81 meta => { is_hash => 1 }, 82 vote => 0.9, 83 }, 84 ], 85 make_iterator => [ 86 { name => "valid executable", 87 raw => [ 88 $perl, ( $ENV{PERL_CORE} ? '-I../../lib' : () ), 89 '-It/lib', '-T', $file{source} 90 ], 91 iclass => 'TAP::Parser::Iterator::Process', 92 output => [ '1..1', 'ok 1 - source' ], 93 assemble_meta => 1, 94 }, 95 { name => "invalid source->raw", 96 raw => "$perl -It/lib $file{source}", 97 error => qr/^No command found/, 98 }, 99 { name => "non-existent source->raw", 100 raw => [], 101 error => qr/^No command found/, 102 }, 103 { name => $file{'source.sh'}, 104 raw => \$file{'source.sh'}, 105 skip => $HAS_SH && $HAS_ECHO ? 0 : 1, 106 skip_reason => 'no /bin/sh, /bin/echo', 107 iclass => 'TAP::Parser::Iterator::Process', 108 output => [ '1..1', 'ok 1 - source.sh' ], 109 assemble_meta => 1, 110 }, 111 { name => $file{'source_args.sh'}, 112 raw => { exec => [ $file{'source_args.sh'} ] }, 113 test_args => ['foo'], 114 skip => $HAS_SH && $HAS_ECHO ? 0 : 1, 115 skip_reason => 'no /bin/sh, /bin/echo', 116 iclass => 'TAP::Parser::Iterator::Process', 117 output => [ '1..1', 'ok 1 - source_args.sh foo' ], 118 assemble_meta => 1, 119 }, 120 { name => $file{'source.bat'}, 121 raw => \$file{'source.bat'}, 122 skip => $IS_WIN32 ? 0 : 1, 123 skip_reason => 'not running Win32', 124 iclass => 'TAP::Parser::Iterator::Process', 125 output => [ '1..1', 'ok 1 - source.bat' ], 126 assemble_meta => 1, 127 }, 128 ], 129 }; 130 131 test_handler( $class, $tests ); 132} 133 134# Perl source tests 135{ 136 my $class = 'TAP::Parser::SourceHandler::Perl'; 137 my $tests = { 138 default_vote => 0, 139 can_handle => [ 140 { name => '.t', 141 meta => { 142 is_file => 1, 143 file => { lc_ext => '.t', dir => '' } 144 }, 145 vote => 0.8, 146 }, 147 { name => '.pl', 148 meta => { 149 is_file => 1, 150 file => { lc_ext => '.pl', dir => '' } 151 }, 152 vote => 0.9, 153 }, 154 { name => 't/.../file', 155 meta => { 156 is_file => 1, 157 file => { lc_ext => '', dir => 't' } 158 }, 159 vote => 0.75, 160 }, 161 { name => '#!...perl', 162 meta => { 163 is_file => 1, 164 file => { 165 lc_ext => '', dir => '', shebang => '#!/usr/bin/perl' 166 } 167 }, 168 vote => 0.9, 169 }, 170 { name => 'file default', 171 meta => { 172 is_file => 1, 173 file => { lc_ext => '', dir => '' } 174 }, 175 vote => 0.25, 176 }, 177 ], 178 make_iterator => [ 179 { name => $file{source}, 180 raw => \$file{source}, 181 iclass => 'TAP::Parser::Iterator::Process', 182 output => [ '1..1', 'ok 1 - source' ], 183 assemble_meta => 1, 184 }, 185 ], 186 }; 187 188 test_handler( $class, $tests ); 189 190 # internals tests! 191 { 192 my $source = TAP::Parser::Source->new->raw( \$file{source} ); 193 $source->assemble_meta; 194 my $iterator = $class->make_iterator($source); 195 my @command = @{ $iterator->{command} }; 196 ok( grep( $_ =~ /^['"]?-T['"]?$/, @command ), 197 '... and it should find the taint switch' 198 ); 199 } 200} 201 202# Raw TAP source tests 203{ 204 my $class = 'TAP::Parser::SourceHandler::RawTAP'; 205 my $tests = { 206 default_vote => 0, 207 can_handle => [ 208 { name => 'file', 209 meta => { is_file => 1 }, 210 raw => \'', 211 vote => 0, 212 }, 213 { name => 'scalar w/newlines', 214 raw => \"hello\nworld\n", 215 vote => 0.3, 216 assemble_meta => 1, 217 }, 218 { name => '1..10', 219 raw => \"1..10\n", 220 vote => 0.9, 221 assemble_meta => 1, 222 }, 223 { name => 'array', 224 raw => [ '1..1', 'ok 1' ], 225 vote => 0.5, 226 assemble_meta => 1, 227 }, 228 ], 229 make_iterator => [ 230 { name => 'valid scalar', 231 raw => \"1..1\nok 1 - raw\n", 232 iclass => 'TAP::Parser::Iterator::Array', 233 output => [ '1..1', 'ok 1 - raw' ], 234 assemble_meta => 1, 235 }, 236 { name => 'valid array', 237 raw => [ '1..1', 'ok 1 - raw' ], 238 iclass => 'TAP::Parser::Iterator::Array', 239 output => [ '1..1', 'ok 1 - raw' ], 240 assemble_meta => 1, 241 }, 242 ], 243 }; 244 245 test_handler( $class, $tests ); 246} 247 248# Text file TAP source tests 249{ 250 my $class = 'TAP::Parser::SourceHandler::File'; 251 my $tests = { 252 default_vote => 0, 253 can_handle => [ 254 { name => '.tap', 255 meta => { 256 is_file => 1, 257 file => { lc_ext => '.tap' } 258 }, 259 vote => 0.9, 260 }, 261 { name => '.foo with config', 262 meta => { 263 is_file => 1, 264 file => { lc_ext => '.foo' } 265 }, 266 config => { File => { extensions => ['.foo'] } }, 267 vote => 0.9, 268 }, 269 ], 270 make_iterator => [ 271 { name => $file{'source.tap'}, 272 raw => \$file{'source.tap'}, 273 iclass => 'TAP::Parser::Iterator::Stream', 274 output => [ '1..1', 'ok 1 - source.tap' ], 275 assemble_meta => 1, 276 }, 277 { name => $file{'source.1'}, 278 raw => \$file{'source.1'}, 279 config => { File => { extensions => ['.1'] } }, 280 iclass => 'TAP::Parser::Iterator::Stream', 281 output => [ '1..1', 'ok 1 - source.1' ], 282 assemble_meta => 1, 283 }, 284 ], 285 }; 286 287 test_handler( $class, $tests ); 288} 289 290# IO::Handle TAP source tests 291{ 292 my $class = 'TAP::Parser::SourceHandler::Handle'; 293 my $tests = { 294 default_vote => 0, 295 can_handle => [ 296 { name => 'glob', 297 meta => { is_glob => 1 }, 298 vote => 0.8, 299 }, 300 { name => 'IO::Handle', 301 raw => IO::Handle->new, 302 vote => 0.9, 303 assemble_meta => 1, 304 }, 305 ], 306 make_iterator => [ 307 { name => 'IO::Handle', 308 raw => IO::File->new( $file{'source.tap'} ), 309 iclass => 'TAP::Parser::Iterator::Stream', 310 output => [ '1..1', 'ok 1 - source.tap' ], 311 assemble_meta => 1, 312 }, 313 ], 314 }; 315 316 test_handler( $class, $tests ); 317} 318 319############################################################################### 320# helper sub 321 322sub test_handler { 323 my ( $class, $tests ) = @_; 324 my ($short_class) = ( $class =~ /\:\:(\w+)$/ ); 325 326 use_ok $class; 327 can_ok $class, 'can_handle', 'make_iterator'; 328 329 { 330 my $default_vote = $tests->{default_vote} || 0; 331 my $source = TAP::Parser::Source->new; 332 is( $class->can_handle($source), $default_vote, 333 '... can_handle default vote' 334 ); 335 } 336 337 for my $test ( @{ $tests->{can_handle} } ) { 338 my $source = TAP::Parser::Source->new; 339 $source->raw( $test->{raw} ) if $test->{raw}; 340 $source->meta( $test->{meta} ) if $test->{meta}; 341 $source->config( $test->{config} ) if $test->{config}; 342 $source->assemble_meta if $test->{assemble_meta}; 343 my $vote = $test->{vote} || 0; 344 my $name = $test->{name} || 'unnamed test'; 345 $name = "$short_class->can_handle( $name )"; 346 is( $class->can_handle($source), $vote, $name ); 347 } 348 349 for my $test ( @{ $tests->{make_iterator} } ) { 350 my $name = $test->{name} || 'unnamed test'; 351 $name = "$short_class->make_iterator( $name )"; 352 353 SKIP: 354 { 355 my $planned = 1; 356 $planned += 1 + scalar @{ $test->{output} } if $test->{output}; 357 skip $test->{skip_reason}, $planned if $test->{skip}; 358 359 my $source = TAP::Parser::Source->new; 360 $source->raw( $test->{raw} ) if $test->{raw}; 361 $source->test_args( $test->{test_args} ) if $test->{test_args}; 362 $source->meta( $test->{meta} ) if $test->{meta}; 363 $source->config( $test->{config} ) if $test->{config}; 364 $source->assemble_meta if $test->{assemble_meta}; 365 366 my $iterator = eval { $class->make_iterator($source) }; 367 my $e = $@; 368 if ( my $error = $test->{error} ) { 369 $e = '' unless defined $e; 370 like $e, $error, "$name threw expected error"; 371 next; 372 } 373 elsif ($e) { 374 fail("$name threw an unexpected error"); 375 diag($e); 376 next; 377 } 378 379 isa_ok $iterator, $test->{iclass}, $name; 380 if ( $test->{output} ) { 381 my $i = 1; 382 for my $line ( @{ $test->{output} } ) { 383 is $iterator->next, $line, "... line $i"; 384 $i++; 385 } 386 ok !$iterator->next, '... and we should have no more results'; 387 } 388 } 389 } 390} 391