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