This is a live mirror of the Perl 5 development currently hosted at https://github.com/perl/perl5
Most magic.t tests can actually run on VMS.
[perl5.git] / t / op / magic.t
index 7e8ab8c..03487b0 100644 (file)
@@ -4,15 +4,49 @@ BEGIN {
     $| = 1;
     chdir 't' if -d 't';
     @INC = '../lib';
+    require './test.pl';
+    plan (tests => 171);
+}
+
+# Test that defined() returns true for magic variables created on the fly,
+# even before they have been created.
+# This must come first, even before turning on warnings or setting up
+# $SIG{__WARN__}, to avoid invalidating the tests.  warnings.pm currently
+# does not mention any special variables, but that could easily change.
+BEGIN {
+    # not available in miniperl
+    my %non_mini = map { $_ => 1 } qw(+ - [);
+    for (qw(
+       SIG ^OPEN ^TAINT ^UNICODE ^UTF8LOCALE ^WARNING_BITS 1 2 3 4 5 6 7 8
+       9 42 & ` ' : ? ! _ - [ ^ ~ = % . ( ) < > \ / $ | + ; ] ^A ^C ^D
+       ^E ^F ^H ^I ^L ^N ^O ^P ^S ^T ^V ^W ^UTF8CACHE ::12345 main::98732
+    )) {
+       my $v = $_;
+       # avoid using any global vars here:
+       if ($v =~ s/^\^(?=.)//) {
+           for(substr $v, 0, 1) {
+               $_ = chr ord() - 64;
+           }
+       }
+       SKIP:
+       {
+           skip_if_miniperl("the module for *$_ may not be available in "
+                            . "miniperl", 1) if $non_mini{$_};
+           ok defined *$v, "*$_ appears to be defined at the outset";
+       }
+    }
+}
+
+# This must be in a separate BEGIN block, as the mere mention of ${^TAINT}
+# will invalidate the test for it.
+BEGIN {
     $ENV{PATH} = '/bin' if ${^TAINT};
     $SIG{__WARN__} = sub { die "Dying on warning: ", @_ };
-    require './test.pl';
 }
 
 use warnings;
 use Config;
 
-plan (tests => 85);
 
 $Is_MSWin32  = $^O eq 'MSWin32';
 $Is_NetWare  = $^O eq 'NetWare';
@@ -21,7 +55,6 @@ $Is_Dos      = $^O eq 'dos';
 $Is_os2      = $^O eq 'os2';
 $Is_Cygwin   = $^O eq 'cygwin';
 $Is_MPE      = $^O eq 'mpeix';         
-$Is_miniperl = $ENV{PERL_CORE_MINITEST};
 $Is_BeOS     = $^O eq 'beos';
 
 $PERL = $ENV{PERL}
@@ -30,9 +63,25 @@ $PERL = $ENV{PERL}
        $Is_MSWin32            ? '.\perl' :
        './perl');
 
+sub env_is {
+    my ($key, $val, $desc) = @_;
+    if ($Is_MSWin32) {
+        # cmd.exe will echo 'variable=value' but 4nt will echo just the value
+        # -- Nikola Knezevic
+        like `set $key`, qr/^(?:\Q$key\E=)?\Q$val\E$/, $desc;
+    } elsif ($Is_VMS) {
+        is `write sys\$output f\$trnlnm("\Q$key\E")`, "$val\n", $desc;
+    } else {
+        is `echo \$\Q$key\E`, "$val\n", $desc;
+    }
+}
+
 END {
     # On VMS, environment variable changes are peristent after perl exits
-    delete $ENV{'FOO'} if $Is_VMS;
+    if ($Is_VMS) {
+        delete $ENV{'FOO'};
+        delete $ENV{'__NoNeSuCh'};
+    }
 }
 
 eval '$ENV{"FOO"} = "hi there";';      # check that ENV is inited inside eval
@@ -42,7 +91,7 @@ if ($Is_MSWin32)  { like `set FOO`, qr/^(?:FOO=)?hi there$/; }
 elsif ($Is_VMS)   { is `write sys\$output f\$trnlnm("FOO")`, "hi there\n"; }
 else              { is `echo \$FOO`, "hi there\n"; }
 
-unlink 'ajslkdfpqjsjfk';
+unlink_all 'ajslkdfpqjsjfk';
 $! = 0;
 open(FOO,'ajslkdfpqjsjfk');
 isnt($!, 0);
@@ -56,22 +105,28 @@ SKIP: {
   # We use a pipe rather than system() because the VMS command buffer
   # would overflow with a command that long.
 
+    # For easy interpolation of test numbers:
+    $next_test = curr_test() - 1;
+    sub TIEARRAY {bless[]}
+    sub FETCH { $next_test + pop }
+    tie my @tn, __PACKAGE__;
+
     open( CMDPIPE, "| $PERL");
 
-    print CMDPIPE <<'END';
+    print CMDPIPE "\$t1 = $tn[1]; \$t2 = $tn[2];\n", <<'END';
 
     $| = 1;            # command buffering
 
-    $SIG{"INT"} = "ok3";     kill "INT",$$; sleep 1;
-    $SIG{"INT"} = "IGNORE";  kill "INT",$$; sleep 1; print "ok 4\n";
-    $SIG{"INT"} = "DEFAULT"; kill "INT",$$; sleep 1; print "not ok 4\n";
+    $SIG{"INT"} = "ok1";     kill "INT",$$; sleep 1;
+    $SIG{"INT"} = "IGNORE";  kill "INT",$$; sleep 1; print "ok $t2\n";
+    $SIG{"INT"} = "DEFAULT"; kill "INT",$$; sleep 1; print" not ok $t2\n";
 
-    sub ok3 {
+    sub ok1 {
        if (($x = pop(@_)) eq "INT") {
-           print "ok 3\n";
+           print "ok $t1\n";
        }
        else {
-           print "not ok 3 ($x @_)\n";
+           print "not ok $t1 ($x @_)\n";
        }
     }
 
@@ -80,7 +135,7 @@ END
     close CMDPIPE;
 
     open( CMDPIPE, "| $PERL");
-    print CMDPIPE <<'END';
+    print CMDPIPE "\$t3 = $tn[3];\n", <<'END';
 
     { package X;
        sub DESTROY {
@@ -92,7 +147,7 @@ END
        return sub { $x };
     }
     $| = 1;            # command buffering
-    $SIG{"INT"} = "ok5";
+    $SIG{"INT"} = "ok3";
     {
        local $SIG{"INT"}=x();
        print ""; # Needed to expose failure in 5.8.0 (why?)
@@ -100,14 +155,14 @@ END
     sleep 1;
     delete $SIG{"INT"};
     kill "INT",$$; sleep 1;
-    sub ok5 {
-       print "ok 5\n";
+    sub ok3 {
+       print "ok $t3\n";
     }
 END
     close CMDPIPE;
     $? >>= 8 if $^O eq 'VMS'; # POSIX status hiding in 2nd byte
     my $todo = ($^O eq 'os2' ? ' # TODO: EMX v0.9d_fix4 bug: wrong nibble? ' : '');
-    print $? & 0xFF ? "ok 6$todo\n" : "not ok 6$todo\n";
+    print $? & 0xFF ? "ok $tn[4]$todo\n" : "not ok $tn[4]$todo\n";
 
     open(CMDPIPE, "| $PERL");
     print CMDPIPE <<'END';
@@ -123,7 +178,7 @@ END
 END
     close CMDPIPE;
     $? >>= 8 if $^O eq 'VMS';
-    print $? ? "not ok 7\n" : "ok 7\n";
+    print $? ? "not ok $tn[5]\n" : "ok $tn[5]\n";
 
     curr_test(curr_test() + 5);
 }
@@ -141,6 +196,14 @@ is $&, 'bar';
 is $', 'baz';
 is $+, 'a';
 
+# [perl #24237]
+for (qw < ` & ' >) {
+ fresh_perl_is
+  qq < \@$_; q "fff" =~ /(?!^)./; print "[\$$_]\\n" >,
+  "[f]\n", {},
+  "referencing \@$_ before \$$_ etc. still saws off ampersands";
+}
+
 # $"
 @a = qw(foo bar baz);
 is "@a", "foo bar baz";
@@ -170,15 +233,33 @@ eval { die "foo\n" };
 is $@, "foo\n";
 
 cmp_ok($$, '>', 0);
-eval { $$++ };
-like ($@, qr/^Modification of a read-only value attempted/);
+my $pid = $$;
+eval { $$ = 42 };
+is $$, 42, '$$ can be modified';
+SKIP: {
+    skip "no fork", 1 unless $Config{d_fork};
+    (my $kidpid = open my $fh, "-|") // skip "cannot fork: $!", 1;
+    if($kidpid) { # parent
+       my $kiddollars = <$fh>;
+       close $fh or die "cannot close pipe from kid proc: $!";
+       is $kiddollars, $kidpid, '$$ is reset on fork';
+    }
+    else { # child
+       print $$;
+       $::NO_ENDING = 1; # silence "Looks like you only ran..."
+       exit;
+    }
+}
+$$ = $pid; # Tests below use $$
 
 # $^X and $0
 {
+    my $is_abs = $Config{d_procselfexe} || $Config{usekernprocpathname}
+      || $Config{usensgetexecutablepath};
     if ($^O eq 'qnx') {
        chomp($wd = `/usr/bin/fullpath -t`);
     }
-    elsif($Is_Cygwin || $Config{'d_procselfexe'}) {
+    elsif($Is_Cygwin || $is_abs) {
        # Cygwin turns the symlink into the real file
        chomp($wd = `pwd`);
        $wd =~ s#/t$##;
@@ -193,7 +274,7 @@ like ($@, qr/^Modification of a read-only value attempted/);
     else {
        $wd = '.';
     }
-    my $perl = $Is_VMS ? $^X : "$wd/perl";
+    my $perl = $Is_VMS || $is_abs ? $^X : "$wd/perl";
     my $headmaybe = '';
     my $middlemaybe = '';
     my $tailmaybe = '';
@@ -237,7 +318,7 @@ EOH
     $s1 = "\$^X is $perl, \$0 is $script\n";
     ok open(SCRIPT, ">$script") or diag "Can't write to $script: $!";
     ok print(SCRIPT $headmaybe . <<EOB . $middlemaybe . <<'EOF' . $tailmaybe) or diag $!;
-#!$wd/perl
+#!$perl
 EOB
 print "\$^X is $^X, \$0 is $0\n";
 EOF
@@ -246,7 +327,6 @@ EOF
     $_ = $Is_VMS ? `$perl $script` : `$script`;
     s/\.exe//i if $Is_Dos or $Is_Cygwin or $Is_os2;
     s{./$script}{$script} if $Is_BeOS; # revert BeOS execvp() side-effect
-    s{\bminiperl\b}{perl}; # so that test doesn't fail with miniperl
     s{is perl}{is $perl}; # for systems where $^X is only a basename
     s{\\}{/}g;
     if ($Is_MSWin32 || $Is_os2) {
@@ -264,6 +344,9 @@ EOF
        is $_, $s1;
     }
     ok unlink($script) or diag $!;
+    # CHECK
+    # Could this be replaced with:
+    # unlink_all($script);
 }
 
 # $], $^O, $^T
@@ -279,72 +362,17 @@ is $^O, $orig_osname, 'Assigning $^I does not clobber $^O';
 }
 $^O = $orig_osname;
 
-SKIP: {
-    skip("%ENV manipulations fail or aren't safe on $^O", 4)
-       if $Is_VMS || $Is_Dos;
-
- SKIP: {
-       skip("clearing \%ENV is not safe when running under valgrind")
-           if $ENV{PERL_VALGRIND};
-
-           $PATH = $ENV{PATH};
-           $PDL = $ENV{PERL_DESTRUCT_LEVEL} || 0;
-           $ENV{foo} = "bar";
-           %ENV = ();
-           $ENV{PATH} = $PATH;
-           $ENV{PERL_DESTRUCT_LEVEL} = $PDL || 0;
-           if ($Is_MSWin32) {
-               is `set foo 2>NUL`, "";
-           } else {
-               is `echo \$foo`, "\n";
-           }
-       }
-
-       $ENV{__NoNeSuCh} = "foo";
-       $0 = "bar";
-# cmd.exe will echo 'variable=value' but 4nt will echo just the value
-# -- Nikola Knezevic
-       if ($Is_MSWin32) {
-           like `set __NoNeSuCh`, qr/^(?:__NoNeSuCh=)?foo$/;
-       } else {
-           is `echo \$__NoNeSuCh`, "foo\n";
-       }
-    SKIP: {
-           skip("\$0 check only on Linux and FreeBSD", 2)
-               unless $^O =~ /^(linux|freebsd)$/
-                   && open CMDLINE, "/proc/$$/cmdline";
-
-           chomp(my $line = scalar <CMDLINE>);
-           my $me = (split /\0/, $line)[0];
-           is $me, $0, 'altering $0 is effective (testing with /proc/)';
-           close CMDLINE;
-            # perlbug #22811
-            my $mydollarzero = sub {
-              my($arg) = shift;
-              $0 = $arg if defined $arg;
-             # In FreeBSD the ps -o command= will cause
-             # an empty header line, grab only the last line.
-              my $ps = (`ps -o command= -p $$`)[-1];
-              return if $?;
-              chomp $ps;
-              printf "# 0[%s]ps[%s]\n", $0, $ps;
-              $ps;
-            };
-            my $ps = $mydollarzero->("x");
-            ok(!$ps  # we allow that something goes wrong with the ps command
-              # In Linux 2.4 we would get an exact match ($ps eq 'x') but
-              # in Linux 2.2 there seems to be something funny going on:
-              # it seems as if the original length of the argv[] would
-              # be stored in the proc struct and then used by ps(1),
-              # no matter what characters we use to pad the argv[].
-              # (And if we use \0:s, they are shown as spaces.)  Sigh.
-               || $ps =~ /^x\s*$/
-              # FreeBSD cannot get rid of both the leading "perl :"
-              # and the trailing " (perl)": some FreeBSD versions
-              # can get rid of the first one.
-              || ($^O eq 'freebsd' && $ps =~ m/^(?:perl: )?x(?: \(perl\))?$/),
-                      'altering $0 is effective (testing with `ps`)');
-       }
+{
+    #RT #72422
+    foreach my $p (0, 1) {
+       fresh_perl_is(<<"EOP", '2 4 8', undef, "test \$^P = $p");
+\$DB::single = 2;
+\$DB::trace = 4;
+\$DB::signal = 8;
+\$^P = $p;
+print "\$DB::single \$DB::trace \$DB::signal";
+EOP
+    }
 }
 
 # Check that assigning to $0 on Linux sets the process name with both
@@ -363,7 +391,7 @@ SKIP: {
 
         no warnings;
         my $res = `$cmd`;
-        skip "Couldn't shell out to `$cmd', returned code $?", 2 if $?;
+        skip "Couldn't shell out to '$cmd', returned code $?", 2 if $?;
         return $res;
     };
 
@@ -387,22 +415,8 @@ SKIP: {
     ok($ok, $warn);
 }
 
-# test case-insignificance of %ENV (these tests must be enabled only
-# when perl is compiled with -DENV_IS_CASELESS)
 SKIP: {
-    skip('no caseless %ENV support', 4) unless $Is_MSWin32 || $Is_NetWare;
-
-    %ENV = ();
-    $ENV{'Foo'} = 'bar';
-    $ENV{'fOo'} = 'baz';
-    is scalar(keys(%ENV)), 1;
-    ok exists $ENV{'FOo'};
-    is delete $ENV{'foO'}, 'baz';
-    is scalar(keys(%ENV)), 0;
-}
-
-SKIP: {
-    skip ("miniperl can't rely on loading %Errno", 2) if $Is_miniperl;
+    skip_if_miniperl("miniperl can't rely on loading %Errno", 2);
    no warnings 'void';
 
 # Make sure Errno hasn't been prematurely autoloaded
@@ -418,7 +432,7 @@ SKIP: {
 }
 
 SKIP:  {
-    skip ("miniperl can't rely on loading %Errno") if $Is_miniperl;
+    skip_if_miniperl("miniperl can't rely on loading %Errno", 2);
     # Make sure that Errno loading doesn't clobber $!
 
     undef %Errno::;
@@ -427,6 +441,36 @@ SKIP:  {
     open(FOO, "nonesuch"); # Generate ENOENT
     my %errs = %{"!"}; # Cause Errno.pm to be loaded at run-time
     ok ${"!"}{ENOENT};
+
+    # Make sure defined(*{"!"}) before %! does not stop %! from working
+    is
+      runperl(
+       prog => 'BEGIN { defined *{q-!-} } print qq-ok\n- if tied %!',
+      ),
+     "ok\n",
+     'defined *{"!"} does not stop %! from working';
+}
+
+# Check that we don't auto-load packages
+SKIP: {
+    skip "staticly linked; may be preloaded", 4 unless $Config{usedl};
+    foreach (['powie::!', 'Errno'],
+            ['powie::+', 'Tie::Hash::NamedCapture']) {
+       my ($symbol, $package) = @$_;
+       foreach my $scalar_first ('', '$$symbol;') {
+           my $desc = qq{Referencing %{"$symbol"}};
+           $desc .= qq{ after mentioning \${"$symbol"}} if $scalar_first;
+           $desc .= " doesn't load $package";
+
+           fresh_perl_is(<<"EOP", 0, {}, $desc);
+use strict qw(vars subs);
+my \$symbol = '$symbol';
+$scalar_first;
+1 if %{\$symbol};
+print scalar %${package}::;
+EOP
+       }
+    }
 }
 
 is $^S, 0;
@@ -464,28 +508,6 @@ is "@+", "10 1 6 10";
     ok $ok;
 }
 
-# Test for bug [perl #27839]
-{
-    my $x;
-    sub f {
-       "abc" =~ /(.)./;
-       $x = "@+";
-       return @+;
-    };
-    "pqrstuvwxyz" =~ /..(....)../; # prime @+ etc in this scope
-    my @y = f();
-    is $x, "@y", "return a magic array ($x) vs (@y)";
-
-    sub f2 {
-       "abc" =~ /(?<foo>.)./;
-       my @h =  %+;
-       $x = "@h";
-       return %+;
-    };
-    @y = f();
-    is $x, "@y", "return a magic hash ($x) vs (@y)";
-}
-
 # Test for bug [perl #36434]
 # Can not do this test on VMS, EPOC, and SYMBIAN according to comments
 # in mg.c/Perl_magic_clear_all_env()
@@ -539,15 +561,168 @@ foreach my $sig (qw(__DIE__ _BOGUS_HOOK KILL THIRSTY)) {
 
 }
 
-{
-    #RT #72422
-    foreach my $p (0, 1) {
-       fresh_perl_is(<<"EOP", '2 4 8', undef, "test \$^P = $p");
-\$DB::single = 2;
-\$DB::trace = 4;
-\$DB::signal = 8;
-\$^P = $p;
-print "\$DB::single \$DB::trace \$DB::signal";
-EOP
+# %+ %-
+SKIP: {
+    skip_if_miniperl("No XS in miniperl", 2);
+    # Make sure defined(*{"+"}) before %+ does not stop %+ from working
+    is
+      runperl(
+       prog => 'BEGIN { defined *{q-+-} } print qq-ok\n- if tied %+',
+      ),
+     "ok\n",
+     'defined *{"+"} does not stop %+ from working';
+    is
+      runperl(
+       prog => 'BEGIN { defined *{q=-=} } print qq-ok\n- if tied %-',
+      ),
+     "ok\n",
+     'defined *{"-"} does not stop %- from working';
+}
+
+SKIP: {
+    skip_if_miniperl("No XS in miniperl", 3);
+
+    for ( [qw( %- Tie::Hash::NamedCapture )], [qw( $[ arybase )],
+          [qw( %! Errno )] ) {
+       my ($var, $mod) = @$_;
+       my $modfile = $mod =~ s|::|/|gr . ".pm";
+       fresh_perl_is
+          qq 'sub UNIVERSAL::AUTOLOAD{}
+              $mod\::foo() if 0;
+              $var;
+              print "ok\\n" if \$INC{"$modfile"}',
+         "ok\n",
+          { switches => [ '-X' ] },
+         "$var still loads $mod when stash and UNIVERSAL::AUTOLOAD exist";
     }
 }
+
+# ^^^^^^^^^ New tests go here ^^^^^^^^^
+
+SKIP: {
+    skip("%ENV manipulations fail or aren't safe on $^O", 19)
+       if $Is_Dos;
+
+ SKIP: {
+       skip("clearing \%ENV is not safe when running under valgrind or on VMS")
+           if $ENV{PERL_VALGRIND} || $Is_VMS;
+
+           $PATH = $ENV{PATH};
+           $PDL = $ENV{PERL_DESTRUCT_LEVEL} || 0;
+           $ENV{foo} = "bar";
+           %ENV = ();
+           $ENV{PATH} = $PATH;
+           $ENV{PERL_DESTRUCT_LEVEL} = $PDL || 0;
+           if ($Is_MSWin32) {
+               is `set foo 2>NUL`, "";
+           } else {
+               is `echo \$foo`, "\n";
+           }
+       }
+
+       $ENV{__NoNeSuCh} = 'foo';
+       $0 = 'bar';
+       env_is(__NoNeSuCh => 'foo', 'setting $0 does not break %ENV');
+
+       # stringify a glob
+       $ENV{foo} = *TODO;
+       env_is(foo => '*main::TODO', 'ENV store of stringified glob');
+
+       # stringify a ref
+       my $ref = [];
+       $ENV{foo} = $ref;
+       env_is(foo => "$ref", 'ENV store of stringified ref');
+
+       # downgrade utf8 when possible
+       $bytes = "eh zero \x{A0}";
+       utf8::upgrade($chars = $bytes);
+       $forced = $ENV{foo} = $chars;
+       ok(!utf8::is_utf8($forced) && $forced eq $bytes, 'ENV store downgrades utf8 in SV');
+       env_is(foo => $bytes, 'ENV store downgrades utf8 in setenv');
+
+       # warn when downgrading utf8 is not possible
+       $chars = "X-Day \x{1998}";
+       utf8::encode($bytes = $chars);
+       {
+         my $warned = 0;
+         local $SIG{__WARN__} = sub { ++$warned if $_[0] =~ /^Wide character in setenv/; print "# @_" };
+         $forced = $ENV{foo} = $chars;
+         ok($warned == 1, 'ENV store warns about wide characters');
+       }
+       ok(!utf8::is_utf8($forced) && $forced eq $bytes, 'ENV store encodes high utf8 in SV');
+       env_is(foo => $bytes, 'ENV store encodes high utf8 in SV');
+
+       # test local $ENV{foo} on existing foo
+       {
+         local $ENV{__NoNeSuCh};
+         { local $TODO = 'exists on %ENV should reflect real env';
+           ok(!exists $ENV{__NoNeSuCh}, 'not exists $ENV{existing} during local $ENV{existing}'); }
+         env_is(__NoNeLoCaL => '');
+       }
+       ok(exists $ENV{__NoNeSuCh}, 'exists $ENV{existing} after local $ENV{existing}');
+       env_is(__NoNeSuCh => 'foo');
+
+       # test local $ENV{foo} on new foo
+       {
+         local $ENV{__NoNeLoCaL} = 'foo';
+         ok(exists $ENV{__NoNeLoCaL}, 'exists $ENV{new} during local $ENV{new}');
+         env_is(__NoNeLoCaL => 'foo');
+       }
+       ok(!exists $ENV{__NoNeLoCaL}, 'not exists $ENV{new} after local $ENV{new}');
+       env_is(__NoNeLoCaL => '');
+
+    SKIP: {
+           skip("\$0 check only on Linux and FreeBSD", 2)
+               unless $^O =~ /^(linux|freebsd)$/
+                   && open CMDLINE, "/proc/$$/cmdline";
+
+           chomp(my $line = scalar <CMDLINE>);
+           my $me = (split /\0/, $line)[0];
+           is $me, $0, 'altering $0 is effective (testing with /proc/)';
+           close CMDLINE;
+            # perlbug #22811
+            my $mydollarzero = sub {
+              my($arg) = shift;
+              $0 = $arg if defined $arg;
+             # In FreeBSD the ps -o command= will cause
+             # an empty header line, grab only the last line.
+              my $ps = (`ps -o command= -p $$`)[-1];
+              return if $?;
+              chomp $ps;
+              printf "# 0[%s]ps[%s]\n", $0, $ps;
+              $ps;
+            };
+            my $ps = $mydollarzero->("x");
+            ok(!$ps  # we allow that something goes wrong with the ps command
+              # In Linux 2.4 we would get an exact match ($ps eq 'x') but
+              # in Linux 2.2 there seems to be something funny going on:
+              # it seems as if the original length of the argv[] would
+              # be stored in the proc struct and then used by ps(1),
+              # no matter what characters we use to pad the argv[].
+              # (And if we use \0:s, they are shown as spaces.)  Sigh.
+               || $ps =~ /^x\s*$/
+              # FreeBSD cannot get rid of both the leading "perl :"
+              # and the trailing " (perl)": some FreeBSD versions
+              # can get rid of the first one.
+              || ($^O eq 'freebsd' && $ps =~ m/^(?:perl: )?x(?: \(perl\))?$/),
+                      'altering $0 is effective (testing with `ps`)');
+       }
+}
+
+# test case-insignificance of %ENV (these tests must be enabled only
+# when perl is compiled with -DENV_IS_CASELESS)
+SKIP: {
+    skip('no caseless %ENV support', 4) unless $Is_MSWin32 || $Is_NetWare;
+
+    %ENV = ();
+    $ENV{'Foo'} = 'bar';
+    $ENV{'fOo'} = 'baz';
+    is scalar(keys(%ENV)), 1;
+    ok exists $ENV{'FOo'};
+    is delete $ENV{'foO'}, 'baz';
+    is scalar(keys(%ENV)), 0;
+}
+
+__END__
+
+# Put new tests before the various ENV tests, as they blow %ENV away.