Generate the warnings masks programatically.
[p5sagit/p5-mst-13.2.git] / t / test.pl
index 179b2f1..9b896f7 100644 (file)
--- 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 <<WHOA;
+WHOA! I tried to call ->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;