1#!perl 2# this should be perl 5.8 compatible, since it will be used 3# with old perls while testing dist modules on those perls 4use strict; 5use warnings; 6use File::Temp "tempdir"; 7use ExtUtils::Manifest "maniread"; 8use Cwd "getcwd"; 9use Getopt::Long; 10use Config; 11 12my $continue; 13my $separate; 14GetOptions("c|continue" => \$continue, 15 "s|separate" => \$separate, 16 "h|help" => \&usage) 17 or die "Unknown options\n"; 18 19$|++; 20 21-f "Configure" 22 or die "Expected to be run from a perl checkout"; 23 24my $github_ci = $ENV{'GITHUB_SHA'} ? 1 : 0; 25 26my $manifest = maniread(); 27my @failures = (); 28 29my @config; 30my $install_path; 31if ($separate) { 32 # require EU::MM 6.31 or later 33 my $install_base = tempdir( CLEANUP => 1 ); 34 push @config, "INSTALL_BASE=$install_base"; 35 $ENV{PERL5LIB} .= $Config{path_sep} if $ENV{PERL5LIB}; 36 $ENV{PERL5LIB} .= join $Config{path_sep}, 37 "$install_base/lib/perl5/$Config{archname}", 38 "$install_base/lib/perl5"; 39} 40 41my %dist_config = ( 42 # these are defined by the modules as distributed on CPAN 43 # I don't know why their Makefile.PLs aren't in core 44 "threads" => [ "DEFINE=-DHAS_PPPORT_H" ], 45 "threads-shared" => [ "DEFINE=-DHAS_PPPORT_H" ], 46 ); 47 48my $start = getcwd() 49 or die "Cannot fetch current directory: $!\n"; 50 51# get ppport.h 52my $pppdir = test_dist("Devel-PPPort"); 53 54if (@failures) { 55 if ($github_ci) { 56 # GitHub may show STDERR before STDOUT.. despite autoflush 57 # being enabled.. Make sure it detects the 'endgroup' before 58 # the `die` statement. 59 print STDERR "::endgroup::\n"; 60 } 61 die "Devel-PPPort failed, aborting other tests.\n"; 62} 63 64my $pppfile = "$pppdir/ppport.h"; 65 66-f $pppfile 67 or die "No ppport.h found in $pppdir\n"; 68 69# Devel-PPPort is manually processed before anything else to ensure we 70# have an up to date ppport.h 71my @dists = @ARGV; 72if (@dists) { 73 for my $dist (@dists) { 74 -d "dist/$dist" or die "dist/$dist not a directory\n"; 75 } 76} 77else { 78 opendir my $distdir, "dist" 79 or die "Cannot opendir 'dist': $!\n"; 80 @dists = sort { lc $a cmp lc $b } grep { /^\w/ && $_ ne "Devel-PPPort" } readdir $distdir; 81 closedir $distdir; 82} 83 84# These may end up being included if their problems are resolved 85{ 86 # https://github.com/Perl/version.pm claims CPAN is upstream 87 @dists = grep { $_ ne "version" } @dists; 88 89 # Safe is tied pretty heavily to core 90 # in any case it didn't seem simple to fix 91 @dists = grep { $_ ne "Safe" } @dists; 92} 93 94for my $dist (@dists) { 95 test_dist($dist); 96} 97 98if (@failures) { 99 if ($github_ci) { 100 # GitHub may show STDERR before STDOUT.. despite autoflush 101 # being enabled.. Make sure it detects the 'endgroup' before 102 # the `die` statement. 103 print STDERR "::endgroup::\n"; 104 } 105 my $msg = join("\n", map { "\t'$_->[0]' failed at $_->[1]" } @failures); 106 die "Following dists had failures:\n$msg\n"; 107} 108 109sub test_dist { 110 my ($name) = @_; 111 112 print "::group::Testing $name\n" if $github_ci; 113 print "*** Testing $name ***\n"; 114 my $dir = tempdir( CLEANUP => 1); 115 run("cp", "-a", "dist/$name/.", "$dir/.") 116 or die "Cannot copy dist files to working directory\n"; 117 chdir $dir 118 or die "Cannot chdir to dist working directory '$dir': $!\n"; 119 if ($pppfile) { 120 run("cp", $pppfile, ".") 121 or die "Cannot copy $pppfile to .\n"; 122 } 123 if ($name eq "IO" || $name eq "threads" || $name eq "threads-shared") { 124 write_testpl(); 125 } 126 if ($name eq "threads" || $name eq "threads-shared") { 127 write_threads_h(); 128 } 129 if ($name eq "threads-shared") { 130 write_shared_h(); 131 } 132 unless (-f "Makefile.PL") { 133 print " Creating Makefile.PL for $name\n"; 134 my $key = "ABSTRACT_FROM"; 135 my @parts = split /-/, $name; 136 my $last = $parts[-1]; 137 my $module = join "::", @parts; 138 my $fromname; 139 for my $check ("$last.pm", join("/", "lib", @parts) . ".pm") { 140 if (-f $check) { 141 $fromname = $check; 142 last; 143 } 144 } 145 $fromname 146 or die "Cannot find ABSTRACT_FROM for $name\n"; 147 my $value = $fromname; 148 open my $fh, ">", "Makefile.PL" 149 or die "Cannot create Makefile.PL: $!\n"; 150 # adapted from make_ext.pl 151 printf $fh <<'EOM', $module, $fromname, $key, $value; 152use strict; 153use ExtUtils::MakeMaker; 154 155# This is what the .PL extracts to. Not the ultimate file that is installed. 156# (ie Win32 runs pl2bat after this) 157 158# Doing this here avoids all sort of quoting issues that would come from 159# attempting to write out perl source with literals to generate the arrays and 160# hash. 161my @temps = 'Makefile.PL'; 162foreach (glob('scripts/pod*.PL')) { 163 # The various pod*.PL extractors change directory. Doing that with relative 164 # paths in @INC breaks. It seems the lesser of two evils to copy (to avoid) 165 # the chdir doing anything, than to attempt to convert lib paths to 166 # absolute, and potentially run into problems with quoting special 167 # characters in the path to our build dir (such as spaces) 168 require File::Copy; 169 170 my $temp = $_; 171 $temp =~ s!scripts/!!; 172 File::Copy::copy($_, $temp) or die "Can't copy $temp to $_: $!"; 173 push @temps, $temp; 174} 175 176my $script_ext = $^O eq 'VMS' ? '.com' : ''; 177my %%pod_scripts; 178foreach (glob('pod*.PL')) { 179 my $script = $_; 180 s/.PL$/$script_ext/i; 181 $pod_scripts{$script} = $_; 182} 183my @exe_files = values %%pod_scripts; 184 185WriteMakefile( 186 NAME => '%s', 187 VERSION_FROM => '%s', 188 %-13s => '%s', 189 realclean => { FILES => "@temps" }, 190 (%%pod_scripts ? ( 191 PL_FILES => \%%pod_scripts, 192 EXE_FILES => \@exe_files, 193 clean => { FILES => "@exe_files" }, 194 ) : ()), 195); 196 197EOM 198 close $fh; 199 } 200 201 my $verbose = $github_ci && $ENV{'RUNNER_DEBUG'} ? 1 : 0; 202 my $failed = ""; 203 my @my_config = @config; 204 if (my $cfg = $dist_config{$name}) { 205 push @my_config, @$cfg; 206 } 207 if (!run($^X, "Makefile.PL", @my_config)) { 208 $failed = "Makefile.PL"; 209 die "$name: Makefile.PL failed\n" unless $continue; 210 } 211 elsif (!run("make", "test", "TEST_VERBOSE=$verbose")) { 212 $failed = "make test"; 213 die "$name: make test failed\n" unless $continue; 214 } 215 elsif (!run("make", "install")) { 216 $failed = "make install"; 217 die "$name: make install failed\n" unless $continue; 218 } 219 220 chdir $start 221 or die "Cannot return to $start: $!\n"; 222 223 if ($github_ci) { 224 print "::endgroup::\n"; 225 } 226 if ($continue && $failed) { 227 print "::error ::$name failed at $failed\n" if $github_ci; 228 push @failures, [ $name, $failed ]; 229 } 230 231 $dir; 232} 233 234# IO, threads and threads-shared use the blead t/test.pl when tested in core 235# and bundle their own test.pl when distributed on CPAN. 236# The test.pl source below is from the IO distribution but so far seems sufficient 237# for threads and threads-shared. 238sub write_testpl { 239 _write_from_data("t/test.pl"); 240} 241 242# threads and threads-shared bundle this file, which isn't needed in core 243sub write_threads_h { 244 _write_from_data("threads.h"); 245} 246 247# threads-shared bundles this file, which isn't needed in core 248sub write_shared_h { 249 _write_from_data("shared.h"); 250} 251 252# file data read from <DATA> 253my %file_data; 254 255sub _write_from_data { 256 my ($want_name) = @_; 257 258 unless (keys %file_data) { 259 my $name; 260 while (<DATA>) { 261 if (/^-- (\S+) --/) { 262 $name = $1; 263 } 264 else { 265 $file_data{$name} .= $_; 266 } 267 } 268 close DATA; 269 } 270 271 my $data = $file_data{$want_name} or die "No data found for $want_name"; 272 open my $fh, ">", $want_name 273 or die "Cannot create $want_name: $!\n"; 274 print $fh $data; 275 close $fh 276 or die "Cannot close $want_name: $!\n"; 277} 278 279sub run { 280 my (@cmd) = @_; 281 282 print "\$ @cmd\n"; 283 my $result = system(@cmd); 284 if ($result < 0) { 285 print "Failed: $!\n"; 286 } 287 elsif ($result) { 288 printf "Failed: %d (%#x)\n", $result, $?; 289 } 290 return $result == 0; 291} 292 293sub usage { 294 print <<EOS; 295Usage: $^X $0 [options] [distnames] 296 -c | -continue 297 Continue processing after failures 298 Devel::PPPort must successfully build to continue. 299 -s | -separate 300 Install to a work path, not to perl's site_perl. 301 -h | -help 302 Display this message. 303 304Optional distnames should be names of the distributions under dist/ to 305test. If omitted all of the distributions under dist/ are tested. 306Devel-PPPort is always tested. 307 308Test all of the distributions, stop on the first failure: 309 310 $^X $0 -s 311 312Test the various threads distributions, continue on failure: 313 314 $^X $0 -s -c threads threads-shared Thread-Queue Thread-Semaphore 315EOS 316} 317 318__DATA__ 319-- t/test.pl -- 320# 321# t/test.pl - most of Test::More functionality without the fuss 322 323 324# NOTE: 325# 326# Increment ($x++) has a certain amount of cleverness for things like 327# 328# $x = 'zz'; 329# $x++; # $x eq 'aaa'; 330# 331# stands more chance of breaking than just a simple 332# 333# $x = $x + 1 334# 335# In this file, we use the latter "Baby Perl" approach, and increment 336# will be worked over by t/op/inc.t 337 338$Level = 1; 339my $test = 1; 340my $planned; 341my $noplan; 342my $Perl; # Safer version of $^X set by which_perl() 343 344$TODO = 0; 345$NO_ENDING = 0; 346 347# Use this instead of print to avoid interference while testing globals. 348sub _print { 349 local($\, $", $,) = (undef, ' ', ''); 350 print STDOUT @_; 351} 352 353sub _print_stderr { 354 local($\, $", $,) = (undef, ' ', ''); 355 print STDERR @_; 356} 357 358sub plan { 359 my $n; 360 if (@_ == 1) { 361 $n = shift; 362 if ($n eq 'no_plan') { 363 undef $n; 364 $noplan = 1; 365 } 366 } else { 367 my %plan = @_; 368 $n = $plan{tests}; 369 } 370 _print "1..$n\n" unless $noplan; 371 $planned = $n; 372} 373 374END { 375 my $ran = $test - 1; 376 if (!$NO_ENDING) { 377 if (defined $planned && $planned != $ran) { 378 _print_stderr 379 "# Looks like you planned $planned tests but ran $ran.\n"; 380 } elsif ($noplan) { 381 _print "1..$ran\n"; 382 } 383 } 384} 385 386# Use this instead of "print STDERR" when outputing failure diagnostic 387# messages 388sub _diag { 389 return unless @_; 390 my @mess = map { /^#/ ? "$_\n" : "# $_\n" } 391 map { split /\n/ } @_; 392 $TODO ? _print(@mess) : _print_stderr(@mess); 393} 394 395sub diag { 396 _diag(@_); 397} 398 399sub skip_all { 400 if (@_) { 401 _print "1..0 # Skip @_\n"; 402 } else { 403 _print "1..0\n"; 404 } 405 exit(0); 406} 407 408sub _ok { 409 my ($pass, $where, $name, @mess) = @_; 410 # Do not try to microoptimize by factoring out the "not ". 411 # VMS will avenge. 412 my $out; 413 if ($name) { 414 # escape out '#' or it will interfere with '# skip' and such 415 $name =~ s/#/\\#/g; 416 $out = $pass ? "ok $test - $name" : "not ok $test - $name"; 417 } else { 418 $out = $pass ? "ok $test" : "not ok $test"; 419 } 420 421 $out .= " # TODO $TODO" if $TODO; 422 _print "$out\n"; 423 424 unless ($pass) { 425 _diag "# Failed $where\n"; 426 } 427 428 # Ensure that the message is properly escaped. 429 _diag @mess; 430 431 $test = $test + 1; # don't use ++ 432 433 return $pass; 434} 435 436sub _where { 437 my @caller = caller($Level); 438 return "at $caller[1] line $caller[2]"; 439} 440 441# DON'T use this for matches. Use like() instead. 442sub ok ($@) { 443 my ($pass, $name, @mess) = @_; 444 _ok($pass, _where(), $name, @mess); 445} 446 447sub _q { 448 my $x = shift; 449 return 'undef' unless defined $x; 450 my $q = $x; 451 $q =~ s/\\/\\\\/g; 452 $q =~ s/'/\\'/g; 453 return "'$q'"; 454} 455 456sub _qq { 457 my $x = shift; 458 return defined $x ? '"' . display ($x) . '"' : 'undef'; 459}; 460 461# keys are the codes \n etc map to, values are 2 char strings such as \n 462my %backslash_escape; 463foreach my $x (split //, 'nrtfa\\\'"') { 464 $backslash_escape{ord eval "\"\\$x\""} = "\\$x"; 465} 466# A way to display scalars containing control characters and Unicode. 467# Trying to avoid setting $_, or relying on local $_ to work. 468sub display { 469 my @result; 470 foreach my $x (@_) { 471 if (defined $x and not ref $x) { 472 my $y = ''; 473 foreach my $c (unpack("U*", $x)) { 474 if ($c > 255) { 475 $y .= sprintf "\\x{%x}", $c; 476 } elsif ($backslash_escape{$c}) { 477 $y .= $backslash_escape{$c}; 478 } else { 479 my $z = chr $c; # Maybe we can get away with a literal... 480 $z = sprintf "\\%03o", $c if $z =~ /[[:^print:]]/; 481 $y .= $z; 482 } 483 } 484 $x = $y; 485 } 486 return $x unless wantarray; 487 push @result, $x; 488 } 489 return @result; 490} 491 492sub is ($$@) { 493 my ($got, $expected, $name, @mess) = @_; 494 495 my $pass; 496 if( !defined $got || !defined $expected ) { 497 # undef only matches undef 498 $pass = !defined $got && !defined $expected; 499 } 500 else { 501 $pass = $got eq $expected; 502 } 503 504 unless ($pass) { 505 unshift(@mess, "# got "._q($got)."\n", 506 "# expected "._q($expected)."\n"); 507 } 508 _ok($pass, _where(), $name, @mess); 509} 510 511sub isnt ($$@) { 512 my ($got, $isnt, $name, @mess) = @_; 513 514 my $pass; 515 if( !defined $got || !defined $isnt ) { 516 # undef only matches undef 517 $pass = defined $got || defined $isnt; 518 } 519 else { 520 $pass = $got ne $isnt; 521 } 522 523 unless( $pass ) { 524 unshift(@mess, "# it should not be "._q($got)."\n", 525 "# but it is.\n"); 526 } 527 _ok($pass, _where(), $name, @mess); 528} 529 530sub cmp_ok ($$$@) { 531 my($got, $type, $expected, $name, @mess) = @_; 532 533 my $pass; 534 { 535 local $^W = 0; 536 local($@,$!); # don't interfere with $@ 537 # eval() sometimes resets $! 538 $pass = eval "\$got $type \$expected"; 539 } 540 unless ($pass) { 541 # It seems Irix long doubles can have 2147483648 and 2147483648 542 # that stringify to the same thing but are acutally numerically 543 # different. Display the numbers if $type isn't a string operator, 544 # and the numbers are stringwise the same. 545 # (all string operators have alphabetic names, so tr/a-z// is true) 546 # This will also show numbers for some uneeded cases, but will 547 # definately be helpful for things such as == and <= that fail 548 if ($got eq $expected and $type !~ tr/a-z//) { 549 unshift @mess, "# $got - $expected = " . ($got - $expected) . "\n"; 550 } 551 unshift(@mess, "# got "._q($got)."\n", 552 "# expected $type "._q($expected)."\n"); 553 } 554 _ok($pass, _where(), $name, @mess); 555} 556 557# Check that $got is within $range of $expected 558# if $range is 0, then check it's exact 559# else if $expected is 0, then $range is an absolute value 560# otherwise $range is a fractional error. 561# Here $range must be numeric, >= 0 562# Non numeric ranges might be a useful future extension. (eg %) 563sub within ($$$@) { 564 my ($got, $expected, $range, $name, @mess) = @_; 565 my $pass; 566 if (!defined $got or !defined $expected or !defined $range) { 567 # This is a fail, but doesn't need extra diagnostics 568 } elsif ($got !~ tr/0-9// or $expected !~ tr/0-9// or $range !~ tr/0-9//) { 569 # This is a fail 570 unshift @mess, "# got, expected and range must be numeric\n"; 571 } elsif ($range < 0) { 572 # This is also a fail 573 unshift @mess, "# range must not be negative\n"; 574 } elsif ($range == 0) { 575 # Within 0 is == 576 $pass = $got == $expected; 577 } elsif ($expected == 0) { 578 # If expected is 0, treat range as absolute 579 $pass = ($got <= $range) && ($got >= - $range); 580 } else { 581 my $diff = $got - $expected; 582 $pass = abs ($diff / $expected) < $range; 583 } 584 unless ($pass) { 585 if ($got eq $expected) { 586 unshift @mess, "# $got - $expected = " . ($got - $expected) . "\n"; 587 } 588 unshift@mess, "# got "._q($got)."\n", 589 "# expected "._q($expected)." (within "._q($range).")\n"; 590 } 591 _ok($pass, _where(), $name, @mess); 592} 593 594# Note: this isn't quite as fancy as Test::More::like(). 595 596sub like ($$@) { like_yn (0,@_) }; # 0 for - 597sub unlike ($$@) { like_yn (1,@_) }; # 1 for un- 598 599sub like_yn ($$$@) { 600 my ($flip, $got, $expected, $name, @mess) = @_; 601 my $pass; 602 $pass = $got =~ /$expected/ if !$flip; 603 $pass = $got !~ /$expected/ if $flip; 604 unless ($pass) { 605 unshift(@mess, "# got '$got'\n", 606 $flip 607 ? "# expected !~ /$expected/\n" : "# expected /$expected/\n"); 608 } 609 local $Level = $Level + 1; 610 _ok($pass, _where(), $name, @mess); 611} 612 613sub pass { 614 _ok(1, '', @_); 615} 616 617sub fail { 618 _ok(0, _where(), @_); 619} 620 621sub curr_test { 622 $test = shift if @_; 623 return $test; 624} 625 626sub next_test { 627 my $retval = $test; 628 $test = $test + 1; # don't use ++ 629 $retval; 630} 631 632# Note: can't pass multipart messages since we try to 633# be compatible with Test::More::skip(). 634sub skip { 635 my $why = shift; 636 my $n = @_ ? shift : 1; 637 for (1..$n) { 638 _print "ok $test # skip $why\n"; 639 $test = $test + 1; 640 } 641 local $^W = 0; 642 last SKIP; 643} 644 645sub todo_skip { 646 my $why = shift; 647 my $n = @_ ? shift : 1; 648 649 for (1..$n) { 650 _print "not ok $test # TODO & SKIP $why\n"; 651 $test = $test + 1; 652 } 653 local $^W = 0; 654 last TODO; 655} 656 657sub eq_array { 658 my ($ra, $rb) = @_; 659 return 0 unless $#$ra == $#$rb; 660 for my $i (0..$#$ra) { 661 next if !defined $ra->[$i] && !defined $rb->[$i]; 662 return 0 if !defined $ra->[$i]; 663 return 0 if !defined $rb->[$i]; 664 return 0 unless $ra->[$i] eq $rb->[$i]; 665 } 666 return 1; 667} 668 669sub eq_hash { 670 my ($orig, $suspect) = @_; 671 my $fail; 672 while (my ($key, $value) = each %$suspect) { 673 # Force a hash recompute if this perl's internals can cache the hash key. 674 $key = "" . $key; 675 if (exists $orig->{$key}) { 676 if ($orig->{$key} ne $value) { 677 _print "# key ", _qq($key), " was ", _qq($orig->{$key}), 678 " now ", _qq($value), "\n"; 679 $fail = 1; 680 } 681 } else { 682 _print "# key ", _qq($key), " is ", _qq($value), 683 ", not in original.\n"; 684 $fail = 1; 685 } 686 } 687 foreach (keys %$orig) { 688 # Force a hash recompute if this perl's internals can cache the hash key. 689 $_ = "" . $_; 690 next if (exists $suspect->{$_}); 691 _print "# key ", _qq($_), " was ", _qq($orig->{$_}), " now missing.\n"; 692 $fail = 1; 693 } 694 !$fail; 695} 696 697sub require_ok ($) { 698 my ($require) = @_; 699 eval <<REQUIRE_OK; 700require $require; 701REQUIRE_OK 702 _ok(!$@, _where(), "require $require"); 703} 704 705sub use_ok ($) { 706 my ($use) = @_; 707 eval <<USE_OK; 708use $use; 709USE_OK 710 _ok(!$@, _where(), "use $use"); 711} 712 713# runperl - Runs a separate perl interpreter. 714# Arguments : 715# switches => [ command-line switches ] 716# nolib => 1 # don't use -I../lib (included by default) 717# prog => one-liner (avoid quotes) 718# progs => [ multi-liner (avoid quotes) ] 719# progfile => perl script 720# stdin => string to feed the stdin 721# stderr => redirect stderr to stdout 722# args => [ command-line arguments to the perl program ] 723# verbose => print the command line 724 725my $is_mswin = $^O eq 'MSWin32'; 726my $is_netware = $^O eq 'NetWare'; 727my $is_macos = $^O eq 'MacOS'; 728my $is_vms = $^O eq 'VMS'; 729my $is_cygwin = $^O eq 'cygwin'; 730 731sub _quote_args { 732 my ($runperl, $args) = @_; 733 734 foreach (@$args) { 735 # In VMS protect with doublequotes because otherwise 736 # DCL will lowercase -- unless already doublequoted. 737 $_ = q(").$_.q(") if $is_vms && !/^\"/ && length($_) > 0; 738 $$runperl .= ' ' . $_; 739 } 740} 741 742sub _create_runperl { # Create the string to qx in runperl(). 743 my %args = @_; 744 my $runperl = which_perl(); 745 if ($runperl =~ m/\s/) { 746 $runperl = qq{"$runperl"}; 747 } 748 #- this allows, for example, to set PERL_RUNPERL_DEBUG=/usr/bin/valgrind 749 if ($ENV{PERL_RUNPERL_DEBUG}) { 750 $runperl = "$ENV{PERL_RUNPERL_DEBUG} $runperl"; 751 } 752 unless ($args{nolib}) { 753 if ($is_macos) { 754 $runperl .= ' -I::lib'; 755 # Use UNIX style error messages instead of MPW style. 756 $runperl .= ' -MMac::err=unix' if $args{stderr}; 757 } 758 else { 759 $runperl .= ' "-I../lib"'; # doublequotes because of VMS 760 } 761 } 762 if ($args{switches}) { 763 local $Level = 2; 764 die "test.pl:runperl(): 'switches' must be an ARRAYREF " . _where() 765 unless ref $args{switches} eq "ARRAY"; 766 _quote_args(\$runperl, $args{switches}); 767 } 768 if (defined $args{prog}) { 769 die "test.pl:runperl(): both 'prog' and 'progs' cannot be used " . _where() 770 if defined $args{progs}; 771 $args{progs} = [$args{prog}] 772 } 773 if (defined $args{progs}) { 774 die "test.pl:runperl(): 'progs' must be an ARRAYREF " . _where() 775 unless ref $args{progs} eq "ARRAY"; 776 foreach my $prog (@{$args{progs}}) { 777 if ($is_mswin || $is_netware || $is_vms) { 778 $runperl .= qq ( -e "$prog" ); 779 } 780 else { 781 $runperl .= qq ( -e '$prog' ); 782 } 783 } 784 } elsif (defined $args{progfile}) { 785 $runperl .= qq( "$args{progfile}"); 786 } else { 787 # You probaby didn't want to be sucking in from the upstream stdin 788 die "test.pl:runperl(): none of prog, progs, progfile, args, " 789 . " switches or stdin specified" 790 unless defined $args{args} or defined $args{switches} 791 or defined $args{stdin}; 792 } 793 if (defined $args{stdin}) { 794 # so we don't try to put literal newlines and crs onto the 795 # command line. 796 $args{stdin} =~ s/\n/\\n/g; 797 $args{stdin} =~ s/\r/\\r/g; 798 799 if ($is_mswin || $is_netware || $is_vms) { 800 $runperl = qq{$Perl -e "print qq(} . 801 $args{stdin} . q{)" | } . $runperl; 802 } 803 elsif ($is_macos) { 804 # MacOS can only do two processes under MPW at once; 805 # the test itself is one; we can't do two more, so 806 # write to temp file 807 my $stdin = qq{$Perl -e 'print qq(} . $args{stdin} . qq{)' > teststdin; }; 808 if ($args{verbose}) { 809 my $stdindisplay = $stdin; 810 $stdindisplay =~ s/\n/\n\#/g; 811 _print_stderr "# $stdindisplay\n"; 812 } 813 `$stdin`; 814 $runperl .= q{ < teststdin }; 815 } 816 else { 817 $runperl = qq{$Perl -e 'print qq(} . 818 $args{stdin} . q{)' | } . $runperl; 819 } 820 } 821 if (defined $args{args}) { 822 _quote_args(\$runperl, $args{args}); 823 } 824 $runperl .= ' 2>&1' if $args{stderr} && !$is_macos; 825 $runperl .= " \xB3 Dev:Null" if !$args{stderr} && $is_macos; 826 if ($args{verbose}) { 827 my $runperldisplay = $runperl; 828 $runperldisplay =~ s/\n/\n\#/g; 829 _print_stderr "# $runperldisplay\n"; 830 } 831 return $runperl; 832} 833 834sub runperl { 835 die "test.pl:runperl() does not take a hashref" 836 if ref $_[0] and ref $_[0] eq 'HASH'; 837 my $runperl = &_create_runperl; 838 my $result; 839 840 my $tainted = ${^TAINT}; 841 my %args = @_; 842 exists $args{switches} && grep m/^-T$/, @{$args{switches}} and $tainted = $tainted + 1; 843 844 if ($tainted) { 845 # We will assume that if you're running under -T, you really mean to 846 # run a fresh perl, so we'll brute force launder everything for you 847 my $sep; 848 849 if (! eval 'require Config; 1') { 850 warn "test.pl had problems loading Config: $@"; 851 $sep = ':'; 852 } else { 853 $sep = $Config::Config{path_sep}; 854 } 855 856 my @keys = grep {exists $ENV{$_}} qw(CDPATH IFS ENV BASH_ENV); 857 local @ENV{@keys} = (); 858 # Untaint, plus take out . and empty string: 859 local $ENV{'DCL$PATH'} = $1 if $is_vms && ($ENV{'DCL$PATH'} =~ /(.*)/s); 860 $ENV{PATH} =~ /(.*)/s; 861 local $ENV{PATH} = 862 join $sep, grep { $_ ne "" and $_ ne "." and -d $_ and 863 ($is_mswin or $is_vms or !(stat && (stat _)[2]&0022)) } 864 split quotemeta ($sep), $1; 865 $ENV{PATH} .= "$sep/bin" if $is_cygwin; # Must have /bin under Cygwin 866 867 $runperl =~ /(.*)/s; 868 $runperl = $1; 869 870 $result = `$runperl`; 871 } else { 872 $result = `$runperl`; 873 } 874 $result =~ s/\n\n/\n/ if $is_vms; # XXX pipes sometimes double these 875 return $result; 876} 877 878*run_perl = \&runperl; # Nice alias. 879 880sub DIE { 881 _print_stderr "# @_\n"; 882 exit 1; 883} 884 885# A somewhat safer version of the sometimes wrong $^X. 886sub which_perl { 887 unless (defined $Perl) { 888 $Perl = $^X; 889 890 # VMS should have 'perl' aliased properly 891 return $Perl if $^O eq 'VMS'; 892 893 my $exe; 894 if (! eval 'require Config; 1') { 895 warn "test.pl had problems loading Config: $@"; 896 $exe = ''; 897 } else { 898 $exe = $Config::Config{_exe}; 899 } 900 $exe = '' unless defined $exe; 901 902 # This doesn't absolutize the path: beware of future chdirs(). 903 # We could do File::Spec->abs2rel() but that does getcwd()s, 904 # which is a bit heavyweight to do here. 905 906 if ($Perl =~ /^perl\Q$exe\E$/i) { 907 my $perl = "perl$exe"; 908 if (! eval 'require File::Spec; 1') { 909 warn "test.pl had problems loading File::Spec: $@"; 910 $Perl = "./$perl"; 911 } else { 912 $Perl = File::Spec->catfile(File::Spec->curdir(), $perl); 913 } 914 } 915 916 # Build up the name of the executable file from the name of 917 # the command. 918 919 if ($Perl !~ /\Q$exe\E$/i) { 920 $Perl .= $exe; 921 } 922 923 warn "which_perl: cannot find $Perl from $^X" unless -f $Perl; 924 925 # For subcommands to use. 926 $ENV{PERLEXE} = $Perl; 927 } 928 return $Perl; 929} 930 931sub unlink_all { 932 foreach my $file (@_) { 933 1 while unlink $file; 934 _print_stderr "# Couldn't unlink '$file': $!\n" if -f $file; 935 } 936} 937 938my %tmpfiles; 939END { unlink_all keys %tmpfiles } 940 941# A regexp that matches the tempfile names 942$::tempfile_regexp = 'tmp\d+[A-Z][A-Z]?'; 943 944# Avoid ++, avoid ranges, avoid split // 945my @letters = qw(A B C D E F G H I J K L M N O P Q R S T U V W X Y Z); 946sub tempfile { 947 my $count = 0; 948 do { 949 my $temp = $count; 950 my $try = "tmp$$"; 951 do { 952 $try .= $letters[$temp % 26]; 953 $temp = int ($temp / 26); 954 } while $temp; 955 # Need to note all the file names we allocated, as a second request may 956 # come before the first is created. 957 if (!-e $try && !$tmpfiles{$try}) { 958 # We have a winner 959 $tmpfiles{$try}++; 960 return $try; 961 } 962 $count = $count + 1; 963 } while $count < 26 * 26; 964 die "Can't find temporary file name starting 'tmp$$'"; 965} 966 967# This is the temporary file for _fresh_perl 968my $tmpfile = tempfile(); 969 970# 971# _fresh_perl 972# 973# The $resolve must be a subref that tests the first argument 974# for success, or returns the definition of success (e.g. the 975# expected scalar) if given no arguments. 976# 977 978sub _fresh_perl { 979 my($prog, $resolve, $runperl_args, $name) = @_; 980 981 $runperl_args ||= {}; 982 $runperl_args->{progfile} = $tmpfile; 983 $runperl_args->{stderr} = 1; 984 985 open TEST, ">$tmpfile" or die "Cannot open $tmpfile: $!"; 986 987 # VMS adjustments 988 if( $^O eq 'VMS' ) { 989 $prog =~ s#/dev/null#NL:#; 990 991 # VMS file locking 992 $prog =~ s{if \(-e _ and -f _ and -r _\)} 993 {if (-e _ and -f _)} 994 } 995 996 print TEST $prog; 997 close TEST or die "Cannot close $tmpfile: $!"; 998 999 my $results = runperl(%$runperl_args); 1000 my $status = $?; 1001 1002 # Clean up the results into something a bit more predictable. 1003 $results =~ s/\n+$//; 1004 $results =~ s/at\s+$::tempfile_regexp\s+line/at - line/g; 1005 $results =~ s/of\s+$::tempfile_regexp\s+aborted/of - aborted/g; 1006 1007 # bison says 'parse error' instead of 'syntax error', 1008 # various yaccs may or may not capitalize 'syntax'. 1009 $results =~ s/^(syntax|parse) error/syntax error/mig; 1010 1011 if ($^O eq 'VMS') { 1012 # some tests will trigger VMS messages that won't be expected 1013 $results =~ s/\n?%[A-Z]+-[SIWEF]-[A-Z]+,.*//; 1014 1015 # pipes double these sometimes 1016 $results =~ s/\n\n/\n/g; 1017 } 1018 1019 my $pass = $resolve->($results); 1020 unless ($pass) { 1021 _diag "# PROG: \n$prog\n"; 1022 _diag "# EXPECTED:\n", $resolve->(), "\n"; 1023 _diag "# GOT:\n$results\n"; 1024 _diag "# STATUS: $status\n"; 1025 } 1026 1027 # Use the first line of the program as a name if none was given 1028 unless( $name ) { 1029 ($first_line, $name) = $prog =~ /^((.{1,50}).*)/; 1030 $name .= '...' if length $first_line > length $name; 1031 } 1032 1033 _ok($pass, _where(), "fresh_perl - $name"); 1034} 1035 1036# 1037# fresh_perl_is 1038# 1039# Combination of run_perl() and is(). 1040# 1041 1042sub fresh_perl_is { 1043 my($prog, $expected, $runperl_args, $name) = @_; 1044 local $Level = 2; 1045 _fresh_perl($prog, 1046 sub { @_ ? $_[0] eq $expected : $expected }, 1047 $runperl_args, $name); 1048} 1049 1050# 1051# fresh_perl_like 1052# 1053# Combination of run_perl() and like(). 1054# 1055 1056sub fresh_perl_like { 1057 my($prog, $expected, $runperl_args, $name) = @_; 1058 local $Level = 2; 1059 _fresh_perl($prog, 1060 sub { @_ ? 1061 $_[0] =~ (ref $expected ? $expected : /$expected/) : 1062 $expected }, 1063 $runperl_args, $name); 1064} 1065 1066sub can_ok ($@) { 1067 my($proto, @methods) = @_; 1068 my $class = ref $proto || $proto; 1069 1070 unless( @methods ) { 1071 return _ok( 0, _where(), "$class->can(...)" ); 1072 } 1073 1074 my @nok = (); 1075 foreach my $method (@methods) { 1076 local($!, $@); # don't interfere with caller's $@ 1077 # eval sometimes resets $! 1078 eval { $proto->can($method) } || push @nok, $method; 1079 } 1080 1081 my $name; 1082 $name = @methods == 1 ? "$class->can('$methods[0]')" 1083 : "$class->can(...)"; 1084 1085 _ok( !@nok, _where(), $name ); 1086} 1087 1088sub isa_ok ($$;$) { 1089 my($object, $class, $obj_name) = @_; 1090 1091 my $diag; 1092 $obj_name = 'The object' unless defined $obj_name; 1093 my $name = "$obj_name isa $class"; 1094 if( !defined $object ) { 1095 $diag = "$obj_name isn't defined"; 1096 } 1097 elsif( !ref $object ) { 1098 $diag = "$obj_name isn't a reference"; 1099 } 1100 else { 1101 # We can't use UNIVERSAL::isa because we want to honor isa() overrides 1102 local($@, $!); # eval sometimes resets $! 1103 my $rslt = eval { $object->isa($class) }; 1104 if( $@ ) { 1105 if( $@ =~ /^Can't call method "isa" on unblessed reference/ ) { 1106 if( !UNIVERSAL::isa($object, $class) ) { 1107 my $ref = ref $object; 1108 $diag = "$obj_name isn't a '$class' it's a '$ref'"; 1109 } 1110 } else { 1111 die <<WHOA; 1112WHOA! I tried to call ->isa on your object and got some weird error. 1113This should never happen. Please contact the author immediately. 1114Here's the error. 1115$@ 1116WHOA 1117 } 1118 } 1119 elsif( !$rslt ) { 1120 my $ref = ref $object; 1121 $diag = "$obj_name isn't a '$class' it's a '$ref'"; 1122 } 1123 } 1124 1125 _ok( !$diag, _where(), $name ); 1126} 1127 1128# Set a watchdog to timeout the entire test file 1129# NOTE: If the test file uses 'threads', then call the watchdog() function 1130# _AFTER_ the 'threads' module is loaded. 1131sub watchdog ($) 1132{ 1133 my $timeout = shift; 1134 my $timeout_msg = 'Test process timed out - terminating'; 1135 1136 my $pid_to_kill = $$; # PID for this process 1137 1138 # Don't use a watchdog process if 'threads' is loaded - 1139 # use a watchdog thread instead 1140 if (! $threads::threads) { 1141 1142 # On Windows and VMS, try launching a watchdog process 1143 # using system(1, ...) (see perlport.pod) 1144 if (($^O eq 'MSWin32') || ($^O eq 'VMS')) { 1145 # On Windows, try to get the 'real' PID 1146 if ($^O eq 'MSWin32') { 1147 eval { require Win32; }; 1148 if (defined(&Win32::GetCurrentProcessId)) { 1149 $pid_to_kill = Win32::GetCurrentProcessId(); 1150 } 1151 } 1152 1153 # If we still have a fake PID, we can't use this method at all 1154 return if ($pid_to_kill <= 0); 1155 1156 # Launch watchdog process 1157 my $watchdog; 1158 eval { 1159 local $SIG{'__WARN__'} = sub { 1160 _diag("Watchdog warning: $_[0]"); 1161 }; 1162 my $sig = $^O eq 'VMS' ? 'TERM' : 'KILL'; 1163 $watchdog = system(1, which_perl(), '-e', 1164 "sleep($timeout);" . 1165 "warn('# $timeout_msg\n');" . 1166 "kill($sig, $pid_to_kill);"); 1167 }; 1168 if ($@ || ($watchdog <= 0)) { 1169 _diag('Failed to start watchdog'); 1170 _diag($@) if $@; 1171 undef($watchdog); 1172 return; 1173 } 1174 1175 # Add END block to parent to terminate and 1176 # clean up watchdog process 1177 eval "END { local \$! = 0; local \$? = 0; 1178 wait() if kill('KILL', $watchdog); };"; 1179 return; 1180 } 1181 1182 # Try using fork() to generate a watchdog process 1183 my $watchdog; 1184 eval { $watchdog = fork() }; 1185 if (defined($watchdog)) { 1186 if ($watchdog) { # Parent process 1187 # Add END block to parent to terminate and 1188 # clean up watchdog process 1189 eval "END { local \$! = 0; local \$? = 0; 1190 wait() if kill('KILL', $watchdog); };"; 1191 return; 1192 } 1193 1194 ### Watchdog process code 1195 1196 # Load POSIX if available 1197 eval { require POSIX; }; 1198 1199 # Execute the timeout 1200 sleep($timeout - 2) if ($timeout > 2); # Workaround for perlbug #49073 1201 sleep(2); 1202 1203 # Kill test process if still running 1204 if (kill(0, $pid_to_kill)) { 1205 _diag($timeout_msg); 1206 kill('KILL', $pid_to_kill); 1207 } 1208 1209 # Don't execute END block (added at beginning of this file) 1210 $NO_ENDING = 1; 1211 1212 # Terminate ourself (i.e., the watchdog) 1213 POSIX::_exit(1) if (defined(&POSIX::_exit)); 1214 exit(1); 1215 } 1216 1217 # fork() failed - fall through and try using a thread 1218 } 1219 1220 # Use a watchdog thread because either 'threads' is loaded, 1221 # or fork() failed 1222 if (eval 'require threads; 1') { 1223 threads->create(sub { 1224 # Load POSIX if available 1225 eval { require POSIX; }; 1226 1227 # Execute the timeout 1228 my $time_left = $timeout; 1229 do { 1230 $time_left -= sleep($time_left); 1231 } while ($time_left > 0); 1232 1233 # Kill the parent (and ourself) 1234 select(STDERR); $| = 1; 1235 _diag($timeout_msg); 1236 POSIX::_exit(1) if (defined(&POSIX::_exit)); 1237 my $sig = $^O eq 'VMS' ? 'TERM' : 'KILL'; 1238 kill($sig, $pid_to_kill); 1239 })->detach(); 1240 return; 1241 } 1242 1243 # If everything above fails, then just use an alarm timeout 1244 if (eval { alarm($timeout); 1; }) { 1245 # Load POSIX if available 1246 eval { require POSIX; }; 1247 1248 # Alarm handler will do the actual 'killing' 1249 $SIG{'ALRM'} = sub { 1250 select(STDERR); $| = 1; 1251 _diag($timeout_msg); 1252 POSIX::_exit(1) if (defined(&POSIX::_exit)); 1253 my $sig = $^O eq 'VMS' ? 'TERM' : 'KILL'; 1254 kill($sig, $pid_to_kill); 1255 }; 1256 } 1257} 1258 12591; 1260-- threads.h -- 1261#ifndef _THREADS_H_ 1262#define _THREADS_H_ 1263 1264/* Needed for 5.8.0 */ 1265#ifndef CLONEf_JOIN_IN 1266# define CLONEf_JOIN_IN 8 1267#endif 1268#ifndef SAVEBOOL 1269# define SAVEBOOL(a) 1270#endif 1271 1272/* Added in 5.11.x */ 1273#ifndef G_WANT 1274# define G_WANT (128|1) 1275#endif 1276 1277/* Added in 5.24.x */ 1278#ifndef PERL_TSA_RELEASE 1279# define PERL_TSA_RELEASE(x) 1280#endif 1281#ifndef PERL_TSA_EXCLUDES 1282# define PERL_TSA_EXCLUDES(x) 1283#endif 1284#ifndef CLANG_DIAG_IGNORE 1285# define CLANG_DIAG_IGNORE(x) 1286#endif 1287#ifndef CLANG_DIAG_RESTORE 1288# define CLANG_DIAG_RESTORE 1289#endif 1290 1291/* Added in 5.38 */ 1292#ifndef PERL_SRAND_OVERRIDE_NEXT_PARENT 1293# define PERL_SRAND_OVERRIDE_NEXT_PARENT() 1294#endif 1295 1296#endif 1297-- shared.h -- 1298#ifndef _SHARED_H_ 1299#define _SHARED_H_ 1300 1301#include "ppport.h" 1302 1303#ifndef HvNAME_get 1304# define HvNAME_get(hv) (0 + ((XPVHV*)SvANY(hv))->xhv_name) 1305#endif 1306 1307#endif 1308