TEST: add util/wrap.pl and use it
[openssl.git] / util / perl / OpenSSL / Test.pm
index eb453a3290c418fb69dc7f016548f3058fde9266..bb39854a4d8302ad974641404194f27ec5f451d5 100644 (file)
@@ -1,6 +1,6 @@
-# Copyright 2016 The OpenSSL Project Authors. All Rights Reserved.
+# Copyright 2016-2019 The OpenSSL Project Authors. All Rights Reserved.
 #
 #
-# Licensed under the OpenSSL license (the "License").  You may not use
+# Licensed under the Apache License 2.0 (the "License").  You may not use
 # this file except in compliance with the License.  You can obtain a copy
 # in the file LICENSE in the source distribution or at
 # https://www.openssl.org/source/license.html
 # this file except in compliance with the License.  You can obtain a copy
 # in the file LICENSE in the source distribution or at
 # https://www.openssl.org/source/license.html
@@ -14,14 +14,16 @@ use Test::More 0.96;
 
 use Exporter;
 use vars qw($VERSION @ISA @EXPORT @EXPORT_OK %EXPORT_TAGS);
 
 use Exporter;
 use vars qw($VERSION @ISA @EXPORT @EXPORT_OK %EXPORT_TAGS);
-$VERSION = "0.8";
+$VERSION = "1.0";
 @ISA = qw(Exporter);
 @EXPORT = (@Test::More::EXPORT, qw(setup run indir cmd app fuzz test
                                    perlapp perltest subtest));
 @EXPORT_OK = (@Test::More::EXPORT_OK, qw(bldtop_dir bldtop_file
                                          srctop_dir srctop_file
 @ISA = qw(Exporter);
 @EXPORT = (@Test::More::EXPORT, qw(setup run indir cmd app fuzz test
                                    perlapp perltest subtest));
 @EXPORT_OK = (@Test::More::EXPORT_OK, qw(bldtop_dir bldtop_file
                                          srctop_dir srctop_file
-                                         data_file
-                                         pipe with cmdstr quotify));
+                                         data_file data_dir
+                                         pipe with cmdstr quotify
+                                         openssl_versions
+                                         ok_nofips is_nofips isnt_nofips));
 
 =head1 NAME
 
 
 =head1 NAME
 
@@ -64,6 +66,7 @@ use File::Spec::Functions qw/file_name_is_absolute curdir canonpath splitdir
                              rel2abs/;
 use File::Path 2.00 qw/rmtree mkpath/;
 use File::Basename;
                              rel2abs/;
 use File::Path 2.00 qw/rmtree mkpath/;
 use File::Basename;
+use Cwd qw/getcwd abs_path/;
 
 my $level = 0;
 
 
 my $level = 0;
 
