X-Git-Url: http://git.shadowcat.co.uk/gitweb/gitweb.cgi?a=blobdiff_plain;f=t%2Ftest.pl;h=9b896f7341133f1a56fc218e8784d1473c36770b;hb=ac27d13b824657b726428f3a6a1d5b3a01df569e;hp=179b2f19bc9b38460224216f10a180245b76a4e4;hpb=0d65d7d555c9e685ae54e22c9f9eb33ec635ea81;p=p5sagit%2Fp5-mst-13.2.git diff --git a/t/test.pl b/t/test.pl index 179b2f1..9b896f7 100644 --- a/t/test.pl +++ b/t/test.pl @@ -1,6 +1,20 @@ # # t/test.pl - most of Test::More functionality without the fuss + + +# NOTE: +# +# Increment ($x++) has a certain amount of cleverness for things like +# +# $x = 'zz'; +# $x++; # $x eq 'aaa'; +# +# stands more chance of breaking than just a simple +# +# $x = $x + 1 # +# In this file, we use the latter "Baby Perl" approach, and increment +# will be worked over by t/op/inc.t $Level = 1; my $test = 1; @@ -10,6 +24,17 @@ my $noplan; $TODO = 0; $NO_ENDING = 0; +# Use this instead of print to avoid interference while testing globals. +sub _print { + local($\, $", $,) = (undef, ' ', ''); + print STDOUT @_; +} + +sub _print_stderr { + local($\, $", $,) = (undef, ' ', ''); + print STDERR @_; +} + sub plan { my $n; if (@_ == 1) { @@ -20,9 +45,9 @@ sub plan { } } else { my %plan = @_; - $n = $plan{tests}; + $n = $plan{tests}; } - print STDOUT "1..$n\n" unless $noplan; + _print "1..$n\n" unless $noplan; $planned = $n; } @@ -30,30 +55,34 @@ END { my $ran = $test - 1; if (!$NO_ENDING) { if (defined $planned && $planned != $ran) { - print STDERR + _print_stderr "# Looks like you planned $planned tests but ran $ran.\n"; } elsif ($noplan) { - print "1..$ran\n"; + _print "1..$ran\n"; } } } -# Use this instead of "print STDERR" when outputing failure diagnostic +# Use this instead of "print STDERR" when outputing failure diagnostic # messages sub _diag { return unless @_; - my @mess = map { /^#/ ? "$_\n" : "# $_\n" } + my @mess = map { /^#/ ? "$_\n" : "# $_\n" } map { split /\n/ } @_; - my $fh = $TODO ? *STDOUT : *STDERR; - print $fh @mess; + my $func = $TODO ? \&_print : \&_print_stderr; + $func->(@mess); + +} +sub diag { + _diag(@_); } sub skip_all { if (@_) { - print STDOUT "1..0 # Skipped: @_\n"; + _print "1..0 # Skipped: @_\n"; } else { - print STDOUT "1..0\n"; + _print "1..0\n"; } exit(0); } @@ -72,7 +101,7 @@ sub _ok { } $out .= " # TODO $TODO" if $TODO; - print STDOUT "$out\n"; + _print "$out\n"; unless ($pass) { _diag "# Failed $where\n"; @@ -81,7 +110,7 @@ sub _ok { # Ensure that the message is properly escaped. _diag @mess; - $test++; + $test = $test + 1; # don't use ++ return $pass; } @@ -256,8 +285,10 @@ sub like_yn ($$$@) { $pass = $got !~ /$expected/ if $flip; unless ($pass) { unshift(@mess, "# got '$got'\n", - "# expected /$expected/\n"); + $flip + ? "# expected !~ /$expected/\n" : "# expected /$expected/\n"); } + local $Level = $Level + 1; _ok($pass, _where(), $name, @mess); } @@ -275,7 +306,9 @@ sub curr_test { } sub next_test { - $test++; + my $retval = $test; + $test = $test + 1; # don't use ++ + $retval; } # Note: can't pass multipart messages since we try to @@ -284,8 +317,8 @@ sub skip { my $why = shift; my $n = @_ ? shift : 1; for (1..$n) { - print STDOUT "ok $test # skip: $why\n"; - $test++; + _print "ok $test # skip: $why\n"; + $test = $test + 1; } local $^W = 0; last SKIP; @@ -296,8 +329,8 @@ sub todo_skip { my $n = @_ ? shift : 1; for (1..$n) { - print STDOUT "ok $test # TODO & SKIP: $why\n"; - $test++; + _print "not ok $test # TODO & SKIP: $why\n"; + $test = $test + 1; } local $^W = 0; last TODO; @@ -307,7 +340,7 @@ sub eq_array { my ($ra, $rb) = @_; return 0 unless $#$ra == $#$rb; for my $i (0..$#$ra) { - next if !defined $ra->[$i] && !defined $rb->[$i]; + next if !defined $ra->[$i] && !defined $rb->[$i]; return 0 if !defined $ra->[$i]; return 0 if !defined $rb->[$i]; return 0 unless $ra->[$i] eq $rb->[$i]; @@ -323,12 +356,12 @@ sub eq_hash { $key = "" . $key; if (exists $orig->{$key}) { if ($orig->{$key} ne $value) { - print STDOUT "# key ", _qq($key), " was ", _qq($orig->{$key}), + _print "# key ", _qq($key), " was ", _qq($orig->{$key}), " now ", _qq($value), "\n"; $fail = 1; } } else { - print STDOUT "# key ", _qq($key), " is ", _qq($value), + _print "# key ", _qq($key), " is ", _qq($value), ", not in original.\n"; $fail = 1; } @@ -337,7 +370,7 @@ sub eq_hash { # Force a hash recompute if this perl's internals can cache the hash key. $_ = "" . $_; next if (exists $suspect->{$_}); - print STDOUT "# key ", _qq($_), " was ", _qq($orig->{$_}), " now missing.\n"; + _print "# key ", _qq($_), " was ", _qq($orig->{$_}), " now missing.\n"; $fail = 1; } !$fail; @@ -375,6 +408,7 @@ my $is_mswin = $^O eq 'MSWin32'; my $is_netware = $^O eq 'NetWare'; my $is_macos = $^O eq 'MacOS'; my $is_vms = $^O eq 'VMS'; +my $is_cygwin = $^O eq 'cygwin'; sub _quote_args { my ($runperl, $args) = @_; @@ -453,7 +487,7 @@ sub _create_runperl { # Create the string to qx in runperl(). if ($args{verbose}) { my $stdindisplay = $stdin; $stdindisplay =~ s/\n/\n\#/g; - print STDERR "# $stdindisplay\n"; + _print_stderr "# $stdindisplay\n"; } `$stdin`; $runperl .= q{ < teststdin }; @@ -471,7 +505,7 @@ sub _create_runperl { # Create the string to qx in runperl(). if ($args{verbose}) { my $runperldisplay = $runperl; $runperldisplay =~ s/\n/\n\#/g; - print STDERR "# $runperldisplay\n"; + _print_stderr "# $runperldisplay\n"; } return $runperl; } @@ -480,7 +514,43 @@ sub runperl { die "test.pl:runperl() does not take a hashref" if ref $_[0] and ref $_[0] eq 'HASH'; my $runperl = &_create_runperl; - my $result = `$runperl`; + my $result; + + my $tainted = ${^TAINT}; + my %args = @_; + exists $args{switches} && grep m/^-T$/, @{$args{switches}} and $tainted = $tainted + 1; + + if ($tainted) { + # We will assume that if you're running under -T, you really mean to + # run a fresh perl, so we'll brute force launder everything for you + my $sep; + + eval "require Config; Config->import"; + if ($@) { + warn "test.pl had problems loading Config: $@"; + $sep = ':'; + } else { + $sep = $Config{path_sep}; + } + + my @keys = grep {exists $ENV{$_}} qw(CDPATH IFS ENV BASH_ENV); + local @ENV{@keys} = (); + # Untaint, plus take out . and empty string: + local $ENV{'DCL$PATH'} = $1 if $is_vms && ($ENV{'DCL$PATH'} =~ /(.*)/s); + $ENV{PATH} =~ /(.*)/s; + local $ENV{PATH} = + join $sep, grep { $_ ne "" and $_ ne "." and -d $_ and + ($is_mswin or $is_vms or !(stat && (stat _)[2]&0022)) } + split quotemeta ($sep), $1; + $ENV{PATH} .= "$sep/bin" if $is_cygwin; # Must have /bin under Cygwin + + $runperl =~ /(.*)/s; + $runperl = $1; + + $result = `$runperl`; + } else { + $result = `$runperl`; + } $result =~ s/\n\n/\n/ if $is_vms; # XXX pipes sometimes double these return $result; } @@ -488,7 +558,7 @@ sub runperl { *run_perl = \&runperl; # Nice alias. sub DIE { - print STDERR "# @_\n"; + _print_stderr "# @_\n"; exit 1; } @@ -497,7 +567,7 @@ my $Perl; sub which_perl { unless (defined $Perl) { $Perl = $^X; - + # VMS should have 'perl' aliased properly return $Perl if $^O eq 'VMS'; @@ -510,11 +580,11 @@ sub which_perl { $exe = $Config{_exe}; } $exe = '' unless defined $exe; - + # This doesn't absolutize the path: beware of future chdirs(). # We could do File::Spec->abs2rel() but that does getcwd()s, # which is a bit heavyweight to do here. - + if ($Perl =~ /^perl\Q$exe\E$/i) { my $perl = "perl$exe"; eval "require File::Spec"; @@ -534,7 +604,7 @@ sub which_perl { } warn "which_perl: cannot find $Perl from $^X" unless -f $Perl; - + # For subcommands to use. $ENV{PERLEXE} = $Perl; } @@ -544,7 +614,7 @@ sub which_perl { sub unlink_all { foreach my $file (@_) { 1 while unlink $file; - print STDERR "# Couldn't unlink '$file': $!\n" if -f $file; + _print_stderr "# Couldn't unlink '$file': $!\n" if -f $file; } } @@ -574,7 +644,7 @@ sub _fresh_perl { if( $^O eq 'VMS' ) { $prog =~ s#/dev/null#NL:#; - # VMS file locking + # VMS file locking $prog =~ s{if \(-e _ and -f _ and -r _\)} {if (-e _ and -f _)} } @@ -649,4 +719,66 @@ sub fresh_perl_like { $runperl_args, $name); } +sub can_ok ($@) { + my($proto, @methods) = @_; + my $class = ref $proto || $proto; + + unless( @methods ) { + return _ok( 0, _where(), "$class->can(...)" ); + } + + my @nok = (); + foreach my $method (@methods) { + local($!, $@); # don't interfere with caller's $@ + # eval sometimes resets $! + eval { $proto->can($method) } || push @nok, $method; + } + + my $name; + $name = @methods == 1 ? "$class->can('$methods[0]')" + : "$class->can(...)"; + + _ok( !@nok, _where(), $name ); +} + +sub isa_ok ($$;$) { + my($object, $class, $obj_name) = @_; + + my $diag; + $obj_name = 'The object' unless defined $obj_name; + my $name = "$obj_name isa $class"; + if( !defined $object ) { + $diag = "$obj_name isn't defined"; + } + elsif( !ref $object ) { + $diag = "$obj_name isn't a reference"; + } + else { + # We can't use UNIVERSAL::isa because we want to honor isa() overrides + local($@, $!); # eval sometimes resets $! + my $rslt = eval { $object->isa($class) }; + if( $@ ) { + if( $@ =~ /^Can't call method "isa" on unblessed reference/ ) { + if( !UNIVERSAL::isa($object, $class) ) { + my $ref = ref $object; + $diag = "$obj_name isn't a '$class' it's a '$ref'"; + } + } else { + die <isa on your object and got some weird error. +This should never happen. Please contact the author immediately. +Here's the error. +$@ +WHOA + } + } + elsif( !$rslt ) { + my $ref = ref $object; + $diag = "$obj_name isn't a '$class' it's a '$ref'"; + } + } + + _ok( !$diag, _where(), $name ); +} + 1;