xref: /netbsd-src/crypto/external/bsd/openssl/dist/util/perl/OpenSSL/Test.pm (revision 132cc1c4aeae88a30a5e34dc141e119eb83f8d7f)
1# Copyright 2016-2018 The OpenSSL Project Authors. All Rights Reserved.
2#
3# Licensed under the OpenSSL license (the "License").  You may not use
4# this file except in compliance with the License.  You can obtain a copy
5# in the file LICENSE in the source distribution or at
6# https://www.openssl.org/source/license.html
7
8package OpenSSL::Test;
9
10use strict;
11use warnings;
12
13use Test::More 0.96;
14
15use Exporter;
16use vars qw($VERSION @ISA @EXPORT @EXPORT_OK %EXPORT_TAGS);
17$VERSION = "0.8";
18@ISA = qw(Exporter);
19@EXPORT = (@Test::More::EXPORT, qw(setup indir app fuzz  perlapp test perltest
20                                   run));
21@EXPORT_OK = (@Test::More::EXPORT_OK, qw(bldtop_dir bldtop_file
22                                         srctop_dir srctop_file
23                                         data_file
24                                         pipe with cmdstr quotify
25                                         openssl_versions));
26
27=head1 NAME
28
29OpenSSL::Test - a private extension of Test::More
30
31=head1 SYNOPSIS
32
33  use OpenSSL::Test;
34
35  setup("my_test_name");
36
37  ok(run(app(["openssl", "version"])), "check for openssl presence");
38
39  indir "subdir" => sub {
40    ok(run(test(["sometest", "arg1"], stdout => "foo.txt")),
41       "run sometest with output to foo.txt");
42  };
43
44=head1 DESCRIPTION
45
46This module is a private extension of L<Test::More> for testing OpenSSL.
47In addition to the Test::More functions, it also provides functions that
48easily find the diverse programs within a OpenSSL build tree, as well as
49some other useful functions.
50
51This module I<depends> on the environment variables C<$TOP> or C<$SRCTOP>
52and C<$BLDTOP>.  Without one of the combinations it refuses to work.
53See L</ENVIRONMENT> below.
54
55With each test recipe, a parallel data directory with (almost) the same name
56as the recipe is possible in the source directory tree.  For example, for a
57recipe C<$SRCTOP/test/recipes/99-foo.t>, there could be a directory
58C<$SRCTOP/test/recipes/99-foo_data/>.
59
60=cut
61
62use File::Copy;
63use File::Spec::Functions qw/file_name_is_absolute curdir canonpath splitdir
64                             catdir catfile splitpath catpath devnull abs2rel
65                             rel2abs/;
66use File::Path 2.00 qw/rmtree mkpath/;
67use File::Basename;
68
69
70# The name of the test.  This is set by setup() and is used in the other
71# functions to verify that setup() has been used.
72my $test_name = undef;
73
74# Directories we want to keep track of TOP, APPS, TEST and RESULTS are the
75# ones we're interested in, corresponding to the environment variables TOP
76# (mandatory), BIN_D, TEST_D, UTIL_D and RESULT_D.
77my %directories = ();
78
79# The environment variables that gave us the contents in %directories.  These
80# get modified whenever we change directories, so that subprocesses can use
81# the values of those environment variables as well
82my @direnv = ();
83
84# A bool saying if we shall stop all testing if the current recipe has failing
85# tests or not.  This is set by setup() if the environment variable STOPTEST
86# is defined with a non-empty value.
87my $end_with_bailout = 0;
88
89# A set of hooks that is affected by with() and may be used in diverse places.
90# All hooks are expected to be CODE references.
91my %hooks = (
92
93    # exit_checker is used by run() directly after completion of a command.
94    # it receives the exit code from that command and is expected to return
95    # 1 (for success) or 0 (for failure).  This is the value that will be
96    # returned by run().
97    # NOTE: When run() gets the option 'capture => 1', this hook is ignored.
98    exit_checker => sub { return shift == 0 ? 1 : 0 },
99
100    );
101
102# Debug flag, to be set manually when needed
103my $debug = 0;
104
105# Declare some utility functions that are defined at the end
106sub bldtop_file;
107sub bldtop_dir;
108sub srctop_file;
109sub srctop_dir;
110sub quotify;
111
112# Declare some private functions that are defined at the end
113sub __env;
114sub __cwd;
115sub __apps_file;
116sub __results_file;
117sub __fixup_cmd;
118sub __build_cmd;
119
120=head2 Main functions
121
122The following functions are exported by default when using C<OpenSSL::Test>.
123
124=cut
125
126=over 4
127
128=item B<setup "NAME">
129
130C<setup> is used for initial setup, and it is mandatory that it's used.
131If it's not used in a OpenSSL test recipe, the rest of the recipe will
132most likely refuse to run.
133
134C<setup> checks for environment variables (see L</ENVIRONMENT> below),
135checks that C<$TOP/Configure> or C<$SRCTOP/Configure> exists, C<chdir>
136into the results directory (defined by the C<$RESULT_D> environment
137variable if defined, otherwise C<$BLDTOP/test> or C<$TOP/test>, whichever
138is defined).
139
140=back
141
142=cut
143
144sub setup {
145    my $old_test_name = $test_name;
146    $test_name = shift;
147
148    BAIL_OUT("setup() must receive a name") unless $test_name;
149    warn "setup() detected test name change.  Innocuous, so we continue...\n"
150        if $old_test_name && $old_test_name ne $test_name;
151
152    return if $old_test_name;
153
154    BAIL_OUT("setup() needs \$TOP or \$SRCTOP and \$BLDTOP to be defined")
155        unless $ENV{TOP} || ($ENV{SRCTOP} && $ENV{BLDTOP});
156    BAIL_OUT("setup() found both \$TOP and \$SRCTOP or \$BLDTOP...")
157        if $ENV{TOP} && ($ENV{SRCTOP} || $ENV{BLDTOP});
158
159    __env();
160
161    BAIL_OUT("setup() expects the file Configure in the source top directory")
162        unless -f srctop_file("Configure");
163
164    __cwd($directories{RESULTS});
165}
166
167=over 4
168
169=item B<indir "SUBDIR" =E<gt> sub BLOCK, OPTS>
170
171C<indir> is used to run a part of the recipe in a different directory than
172the one C<setup> moved into, usually a subdirectory, given by SUBDIR.
173The part of the recipe that's run there is given by the codeblock BLOCK.
174
175C<indir> takes some additional options OPTS that affect the subdirectory:
176
177=over 4
178
179=item B<create =E<gt> 0|1>
180
181When set to 1 (or any value that perl preceives as true), the subdirectory
182will be created if it doesn't already exist.  This happens before BLOCK
183is executed.
184
185=item B<cleanup =E<gt> 0|1>
186
187When set to 1 (or any value that perl preceives as true), the subdirectory
188will be cleaned out and removed.  This happens both before and after BLOCK
189is executed.
190
191=back
192
193An example:
194
195  indir "foo" => sub {
196      ok(run(app(["openssl", "version"]), stdout => "foo.txt"));
197      if (ok(open(RESULT, "foo.txt"), "reading foo.txt")) {
198          my $line = <RESULT>;
199          close RESULT;
200          is($line, qr/^OpenSSL 1\./,
201             "check that we're using OpenSSL 1.x.x");
202      }
203  }, create => 1, cleanup => 1;
204
205=back
206
207=cut
208
209sub indir {
210    my $subdir = shift;
211    my $codeblock = shift;
212    my %opts = @_;
213
214    my $reverse = __cwd($subdir,%opts);
215    BAIL_OUT("FAILURE: indir, \"$subdir\" wasn't possible to move into")
216	unless $reverse;
217
218    $codeblock->();
219
220    __cwd($reverse);
221
222    if ($opts{cleanup}) {
223	rmtree($subdir, { safe => 0 });
224    }
225}
226
227=over 4
228
229=item B<app ARRAYREF, OPTS>
230
231=item B<test ARRAYREF, OPTS>
232
233Both of these functions take a reference to a list that is a command and
234its arguments, and some additional options (described further on).
235
236C<app> expects to find the given command (the first item in the given list
237reference) as an executable in C<$BIN_D> (if defined, otherwise C<$TOP/apps>
238or C<$BLDTOP/apps>).
239
240C<test> expects to find the given command (the first item in the given list
241reference) as an executable in C<$TEST_D> (if defined, otherwise C<$TOP/test>
242or C<$BLDTOP/test>).
243
244Both return a CODEREF to be used by C<run>, C<pipe> or C<cmdstr>.
245
246The options that both C<app> and C<test> can take are in the form of hash
247values:
248
249=over 4
250
251=item B<stdin =E<gt> PATH>
252
253=item B<stdout =E<gt> PATH>
254
255=item B<stderr =E<gt> PATH>
256
257In all three cases, the corresponding standard input, output or error is
258redirected from (for stdin) or to (for the others) a file given by the
259string PATH, I<or>, if the value is C<undef>, C</dev/null> or similar.
260
261=back
262
263=item B<perlapp ARRAYREF, OPTS>
264
265=item B<perltest ARRAYREF, OPTS>
266
267Both these functions function the same way as B<app> and B<test>, except
268that they expect the command to be a perl script.  Also, they support one
269more option:
270
271=over 4
272
273=item B<interpreter_args =E<gt> ARRAYref>
274
275The array reference is a set of arguments for perl rather than the script.
276Take care so that none of them can be seen as a script!  Flags and their
277eventual arguments only!
278
279=back
280
281An example:
282
283  ok(run(perlapp(["foo.pl", "arg1"],
284                 interpreter_args => [ "-I", srctop_dir("test") ])));
285
286=back
287
288=cut
289
290sub app {
291    my $cmd = shift;
292    my %opts = @_;
293    return sub { my $num = shift;
294		 return __build_cmd($num, \&__apps_file, $cmd, %opts); }
295}
296
297sub fuzz {
298    my $cmd = shift;
299    my %opts = @_;
300    return sub { my $num = shift;
301		 return __build_cmd($num, \&__fuzz_file, $cmd, %opts); }
302}
303
304sub test {
305    my $cmd = shift;
306    my %opts = @_;
307    return sub { my $num = shift;
308		 return __build_cmd($num, \&__test_file, $cmd, %opts); }
309}
310
311sub perlapp {
312    my $cmd = shift;
313    my %opts = @_;
314    return sub { my $num = shift;
315		 return __build_cmd($num, \&__perlapps_file, $cmd, %opts); }
316}
317
318sub perltest {
319    my $cmd = shift;
320    my %opts = @_;
321    return sub { my $num = shift;
322		 return __build_cmd($num, \&__perltest_file, $cmd, %opts); }
323}
324
325=over 4
326
327=item B<run CODEREF, OPTS>
328
329This CODEREF is expected to be the value return by C<app> or C<test>,
330anything else will most likely cause an error unless you know what you're
331doing.
332
333C<run> executes the command returned by CODEREF and return either the
334resulting output (if the option C<capture> is set true) or a boolean indicating
335if the command succeeded or not.
336
337The options that C<run> can take are in the form of hash values:
338
339=over 4
340
341=item B<capture =E<gt> 0|1>
342
343If true, the command will be executed with a perl backtick, and C<run> will
344return the resulting output as an array of lines.  If false or not given,
345the command will be executed with C<system()>, and C<run> will return 1 if
346the command was successful or 0 if it wasn't.
347
348=back
349
350For further discussion on what is considered a successful command or not, see
351the function C<with> further down.
352
353=back
354
355=cut
356
357sub run {
358    my ($cmd, $display_cmd) = shift->(0);
359    my %opts = @_;
360
361    return () if !$cmd;
362
363    my $prefix = "";
364    if ( $^O eq "VMS" ) {	# VMS
365	$prefix = "pipe ";
366    }
367
368    my @r = ();
369    my $r = 0;
370    my $e = 0;
371
372    # In non-verbose, we want to shut up the command interpreter, in case
373    # it has something to complain about.  On VMS, it might complain both
374    # on stdout and stderr
375    my $save_STDOUT;
376    my $save_STDERR;
377    if ($ENV{HARNESS_ACTIVE} && !$ENV{HARNESS_VERBOSE}) {
378        open $save_STDOUT, '>&', \*STDOUT or die "Can't dup STDOUT: $!";
379        open $save_STDERR, '>&', \*STDERR or die "Can't dup STDERR: $!";
380        open STDOUT, ">", devnull();
381        open STDERR, ">", devnull();
382    }
383
384    # The dance we do with $? is the same dance the Unix shells appear to
385    # do.  For example, a program that gets aborted (and therefore signals
386    # SIGABRT = 6) will appear to exit with the code 134.  We mimic this
387    # to make it easier to compare with a manual run of the command.
388    if ($opts{capture}) {
389	@r = `$prefix$cmd`;
390	$e = ($? & 0x7f) ? ($? & 0x7f)|0x80 : ($? >> 8);
391    } else {
392	system("$prefix$cmd");
393	$e = ($? & 0x7f) ? ($? & 0x7f)|0x80 : ($? >> 8);
394	$r = $hooks{exit_checker}->($e);
395    }
396
397    if ($ENV{HARNESS_ACTIVE} && !$ENV{HARNESS_VERBOSE}) {
398        close STDOUT;
399        close STDERR;
400        open STDOUT, '>&', $save_STDOUT or die "Can't restore STDOUT: $!";
401        open STDERR, '>&', $save_STDERR or die "Can't restore STDERR: $!";
402    }
403
404    print STDERR "$prefix$display_cmd => $e\n"
405        if !$ENV{HARNESS_ACTIVE} || $ENV{HARNESS_VERBOSE};
406
407    # At this point, $? stops being interesting, and unfortunately,
408    # there are Test::More versions that get picky if we leave it
409    # non-zero.
410    $? = 0;
411
412    if ($opts{capture}) {
413	return @r;
414    } else {
415	return $r;
416    }
417}
418
419END {
420    my $tb = Test::More->builder;
421    my $failure = scalar(grep { $_ == 0; } $tb->summary);
422    if ($failure && $end_with_bailout) {
423	BAIL_OUT("Stoptest!");
424    }
425}
426
427=head2 Utility functions
428
429The following functions are exported on request when using C<OpenSSL::Test>.
430
431  # To only get the bldtop_file and srctop_file functions.
432  use OpenSSL::Test qw/bldtop_file srctop_file/;
433
434  # To only get the bldtop_file function in addition to the default ones.
435  use OpenSSL::Test qw/:DEFAULT bldtop_file/;
436
437=cut
438
439# Utility functions, exported on request
440
441=over 4
442
443=item B<bldtop_dir LIST>
444
445LIST is a list of directories that make up a path from the top of the OpenSSL
446build directory (as indicated by the environment variable C<$TOP> or
447C<$BLDTOP>).
448C<bldtop_dir> returns the resulting directory as a string, adapted to the local
449operating system.
450
451=back
452
453=cut
454
455sub bldtop_dir {
456    return __bldtop_dir(@_);	# This caters for operating systems that have
457				# a very distinct syntax for directories.
458}
459
460=over 4
461
462=item B<bldtop_file LIST, FILENAME>
463
464LIST is a list of directories that make up a path from the top of the OpenSSL
465build directory (as indicated by the environment variable C<$TOP> or
466C<$BLDTOP>) and FILENAME is the name of a file located in that directory path.
467C<bldtop_file> returns the resulting file path as a string, adapted to the local
468operating system.
469
470=back
471
472=cut
473
474sub bldtop_file {
475    return __bldtop_file(@_);
476}
477
478=over 4
479
480=item B<srctop_dir LIST>
481
482LIST is a list of directories that make up a path from the top of the OpenSSL
483source directory (as indicated by the environment variable C<$TOP> or
484C<$SRCTOP>).
485C<srctop_dir> returns the resulting directory as a string, adapted to the local
486operating system.
487
488=back
489
490=cut
491
492sub srctop_dir {
493    return __srctop_dir(@_);	# This caters for operating systems that have
494				# a very distinct syntax for directories.
495}
496
497=over 4
498
499=item B<srctop_file LIST, FILENAME>
500
501LIST is a list of directories that make up a path from the top of the OpenSSL
502source directory (as indicated by the environment variable C<$TOP> or
503C<$SRCTOP>) and FILENAME is the name of a file located in that directory path.
504C<srctop_file> returns the resulting file path as a string, adapted to the local
505operating system.
506
507=back
508
509=cut
510
511sub srctop_file {
512    return __srctop_file(@_);
513}
514
515=over 4
516
517=item B<data_file LIST, FILENAME>
518
519LIST is a list of directories that make up a path from the data directory
520associated with the test (see L</DESCRIPTION> above) and FILENAME is the name
521of a file located in that directory path.  C<data_file> returns the resulting
522file path as a string, adapted to the local operating system.
523
524=back
525
526=cut
527
528sub data_file {
529    return __data_file(@_);
530}
531
532=over 4
533
534=item B<pipe LIST>
535
536LIST is a list of CODEREFs returned by C<app> or C<test>, from which C<pipe>
537creates a new command composed of all the given commands put together in a
538pipe.  C<pipe> returns a new CODEREF in the same manner as C<app> or C<test>,
539to be passed to C<run> for execution.
540
541=back
542
543=cut
544
545sub pipe {
546    my @cmds = @_;
547    return
548	sub {
549	    my @cs  = ();
550	    my @dcs = ();
551	    my @els = ();
552	    my $counter = 0;
553	    foreach (@cmds) {
554		my ($c, $dc, @el) = $_->(++$counter);
555
556		return () if !$c;
557
558		push @cs, $c;
559		push @dcs, $dc;
560		push @els, @el;
561	    }
562	    return (
563		join(" | ", @cs),
564		join(" | ", @dcs),
565		@els
566		);
567    };
568}
569
570=over 4
571
572=item B<with HASHREF, CODEREF>
573
574C<with> will temporarly install hooks given by the HASHREF and then execute
575the given CODEREF.  Hooks are usually expected to have a coderef as value.
576
577The currently available hoosk are:
578
579=over 4
580
581=item B<exit_checker =E<gt> CODEREF>
582
583This hook is executed after C<run> has performed its given command.  The
584CODEREF receives the exit code as only argument and is expected to return
5851 (if the exit code indicated success) or 0 (if the exit code indicated
586failure).
587
588=back
589
590=back
591
592=cut
593
594sub with {
595    my $opts = shift;
596    my %opts = %{$opts};
597    my $codeblock = shift;
598
599    my %saved_hooks = ();
600
601    foreach (keys %opts) {
602	$saved_hooks{$_} = $hooks{$_}	if exists($hooks{$_});
603	$hooks{$_} = $opts{$_};
604    }
605
606    $codeblock->();
607
608    foreach (keys %saved_hooks) {
609	$hooks{$_} = $saved_hooks{$_};
610    }
611}
612
613=over 4
614
615=item B<cmdstr CODEREF, OPTS>
616
617C<cmdstr> takes a CODEREF from C<app> or C<test> and simply returns the
618command as a string.
619
620C<cmdstr> takes some additiona options OPTS that affect the string returned:
621
622=over 4
623
624=item B<display =E<gt> 0|1>
625
626When set to 0, the returned string will be with all decorations, such as a
627possible redirect of stderr to the null device.  This is suitable if the
628string is to be used directly in a recipe.
629
630When set to 1, the returned string will be without extra decorations.  This
631is suitable for display if that is desired (doesn't confuse people with all
632internal stuff), or if it's used to pass a command down to a subprocess.
633
634Default: 0
635
636=back
637
638=back
639
640=cut
641
642sub cmdstr {
643    my ($cmd, $display_cmd) = shift->(0);
644    my %opts = @_;
645
646    if ($opts{display}) {
647        return $display_cmd;
648    } else {
649        return $cmd;
650    }
651}
652
653=over 4
654
655=item B<quotify LIST>
656
657LIST is a list of strings that are going to be used as arguments for a
658command, and makes sure to inject quotes and escapes as necessary depending
659on the content of each string.
660
661This can also be used to put quotes around the executable of a command.
662I<This must never ever be done on VMS.>
663
664=back
665
666=cut
667
668sub quotify {
669    # Unix setup (default if nothing else is mentioned)
670    my $arg_formatter =
671	sub { $_ = shift;
672	      ($_ eq '' || /\s|[\{\}\\\$\[\]\*\?\|\&:;<>]/) ? "'$_'" : $_ };
673
674    if ( $^O eq "VMS") {	# VMS setup
675	$arg_formatter = sub {
676	    $_ = shift;
677	    if ($_ eq '' || /\s|["[:upper:]]/) {
678		s/"/""/g;
679		'"'.$_.'"';
680	    } else {
681		$_;
682	    }
683	};
684    } elsif ( $^O eq "MSWin32") { # MSWin setup
685	$arg_formatter = sub {
686	    $_ = shift;
687	    if ($_ eq '' || /\s|["\|\&\*\;<>]/) {
688		s/(["\\])/\\$1/g;
689		'"'.$_.'"';
690	    } else {
691		$_;
692	    }
693	};
694    }
695
696    return map { $arg_formatter->($_) } @_;
697}
698
699=over 4
700
701=item B<openssl_versions>
702
703Returns a list of two numbers, the first representing the build version,
704the second representing the library version.  See opensslv.h for more
705information on those numbers.
706
707= back
708
709=cut
710
711my @versions = ();
712sub openssl_versions {
713    unless (@versions) {
714        my %lines =
715            map { s/\R$//;
716                  /^(.*): (0x[[:xdigit:]]{8})$/;
717                  die "Weird line: $_" unless defined $1;
718                  $1 => hex($2) }
719            run(test(['versions']), capture => 1);
720        @versions = ( $lines{'Build version'}, $lines{'Library version'} );
721    }
722    return @versions;
723}
724
725######################################################################
726# private functions.  These are never exported.
727
728=head1 ENVIRONMENT
729
730OpenSSL::Test depends on some environment variables.
731
732=over 4
733
734=item B<TOP>
735
736This environment variable is mandatory.  C<setup> will check that it's
737defined and that it's a directory that contains the file C<Configure>.
738If this isn't so, C<setup> will C<BAIL_OUT>.
739
740=item B<BIN_D>
741
742If defined, its value should be the directory where the openssl application
743is located.  Defaults to C<$TOP/apps> (adapted to the operating system).
744
745=item B<TEST_D>
746
747If defined, its value should be the directory where the test applications
748are located.  Defaults to C<$TOP/test> (adapted to the operating system).
749
750=item B<STOPTEST>
751
752If defined, it puts testing in a different mode, where a recipe with
753failures will result in a C<BAIL_OUT> at the end of its run.
754
755=back
756
757=cut
758
759sub __env {
760    (my $recipe_datadir = basename($0)) =~ s/\.t$/_data/i;
761
762    $directories{SRCTOP}  = $ENV{SRCTOP} || $ENV{TOP};
763    $directories{BLDTOP}  = $ENV{BLDTOP} || $ENV{TOP};
764    $directories{BLDAPPS} = $ENV{BIN_D}  || __bldtop_dir("apps");
765    $directories{SRCAPPS} =                 __srctop_dir("apps");
766    $directories{BLDFUZZ} =                 __bldtop_dir("fuzz");
767    $directories{SRCFUZZ} =                 __srctop_dir("fuzz");
768    $directories{BLDTEST} = $ENV{TEST_D} || __bldtop_dir("test");
769    $directories{SRCTEST} =                 __srctop_dir("test");
770    $directories{SRCDATA} =                 __srctop_dir("test", "recipes",
771                                                         $recipe_datadir);
772    $directories{RESULTS} = $ENV{RESULT_D} || $directories{BLDTEST};
773
774    push @direnv, "TOP"       if $ENV{TOP};
775    push @direnv, "SRCTOP"    if $ENV{SRCTOP};
776    push @direnv, "BLDTOP"    if $ENV{BLDTOP};
777    push @direnv, "BIN_D"     if $ENV{BIN_D};
778    push @direnv, "TEST_D"    if $ENV{TEST_D};
779    push @direnv, "RESULT_D"  if $ENV{RESULT_D};
780
781    $end_with_bailout	  = $ENV{STOPTEST} ? 1 : 0;
782};
783
784sub __srctop_file {
785    BAIL_OUT("Must run setup() first") if (! $test_name);
786
787    my $f = pop;
788    return catfile($directories{SRCTOP},@_,$f);
789}
790
791sub __srctop_dir {
792    BAIL_OUT("Must run setup() first") if (! $test_name);
793
794    return catdir($directories{SRCTOP},@_);
795}
796
797sub __bldtop_file {
798    BAIL_OUT("Must run setup() first") if (! $test_name);
799
800    my $f = pop;
801    return catfile($directories{BLDTOP},@_,$f);
802}
803
804sub __bldtop_dir {
805    BAIL_OUT("Must run setup() first") if (! $test_name);
806
807    return catdir($directories{BLDTOP},@_);
808}
809
810sub __exeext {
811    my $ext = "";
812    if ($^O eq "VMS" ) {	# VMS
813	$ext = ".exe";
814    } elsif ($^O eq "MSWin32") { # Windows
815	$ext = ".exe";
816    }
817    return $ENV{"EXE_EXT"} || $ext;
818}
819
820sub __test_file {
821    BAIL_OUT("Must run setup() first") if (! $test_name);
822
823    my $f = pop;
824    my $out = catfile($directories{BLDTEST},@_,$f . __exeext());
825    $out = catfile($directories{SRCTEST},@_,$f) unless -x $out;
826    return $out;
827}
828
829sub __perltest_file {
830    BAIL_OUT("Must run setup() first") if (! $test_name);
831
832    my $f = pop;
833    my $out = catfile($directories{BLDTEST},@_,$f);
834    $out = catfile($directories{SRCTEST},@_,$f) unless -f $out;
835    return ($^X, $out);
836}
837
838sub __apps_file {
839    BAIL_OUT("Must run setup() first") if (! $test_name);
840
841    my $f = pop;
842    my $out = catfile($directories{BLDAPPS},@_,$f . __exeext());
843    $out = catfile($directories{SRCAPPS},@_,$f) unless -x $out;
844    return $out;
845}
846
847sub __fuzz_file {
848    BAIL_OUT("Must run setup() first") if (! $test_name);
849
850    my $f = pop;
851    my $out = catfile($directories{BLDFUZZ},@_,$f . __exeext());
852    $out = catfile($directories{SRCFUZZ},@_,$f) unless -x $out;
853    return $out;
854}
855
856sub __perlapps_file {
857    BAIL_OUT("Must run setup() first") if (! $test_name);
858
859    my $f = pop;
860    my $out = catfile($directories{BLDAPPS},@_,$f);
861    $out = catfile($directories{SRCAPPS},@_,$f) unless -f $out;
862    return ($^X, $out);
863}
864
865sub __data_file {
866    BAIL_OUT("Must run setup() first") if (! $test_name);
867
868    my $f = pop;
869    return catfile($directories{SRCDATA},@_,$f);
870}
871
872sub __results_file {
873    BAIL_OUT("Must run setup() first") if (! $test_name);
874
875    my $f = pop;
876    return catfile($directories{RESULTS},@_,$f);
877}
878
879sub __cwd {
880    my $dir = catdir(shift);
881    my %opts = @_;
882    my $abscurdir = rel2abs(curdir());
883    my $absdir = rel2abs($dir);
884    my $reverse = abs2rel($abscurdir, $absdir);
885
886    # PARANOIA: if we're not moving anywhere, we do nothing more
887    if ($abscurdir eq $absdir) {
888	return $reverse;
889    }
890
891    # Do not support a move to a different volume for now.  Maybe later.
892    BAIL_OUT("FAILURE: \"$dir\" moves to a different volume, not supported")
893	if $reverse eq $abscurdir;
894
895    # If someone happened to give a directory that leads back to the current,
896    # it's extremely silly to do anything more, so just simulate that we did
897    # move.
898    # In this case, we won't even clean it out, for safety's sake.
899    return "." if $reverse eq "";
900
901    $dir = canonpath($dir);
902    if ($opts{create}) {
903	mkpath($dir);
904    }
905
906    # We are recalculating the directories we keep track of, but need to save
907    # away the result for after having moved into the new directory.
908    my %tmp_directories = ();
909    my %tmp_ENV = ();
910
911    # For each of these directory variables, figure out where they are relative
912    # to the directory we want to move to if they aren't absolute (if they are,
913    # they don't change!)
914    my @dirtags = sort keys %directories;
915    foreach (@dirtags) {
916	if (!file_name_is_absolute($directories{$_})) {
917	    my $newpath = abs2rel(rel2abs($directories{$_}), rel2abs($dir));
918	    $tmp_directories{$_} = $newpath;
919	}
920    }
921
922    # Treat each environment variable that was used to get us the values in
923    # %directories the same was as the paths in %directories, so any sub
924    # process can use their values properly as well
925    foreach (@direnv) {
926	if (!file_name_is_absolute($ENV{$_})) {
927	    my $newpath = abs2rel(rel2abs($ENV{$_}), rel2abs($dir));
928	    $tmp_ENV{$_} = $newpath;
929	}
930    }
931
932    # Should we just bail out here as well?  I'm unsure.
933    return undef unless chdir($dir);
934
935    if ($opts{cleanup}) {
936	rmtree(".", { safe => 0, keep_root => 1 });
937    }
938
939    # We put back new values carefully.  Doing the obvious
940    # %directories = ( %tmp_irectories )
941    # will clear out any value that happens to be an absolute path
942    foreach (keys %tmp_directories) {
943        $directories{$_} = $tmp_directories{$_};
944    }
945    foreach (keys %tmp_ENV) {
946        $ENV{$_} = $tmp_ENV{$_};
947    }
948
949    if ($debug) {
950	print STDERR "DEBUG: __cwd(), directories and files:\n";
951	print STDERR "  \$directories{BLDTEST} = \"$directories{BLDTEST}\"\n";
952	print STDERR "  \$directories{SRCTEST} = \"$directories{SRCTEST}\"\n";
953	print STDERR "  \$directories{SRCDATA} = \"$directories{SRCDATA}\"\n";
954	print STDERR "  \$directories{RESULTS} = \"$directories{RESULTS}\"\n";
955	print STDERR "  \$directories{BLDAPPS} = \"$directories{BLDAPPS}\"\n";
956	print STDERR "  \$directories{SRCAPPS} = \"$directories{SRCAPPS}\"\n";
957	print STDERR "  \$directories{SRCTOP}  = \"$directories{SRCTOP}\"\n";
958	print STDERR "  \$directories{BLDTOP}  = \"$directories{BLDTOP}\"\n";
959	print STDERR "\n";
960	print STDERR "  current directory is \"",curdir(),"\"\n";
961	print STDERR "  the way back is \"$reverse\"\n";
962    }
963
964    return $reverse;
965}
966
967sub __fixup_cmd {
968    my $prog = shift;
969    my $exe_shell = shift;
970
971    my $prefix = __bldtop_file("util", "shlib_wrap.sh")." ";
972
973    if (defined($exe_shell)) {
974	$prefix = "$exe_shell ";
975    } elsif ($^O eq "VMS" ) {	# VMS
976	$prefix = ($prog =~ /^(?:[\$a-z0-9_]+:)?[<\[]/i ? "mcr " : "mcr []");
977    } elsif ($^O eq "MSWin32") { # Windows
978	$prefix = "";
979    }
980
981    # We test both with and without extension.  The reason
982    # is that we might be passed a complete file spec, with
983    # extension.
984    if ( ! -x $prog ) {
985	my $prog = "$prog";
986	if ( ! -x $prog ) {
987	    $prog = undef;
988	}
989    }
990
991    if (defined($prog)) {
992	# Make sure to quotify the program file on platforms that may
993	# have spaces or similar in their path name.
994	# To our knowledge, VMS is the exception where quotifying should
995	# never happen.
996	($prog) = quotify($prog) unless $^O eq "VMS";
997	return $prefix.$prog;
998    }
999
1000    print STDERR "$prog not found\n";
1001    return undef;
1002}
1003
1004sub __build_cmd {
1005    BAIL_OUT("Must run setup() first") if (! $test_name);
1006
1007    my $num = shift;
1008    my $path_builder = shift;
1009    # Make a copy to not destroy the caller's array
1010    my @cmdarray = ( @{$_[0]} ); shift;
1011    my %opts = @_;
1012
1013    # We do a little dance, as $path_builder might return a list of
1014    # more than one.  If so, only the first is to be considered a
1015    # program to fix up, the rest is part of the arguments.  This
1016    # happens for perl scripts, where $path_builder will return
1017    # a list of two, $^X and the script name.
1018    # Also, if $path_builder returned more than one, we don't apply
1019    # the EXE_SHELL environment variable.
1020    my @prog = ($path_builder->(shift @cmdarray));
1021    my $first = shift @prog;
1022    my $exe_shell = @prog ? undef : $ENV{EXE_SHELL};
1023    my $cmd = __fixup_cmd($first, $exe_shell);
1024    if (@prog) {
1025	if ( ! -f $prog[0] ) {
1026	    print STDERR "$prog[0] not found\n";
1027	    $cmd = undef;
1028	}
1029    }
1030    my @args = (@prog, @cmdarray);
1031    if (defined($opts{interpreter_args})) {
1032        unshift @args, @{$opts{interpreter_args}};
1033    }
1034
1035    return () if !$cmd;
1036
1037    my $arg_str = "";
1038    my $null = devnull();
1039
1040
1041    $arg_str = " ".join(" ", quotify @args) if @args;
1042
1043    my $fileornull = sub { $_[0] ? $_[0] : $null; };
1044    my $stdin = "";
1045    my $stdout = "";
1046    my $stderr = "";
1047    my $saved_stderr = undef;
1048    $stdin = " < ".$fileornull->($opts{stdin})  if exists($opts{stdin});
1049    $stdout= " > ".$fileornull->($opts{stdout}) if exists($opts{stdout});
1050    $stderr=" 2> ".$fileornull->($opts{stderr}) if exists($opts{stderr});
1051
1052    my $display_cmd = "$cmd$arg_str$stdin$stdout$stderr";
1053
1054    $stderr=" 2> ".$null
1055        unless $stderr || !$ENV{HARNESS_ACTIVE} || $ENV{HARNESS_VERBOSE};
1056
1057    $cmd .= "$arg_str$stdin$stdout$stderr";
1058
1059    if ($debug) {
1060	print STDERR "DEBUG[__build_cmd]: \$cmd = \"$cmd\"\n";
1061	print STDERR "DEBUG[__build_cmd]: \$display_cmd = \"$display_cmd\"\n";
1062    }
1063
1064    return ($cmd, $display_cmd);
1065}
1066
1067=head1 SEE ALSO
1068
1069L<Test::More>, L<Test::Harness>
1070
1071=head1 AUTHORS
1072
1073Richard Levitte E<lt>levitte@openssl.orgE<gt> with assitance and
1074inspiration from Andy Polyakov E<lt>appro@openssl.org<gt>.
1075
1076=cut
1077
10781;
1079