@@ -93,7 +96,7 @@ my %hooks = (
     # exit_checker is used by run() directly after completion of a command.
     # it receives the exit code from that command and is expected to return
     # 1 (for success) or 0 (for failure).  This is the status value that run()
     # exit_checker is used by run() directly after completion of a command.
     # it receives the exit code from that command and is expected to return
     # 1 (for success) or 0 (for failure).  This is the status value that run()
-    # will give back (through the |statusvar| referens and as returned value
+    # will give back (through the |statusvar| reference and as returned value
     # when capture => 1 doesn't apply).
     exit_checker => sub { return shift == 0 ? 1 : 0 },
 
     # when capture => 1 doesn't apply).
     exit_checker => sub { return shift == 0 ? 1 : 0 },
 
@@ -129,6 +132,7 @@ is defined).
 sub setup {
     my $old_test_name = $test_name;
     $test_name = shift;
 sub setup {
     my $old_test_name = $test_name;
     $test_name = shift;
+    my %opts = @_;
 
     BAIL_OUT("setup() must receive a name") unless $test_name;
     warn "setup() detected test name change.  Innocuous, so we continue...\n"
 
     BAIL_OUT("setup() must receive a name") unless $test_name;
     warn "setup() detected test name change.  Innocuous, so we continue...\n"
@@ -146,6 +150,9 @@ sub setup {
     BAIL_OUT("setup() expects the file Configure in the source top directory")
         unless -f srctop_file("Configure");
 
     BAIL_OUT("setup() expects the file Configure in the source top directory")
         unless -f srctop_file("Configure");
 
+    note "The results of this test will end up in $directories{RESULTS}"
+        unless $opts{quiet};
+
     __cwd($directories{RESULTS});
 }
 
     __cwd($directories{RESULTS});
 }
 
@@ -163,16 +170,10 @@ C<indir> takes some additional options OPTS that affect the subdirectory:
 
 =item B<create =E<gt> 0|1>
 
 
 =item B<create =E<gt> 0|1>
 
-When set to 1 (or any value that perl preceives as true), the subdirectory
+When set to 1 (or any value that perl perceives as true), the subdirectory
 will be created if it doesn't already exist.  This happens before BLOCK
 is executed.
 
 will be created if it doesn't already exist.  This happens before BLOCK
 is executed.
 
-=item B<cleanup =E<gt> 0|1>
-
-When set to 1 (or any value that perl preceives as true), the subdirectory
-will be cleaned out and removed.  This happens both before and after BLOCK
-is executed.
-
 =back
 
 An example:
 =back
 
 An example:
@@ -185,7 +186,7 @@ An example:
           is($line, qr/^OpenSSL 1\./,
              "check that we're using OpenSSL 1.x.x");
       }
           is($line, qr/^OpenSSL 1\./,
              "check that we're using OpenSSL 1.x.x");
       }
-  }, create => 1, cleanup => 1;
+  }, create => 1;
 
 =back
 
 
 =back
 
@@ -203,10 +204,6 @@ sub indir {
     $codeblock->();
 
     __cwd($reverse);
     $codeblock->();
 
     __cwd($reverse);
-
-    if ($opts{cleanup}) {
-       rmtree($subdir, { safe => 0 });
-    }
 }
 
 =over 4
 }
 
 =over 4
@@ -443,16 +440,21 @@ sub run {
     die "OpenSSL::Test::run(): statusvar value not a scalar reference"
         if $opts{statusvar} && ref($opts{statusvar}) ne "SCALAR";
 
     die "OpenSSL::Test::run(): statusvar value not a scalar reference"
         if $opts{statusvar} && ref($opts{statusvar}) ne "SCALAR";
 
-    # In non-verbose, we want to shut up the command interpreter, in case
-    # it has something to complain about.  On VMS, it might complain both
-    # on stdout and stderr
+    # For some reason, program output, or even output from this function
+    # somehow isn't caught by TAP::Harness (TAP::Parser?) on VMS, so we're
+    # silencing it specifically there until further notice.
     my $save_STDOUT;
     my $save_STDERR;
     my $save_STDOUT;
     my $save_STDERR;
-    if ($ENV{HARNESS_ACTIVE} && !$ENV{HARNESS_VERBOSE}) {
-        open $save_STDOUT, '>&', \*STDOUT or die "Can't dup STDOUT: $!";
-        open $save_STDERR, '>&', \*STDERR or die "Can't dup STDERR: $!";
-        open STDOUT, ">", devnull();
-        open STDERR, ">", devnull();
+    if ($^O eq 'VMS') {
+        # In non-verbose, we want to shut up the command interpreter, in case
+        # it has something to complain about.  On VMS, it might complain both
+        # on stdout and stderr
+        if ($ENV{HARNESS_ACTIVE} && !$ENV{HARNESS_VERBOSE}) {
+            open $save_STDOUT, '>&', \*STDOUT or die "Can't dup STDOUT: $!";
+            open $save_STDERR, '>&', \*STDERR or die "Can't dup STDERR: $!";
+            open STDOUT, ">", devnull();
+            open STDERR, ">", devnull();
+        }
     }
 
     $ENV{HARNESS_OSSL_LEVEL} = $level + 1;
     }
 
     $ENV{HARNESS_OSSL_LEVEL} = $level + 1;
@@ -476,7 +478,9 @@ sub run {
        }
        close $pipe;
     } else {
        }
        close $pipe;
     } else {
+       $ENV{HARNESS_OSSL_PREFIX} = "# ";
        system("$prefix$cmd");
        system("$prefix$cmd");
+       delete $ENV{HARNESS_OSSL_PREFIX};
     }
     $e = ($? & 0x7f) ? ($? & 0x7f)|0x80 : ($? >> 8);
     $r = $hooks{exit_checker}->($e);
     }
     $e = ($? & 0x7f) ? ($? & 0x7f)|0x80 : ($? >> 8);
     $r = $hooks{exit_checker}->($e);
