+######################################################################
+# private functions. These are never exported.
+
+=head1 ENVIRONMENT
+
+OpenSSL::Test depends on some environment variables.
+
+=over 4
+
+=item B<TOP>
+
+This environment variable is mandatory. C<setup> will check that it's
+defined and that it's a directory that contains the file C<Configure>.
+If this isn't so, C<setup> will C<BAIL_OUT>.
+
+=item B<BIN_D>
+
+If defined, its value should be the directory where the openssl application
+is located. Defaults to C<$TOP/apps> (adapted to the operating system).
+
+=item B<TEST_D>
+
+If defined, its value should be the directory where the test applications
+are located. Defaults to C<$TOP/test> (adapted to the operating system).
+
+=item B<RESULT_D>
+
+If defined, its value should be the directory where the log files are
+located. Defaults to C<$TEST_D>.
+
+=item B<STOPTEST>
+
+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.
+
+=back
+
+=cut
+
+sub __env {
+ $directories{TOP} = $ENV{TOP},
+ $directories{APPS} = $ENV{BIN_D} || catdir($directories{TOP},"apps");
+ $directories{TEST} = $ENV{TEST_D} || catdir($directories{TOP},"test");
+ $directories{RESULTS} = $ENV{RESULT_D} || $directories{TEST};
+
+ $end_with_bailout = $ENV{STOPTEST} ? 1 : 0;
+};
+
+sub __top_file {
+ BAIL_OUT("Must run setup() first") if (! $test_name);
+
+ my $f = pop;
+ return catfile($directories{TOP},@_,$f);
+}
+
+sub __test_file {
+ BAIL_OUT("Must run setup() first") if (! $test_name);
+
+ my $f = pop;
+ return catfile($directories{TEST},@_,$f);
+}
+
+sub __apps_file {
+ BAIL_OUT("Must run setup() first") if (! $test_name);
+
+ my $f = pop;
+ return catfile($directories{APPS},@_,$f);
+}
+
+sub __results_file {
+ BAIL_OUT("Must run setup() first") if (! $test_name);
+
+ my $f = pop;
+ return catfile($directories{RESULTS},@_,$f);
+}
+
+sub __test_log {
+ return __results_file("$test_name.log");
+}
+
+sub __cwd {
+ my $dir = shift;
+ my %opts = @_;
+ my $abscurdir = rel2abs(curdir());
+ my $absdir = rel2abs($dir);
+ my $reverse = abs2rel($abscurdir, $absdir);
+
+ # PARANOIA: if we're not moving anywhere, we do nothing more
+ if ($abscurdir eq $absdir) {
+ return $reverse;
+ }
+
+ # Do not support a move to a different volume for now. Maybe later.
+ BAIL_OUT("FAILURE: \"$dir\" moves to a different volume, not supported")
+ if $reverse eq $abscurdir;
+
+ # If someone happened to give a directory that leads back to the current,
+ # it's extremely silly to do anything more, so just simulate that we did
+ # move.
+ # In this case, we won't even clean it out, for safety's sake.
+ return "." if $reverse eq "";
+
+ $dir = canonpath($dir);
+ if ($opts{create}) {
+ mkpath($dir);
+ }
+
+ # Should we just bail out here as well? I'm unsure.
+ return undef unless chdir($dir);
+
+ if ($opts{cleanup}) {
+ remove_tree(".", { safe => 0, keep_root => 1 });
+ }
+
+ # For each of these directory variables, figure out where they are relative
+ # to the directory we want to move to if they aren't absolute (if they are,
+ # they don't change!)
+ my @dirtags = ("TOP", "TEST", "APPS", "RESULTS");
+ foreach (@dirtags) {
+ if (!file_name_is_absolute($directories{$_})) {
+ my $newpath = abs2rel(rel2abs($directories{$_}), rel2abs($dir));
+ $directories{$_} = $newpath;
+ }
+ }
+
+ if (0) {
+ print STDERR "DEBUG: __cwd(), directories and files:\n";
+ print STDERR " \$directories{TEST} = \"$directories{TEST}\"\n";
+ print STDERR " \$directories{RESULTS} = \"$directories{RESULTS}\"\n";
+ print STDERR " \$directories{APPS} = \"$directories{APPS}\"\n";
+ print STDERR " \$directories{TOP} = \"$directories{TOP}\"\n";
+ print STDERR " \$test_log = \"",__test_log(),"\"\n";
+ print STDERR "\n";
+ print STDERR " current directory is \"",curdir(),"\"\n";
+ print STDERR " the way back is \"$reverse\"\n";
+ }
+
+ return $reverse;
+}
+
+sub __fixup_cmd {
+ my $prog = shift;
+
+ my $prefix = __top_file("util", "shlib_wrap.sh")." ";
+ my $ext = $ENV{"EXE_EXT"} || "";
+
+ if ( $^O eq "VMS" ) { # VMS
+ $prefix = "mcr ";
+ $ext = ".exe";
+ } elsif ($^O eq "MSWin32") { # Windows
+ $prefix = "";
+ $ext = ".exe";
+ }
+
+ # We test both with and without extension. The reason
+ # is that we might, for example, be passed a Perl script
+ # ending with .pl...
+ my $file = "$prog$ext";
+ if ( -x $file ) {
+ return $prefix.$file;
+ } elsif ( -f $prog ) {
+ return $prog;
+ }
+
+ print STDERR "$prog not found\n";
+ return undef;
+}
+
+sub __build_cmd {
+ BAIL_OUT("Must run setup() first") if (! $test_name);
+
+ my $num = shift;
+ my $path_builder = shift;
+ # Make a copy to not destroy the caller's array
+ my @cmdarray = ( @{$_[0]} ); shift;
+ my $cmd = __fixup_cmd($path_builder->(shift @cmdarray));
+ my @args = @cmdarray;
+ my %opts = @_;
+
+ return () if !$cmd;
+
+ my $arg_str = "";
+ my $null = devnull();
+
+
+ $arg_str = " ".join(" ", quotify @args) if @args;
+
+ my $fileornull = sub { $_[0] ? $_[0] : $null; };
+ my $stdin = "";
+ my $stdout = "";
+ my $stderr = "";
+ my $saved_stderr = undef;
+ $stdin = " < ".$fileornull->($opts{stdin}) if exists($opts{stdin});
+ $stdout= " > ".$fileornull->($opts{stdout}) if exists($opts{stdout});
+ $stderr=" 2> ".$fileornull->($opts{stderr}) if exists($opts{stderr});
+
+ $saved_stderr = $opts{stderr} if defined($opts{stderr});
+
+ my $errlog = $num ? "$test_name.$num.tmp_err" : "$test_name.tmp_err";
+ my $display_cmd = "$cmd$arg_str$stdin$stdout$stderr";
+ $cmd .= "$arg_str$stdin$stdout 2> $errlog";
+
+ return ($cmd, $display_cmd, $errlog => $saved_stderr);
+}
+
+=head1 SEE ALSO
+
+L<Test::More>, L<Test::Harness>
+
+=head1 AUTHORS
+
+Richard Levitte E<lt>levitte@openssl.orgE<gt> with assitance and
+inspiration from Andy Polyakov E<lt>appro@openssl.org<gt>.
+
+=cut
+