@@ -484,16 +488,21 @@ sub run {
         ${$opts{statusvar}} = $r;
     }
 
         ${$opts{statusvar}} = $r;
     }
 
-    if ($ENV{HARNESS_ACTIVE} && !$ENV{HARNESS_VERBOSE}) {
-        close STDOUT;
-        close STDERR;
-        open STDOUT, '>&', $save_STDOUT or die "Can't restore STDOUT: $!";
-        open STDERR, '>&', $save_STDERR or die "Can't restore STDERR: $!";
+    # Restore STDOUT / STDERR on VMS
+    if ($^O eq 'VMS') {
+        if ($ENV{HARNESS_ACTIVE} && !$ENV{HARNESS_VERBOSE}) {
+            close STDOUT;
+            close STDERR;
+            open STDOUT, '>&', $save_STDOUT or die "Can't restore STDOUT: $!";
+            open STDERR, '>&', $save_STDERR or die "Can't restore STDERR: $!";
+        }
+
+        print STDERR "$prefix$display_cmd => $e\n"
+            if !$ENV{HARNESS_ACTIVE} || $ENV{HARNESS_VERBOSE};
+    } else {
+        print STDERR "$prefix$display_cmd => $e\n";
     }
 
     }
 
-    print STDERR "$prefix$display_cmd => $e\n"
-        if !$ENV{HARNESS_ACTIVE} || $ENV{HARNESS_VERBOSE};
-
     # At this point, $? stops being interesting, and unfortunately,
     # there are Test::More versions that get picky if we leave it
     # non-zero.
     # At this point, $? stops being interesting, and unfortunately,
     # there are Test::More versions that get picky if we leave it
     # non-zero.
@@ -604,6 +613,23 @@ sub srctop_file {
 
 =over 4
 
 
 =over 4
 
+=item B<data_dir LIST>
+
+LIST is a list of directories that make up a path from the data directory
+associated with the test (see L</DESCRIPTION> above).
+C<data_dir> returns the resulting directory as a string, adapted to the local
+operating system.
+
+=back
+
+=cut
+
+sub data_dir {
+    return __data_dir(@_);
+}
+
+=over 4
+
 =item B<data_file LIST, FILENAME>
 
 LIST is a list of directories that make up a path from the data directory
 =item B<data_file LIST, FILENAME>
 
 LIST is a list of directories that make up a path from the data directory
@@ -661,7 +687,7 @@ sub pipe {
 
 =item B<with HASHREF, CODEREF>
 
 
 =item B<with HASHREF, CODEREF>
 
-C<with> will temporarly install hooks given by the HASHREF and then execute
+C<with> will temporarily install hooks given by the HASHREF and then execute
 the given CODEREF.  Hooks are usually expected to have a coderef as value.
 
 The currently available hoosk are:
 the given CODEREF.  Hooks are usually expected to have a coderef as value.
 
 The currently available hoosk are:
@@ -707,7 +733,7 @@ sub with {
 C<cmdstr> takes a CODEREF from C<app> or C<test> and simply returns the
 command as a string.
 
 C<cmdstr> takes a CODEREF from C<app> or C<test> and simply returns the
 command as a string.
 
-C<cmdstr> takes some additiona options OPTS that affect the string returned:
+C<cmdstr> takes some additional options OPTS that affect the string returned:
 
 =over 4
 
 
 =over 4
 
@@ -758,12 +784,13 @@ I<This must never ever be done on VMS.>
 sub quotify {
     # Unix setup (default if nothing else is mentioned)
     my $arg_formatter =
 sub quotify {
     # Unix setup (default if nothing else is mentioned)
     my $arg_formatter =
-       sub { $_ = shift; /\s|[\{\}\\\$\[\]\*\?\|\&:;<>]/ ? "'$_'" : $_ };
+       sub { $_ = shift;
+             ($_ eq '' || /\s|[\{\}\\\$\[\]\*\?\|\&:;<>]/) ? "'$_'" : $_ };
 
     if ( $^O eq "VMS") {       # VMS setup
        $arg_formatter = sub {
            $_ = shift;
 
     if ( $^O eq "VMS") {       # VMS setup
        $arg_formatter = sub {
            $_ = shift;
-           if (/\s|["[:upper:]]/) {
+           if ($_ eq '' || /\s|["[:upper:]]/) {
                s/"/""/g;
                '"'.$_.'"';
            } else {
                s/"/""/g;
                '"'.$_.'"';
            } else {
@@ -773,7 +800,7 @@ sub quotify {
     } elsif ( $^O eq "MSWin32") { # MSWin setup
        $arg_formatter = sub {
            $_ = shift;
     } elsif ( $^O eq "MSWin32") { # MSWin setup
        $arg_formatter = sub {
            $_ = shift;
-           if (/\s|["\|\&\*\;<>]/) {
+           if ($_ eq '' || /\s|["\|\&\*\;<>]/) {
                s/(["\\])/\\$1/g;
                '"'.$_.'"';
            } else {
                s/(["\\])/\\$1/g;
                '"'.$_.'"';
            } else {
@@ -785,6 +812,88 @@ sub quotify {
     return map { $arg_formatter->($_) } @_;
 }
 
     return map { $arg_formatter->($_) } @_;
 }
 
+=over 4
+
+=item B<openssl_versions>
+
+Returns a list of two version numbers, the first representing the build
+version, the second representing the library version.  See opensslv.h for
+more information on those numbers.
+
+=back
+
+=cut
+
+my @versions = ();
+sub openssl_versions {
+    unless (@versions) {
+        my %lines =
+            map { s/\R$//;
+                  /^(.*): (.*)$/;
+                  $1 => $2 }
+            run(test(['versions']), capture => 1);
+        @versions = ( $lines{'Build version'}, $lines{'Library version'} );
+    }
+    return @versions;
+}
+
+=over 4
+
+=item B<ok_nofips EXPR, TEST_NAME>
+
+C<ok_nofips> is equivalent to using C<ok> when the environment variable
+C<FIPS_MODE> is undefined, otherwise it is equivalent to C<not ok>. This can be
+used for C<ok> tests that must fail when testing a FIPS provider. The parameters
+are the same as used by C<ok> which is an expression EXPR followed by the test
+description TEST_NAME.
+
+An example:
+
+  ok_nofips(run(app(["md5.pl"])), "md5 should fail in fips mode");
+
+=item B<is_nofips EXPR1, EXPR2, TEST_NAME>
+
+C<is_nofips> is equivalent to using C<is> when the environment variable
+C<FIPS_MODE> is undefined, otherwise it is equivalent to C<isnt>. This can be
+used for C<is> tests that must fail when testing a FIPS provider. The parameters
+are the same as used by C<is> which has 2 arguments EXPR1 and EXPR2 that can be
+compared using eq or ne, followed by a test description TEST_NAME.
+
+An example:
+
+  is_nofips(ultimate_answer(), 42,  "Meaning of Life");
+
+=item B<isnt_nofips EXPR1, EXPR2, TEST_NAME>
+
+C<isnt_nofips> is equivalent to using C<isnt> when the environment variable
+C<FIPS_MODE> is undefined, otherwise it is equivalent to C<is>. This can be
+used for C<isnt> tests that must fail when testing a FIPS provider. The
+parameters are the same as used by C<isnt> which has 2 arguments EXPR1 and EXPR2
+that can be compared using ne or eq, followed by a test description TEST_NAME.
+
+An example:
+
+  isnt_nofips($foo, '',  "Got some foo");
+
+=back
+
+=cut
+
+sub ok_nofips {
+    return ok(!$_[0], @_[1..$#_]) if defined $ENV{FIPS_MODE};
+    return ok($_[0], @_[1..$#_]);
+}
+
+sub is_nofips {
+    return isnt($_[0], $_[1], @_[2..$#_]) if defined $ENV{FIPS_MODE};
+    return is($_[0], $_[1], @_[2..$#_]);
+}
+
+sub isnt_nofips {
+    return is($_[0], $_[1], @_[2..$#_]) if defined $ENV{FIPS_MODE};
+    return isnt($_[0], $_[1], @_[2..$#_]);
+}
+
 ######################################################################
 # private functions.  These are never exported.
 
 ######################################################################
 # private functions.  These are never exported.
 
@@ -815,6 +924,12 @@ are located.  Defaults to C<$TOP/test> (adapted to the operating system).
 If defined, it puts testing in a different mode, where a recipe with
 failures will result in a C<BAIL_OUT> at the end of its run.
 
 If defined, it puts testing in a different mode, where a recipe with
 failures will result in a C<BAIL_OUT> at the end of its run.
 
+=item B<FIPS_MODE>
+
+If defined it indicates that the FIPS provider is being tested. Tests may use
+B<ok_nofips>, B<is_nofips> and B<isnt_nofips> to invert test results
+i.e. Some tests may only work in non FIPS mode.
+
 =back
 
 =cut
 =back
 
 =cut
@@ -822,17 +937,22 @@ failures will result in a C<BAIL_OUT> at the end of its run.
 sub __env {
     (my $recipe_datadir = basename($0)) =~ s/\.t$/_data/i;
 
 sub __env {
     (my $recipe_datadir = basename($0)) =~ s/\.t$/_data/i;
 
-    $directories{SRCTOP}  = $ENV{SRCTOP} || $ENV{TOP};
-    $directories{BLDTOP}  = $ENV{BLDTOP} || $ENV{TOP};
-    $directories{BLDAPPS} = $ENV{BIN_D}  || __bldtop_dir("apps");
-    $directories{SRCAPPS} =                 __srctop_dir("apps");
-    $directories{BLDFUZZ} =                 __bldtop_dir("fuzz");
-    $directories{SRCFUZZ} =                 __srctop_dir("fuzz");
-    $directories{BLDTEST} = $ENV{TEST_D} || __bldtop_dir("test");
-    $directories{SRCTEST} =                 __srctop_dir("test");
-    $directories{SRCDATA} =                 __srctop_dir("test", "recipes",
-                                                         $recipe_datadir);
-    $directories{RESULTS} = $ENV{RESULT_D} || $directories{BLDTEST};
+    $directories{SRCTOP}    = abs_path($ENV{SRCTOP} || $ENV{TOP});
+    $directories{BLDTOP}    = abs_path($ENV{BLDTOP} || $ENV{TOP});
+    $directories{BLDAPPS}   = $ENV{BIN_D}  || __bldtop_dir("apps");
+    $directories{SRCAPPS}   =                 __srctop_dir("apps");
+    $directories{BLDFUZZ}   =                 __bldtop_dir("fuzz");
+    $directories{SRCFUZZ}   =                 __srctop_dir("fuzz");
+    $directories{BLDTEST}   = $ENV{TEST_D} || __bldtop_dir("test");
+    $directories{SRCTEST}   =                 __srctop_dir("test");
+    $directories{SRCDATA}   =                 __srctop_dir("test", "recipes",
+                                                           $recipe_datadir);
+    $directories{RESULTTOP} = $ENV{RESULT_D} || __bldtop_dir("test-runs");
+    $directories{RESULTS}   = catdir($directories{RESULTTOP}, $test_name);
+
+    # Create result directory dynamically
+    rmtree($directories{RESULTS}, { safe => 0, keep_root => 1 });
+    mkpath($directories{RESULTS});
 
     push @direnv, "TOP"       if $ENV{TOP};
     push @direnv, "SRCTOP"    if $ENV{SRCTOP};
 
     push @direnv, "TOP"       if $ENV{TOP};
     push @direnv, "SRCTOP"    if $ENV{SRCTOP};
@@ -841,7 +961,7 @@ sub __env {
     push @direnv, "TEST_D"    if $ENV{TEST_D};
     push @direnv, "RESULT_D"  if $ENV{RESULT_D};
 
     push @direnv, "TEST_D"    if $ENV{TEST_D};
     push @direnv, "RESULT_D"  if $ENV{RESULT_D};
 
-    $end_with_bailout    = $ENV{STOPTEST} ? 1 : 0;
+    $end_with_bailout = $ENV{STOPTEST} ? 1 : 0;
 };
 
 # __srctop_file and __srctop_dir are helpers to build file and directory
 };
 
 # __srctop_file and __srctop_dir are helpers to build file and directory
@@ -856,26 +976,26 @@ sub __srctop_file {
     BAIL_OUT("Must run setup() first") if (! $test_name);
 
     my $f = pop;
     BAIL_OUT("Must run setup() first") if (! $test_name);
 
     my $f = pop;
-    return catfile($directories{SRCTOP},@_,$f);
+    return abs2rel(catfile($directories{SRCTOP},@_,$f),getcwd);
 }
 
 sub __srctop_dir {
     BAIL_OUT("Must run setup() first") if (! $test_name);
 
 }
 
 sub __srctop_dir {
     BAIL_OUT("Must run setup() first") if (! $test_name);
 
-    return catdir($directories{SRCTOP},@_);
+    return abs2rel(catdir($directories{SRCTOP},@_), getcwd);
 }
 
 sub __bldtop_file {
     BAIL_OUT("Must run setup() first") if (! $test_name);
 
     my $f = pop;
 }
 
 sub __bldtop_file {
     BAIL_OUT("Must run setup() first") if (! $test_name);
 
     my $f = pop;
-    return catfile($directories{BLDTOP},@_,$f);
+    return abs2rel(catfile($directories{BLDTOP},@_,$f), getcwd);
 }
 
 sub __bldtop_dir {
     BAIL_OUT("Must run setup() first") if (! $test_name);
 
 }
 
 sub __bldtop_dir {
     BAIL_OUT("Must run setup() first") if (! $test_name);
 
-    return catdir($directories{BLDTOP},@_);
+    return abs2rel(catdir($directories{BLDTOP},@_), getcwd);
 }
 
 # __exeext is a function that returns the platform dependent file extension
 }
 
 # __exeext is a function that returns the platform dependent file extension
@@ -937,6 +1057,12 @@ sub __data_file {
     return catfile($directories{SRCDATA},@_,$f);
 }
 
     return catfile($directories{SRCDATA},@_,$f);
 }
 
+sub __data_dir {
+    BAIL_OUT("Must run setup() first") if (! $test_name);
+
+    return catdir($directories{SRCDATA},@_);
+}
+
 sub __results_file {
     BAIL_OUT("Must run setup() first") if (! $test_name);
 
 sub __results_file {
     BAIL_OUT("Must run setup() first") if (! $test_name);
 
@@ -952,7 +1078,6 @@ sub __results_file {
 # hash style arguments to alter __cwd's behavior:
 #
 #    create = 0|1       The directory we move to is created if 1, not if 0.
 # hash style arguments to alter __cwd's behavior:
 #
 #    create = 0|1       The directory we move to is created if 1, not if 0.
-#    cleanup = 0|1      The directory we move from is removed if 1, not if 0.
 
 sub __cwd {
     my $dir = catdir(shift);
 
 sub __cwd {
     my $dir = catdir(shift);
@@ -1010,12 +1135,8 @@ sub __cwd {
     # Should we just bail out here as well?  I'm unsure.
     return undef unless chdir($dir);
 
     # Should we just bail out here as well?  I'm unsure.
     return undef unless chdir($dir);
 
-    if ($opts{cleanup}) {
-       rmtree(".", { safe => 0, keep_root => 1 });
-    }
-
     # We put back new values carefully.  Doing the obvious
     # We put back new values carefully.  Doing the obvious
-    # %directories = ( %tmp_irectories )
+    # %directories = ( %tmp_directories )
     # will clear out any value that happens to be an absolute path
     foreach (keys %tmp_directories) {
         $directories{$_} = $tmp_directories{$_};
     # will clear out any value that happens to be an absolute path
     foreach (keys %tmp_directories) {
         $directories{$_} = $tmp_directories{$_};
@@ -1057,13 +1178,31 @@ sub __wrap_cmd {
     my $cmd = shift;
     my $exe_shell = shift;
 
     my $cmd = shift;
     my $exe_shell = shift;
 
-    my @prefix = ( __bldtop_file("util", "shlib_wrap.sh") );
+    my @prefix = ();
 
 
-    if(defined($exe_shell)) {
-       @prefix = ( $exe_shell );
-    } elsif ($^O eq "VMS" || $^O eq "MSWin32") {
-       # VMS and Windows don't use any wrapper script for the moment
-       @prefix = ();
+    if (defined($exe_shell)) {
+        # If $exe_shell is defined, trust it
+        @prefix = ( $exe_shell );
+    } else {
+        # Otherwise, use the standard wrapper
+        my $std_wrapper = __bldtop_file("util", "wrap.pl");
+
+        if ($^O eq "VMS") {
+            # On VMS, running random executables without having a command
+            # symbol means running them with the MCR command.  This is an
+            # old PDP-11 command that stuck around.  So we get a command
+            # running perl running the script.
+            @prefix = ( "MCR", $^X, $std_wrapper );
+        } elsif ($^O eq "MSWin32") {
+            # In the Windows case, we run perl explicitly.  We might not
+            # need it, but that depends on if the user has associated the
+            # '.pl' extension with a perl interpreter, so better be safe.
+            @prefix = ( $^X, $std_wrapper );
+        } else {
+            # Otherwise, we assume Unix semantics, and trust that the #!
+            # line activates perl for us.
+            @prefix = ( $std_wrapper );
+        }
     }
 
     return (@prefix, $cmd);
     }
 
     return (@prefix, $cmd);
@@ -1127,8 +1266,11 @@ sub __decorate_cmd {
 
     my $display_cmd = "$cmdstr$stdin$stdout$stderr";
 
 
     my $display_cmd = "$cmdstr$stdin$stdout$stderr";
 
-    $stderr=" 2> ".$null
-        unless $stderr || !$ENV{HARNESS_ACTIVE} || $ENV{HARNESS_VERBOSE};
+    # VMS program output escapes TAP::Parser
+    if ($^O eq 'VMS') {
+        $stderr=" 2> ".$null
+            unless $stderr || !$ENV{HARNESS_ACTIVE} || $ENV{HARNESS_VERBOSE};
+    }
 
     $cmdstr .= "$stdin$stdout$stderr";
 
 
     $cmdstr .= "$stdin$stdout$stderr";
 
@@ -1146,7 +1288,7 @@ L<Test::More>, L<Test::Harness>
 
 =head1 AUTHORS
 
 
 =head1 AUTHORS
 
-Richard Levitte E<lt>levitte@openssl.orgE<gt> with assitance and
+Richard Levitte E<lt>levitte@openssl.orgE<gt> with assistance and
 inspiration from Andy Polyakov E<lt>appro@openssl.org<gt>.
 
 =cut
 inspiration from Andy Polyakov E<lt>appro@openssl.org<gt>.
 
 =cut