$categories_run = 0;
$categories_passed = 0;
$total_tests_run = 0;
$total_tests_passed = 0;
$tests_run = 0;
$tests_passed = 0;
$test_passed = 1;
%makeENV = ();
%extraENV = ();
%origENV = %ENV;
sub resetENV
{
foreach $v (keys %ENV) {
delete $ENV{$v};
}
%ENV = %makeENV;
foreach $v (keys %extraENV) {
$ENV{$v} = $extraENV{$v};
delete $extraENV{$v};
}
}
sub toplevel
{
foreach ( 'TZ', 'LANG', 'TMPDIR', 'HOME', 'USER', 'LOGNAME', 'PATH',
'PURIFYOPTIONS',
'Path', 'SystemRoot',
'DJDIR', 'DJGPP', 'SHELL', 'COMSPEC', 'HOSTNAME', 'LFN',
'FNCASE', '387', 'EMU387', 'GROUP'
) {
$makeENV{$_} = $ENV{$_} if $ENV{$_};
}
%origENV = %ENV;
resetENV();
$| = 1;
$debug = 0; $profile = 0; $verbose = 0; $detail = 0; $keep = 0; $workdir = "work"; $scriptdir = "scripts"; $tmpfilesuffix = "t"; $default_output_stack_level = 0; $default_input_stack_level = 0; $cwd = "."; $cwdslash = "";
&get_osname;
&set_defaults;
&parse_command_line (@ARGV);
print "OS name = `$osname'\n" if $debug;
$workpath = "$cwdslash$workdir";
$scriptpath = "$cwdslash$scriptdir";
&set_more_defaults;
&print_banner;
if (-d $workpath)
{
print "Clearing $workpath...\n";
&remove_directory_tree("$workpath/")
|| &error ("Couldn't wipe out $workpath\n");
}
else
{
mkdir ($workpath, 0777) || &error ("Couldn't mkdir $workpath: $!\n");
}
if (!-d $scriptpath)
{
&error ("Failed to find $scriptpath containing perl test scripts.\n");
}
if (@TESTS)
{
print "Making work dirs...\n";
foreach $test (@TESTS)
{
if ($test =~ /^([^\/]+)\//)
{
$dir = $1;
push (@rmdirs, $dir);
-d "$workpath/$dir"
|| mkdir ("$workpath/$dir", 0777)
|| &error ("Couldn't mkdir $workpath/$dir: $!\n");
}
}
}
else
{
print "Finding tests...\n";
opendir (SCRIPTDIR, $scriptpath)
|| &error ("Couldn't opendir $scriptpath: $!\n");
@dirs = grep (!/^(\..*|CVS|RCS)$/, readdir (SCRIPTDIR) );
closedir (SCRIPTDIR);
foreach $dir (@dirs)
{
next if ($dir =~ /^(\..*|CVS|RCS)$/ || ! -d "$scriptpath/$dir");
push (@rmdirs, $dir);
mkdir ("$workpath/$dir", 0777)
|| &error ("Couldn't mkdir $workpath/$dir: $!\n");
opendir (SCRIPTDIR, "$scriptpath/$dir")
|| &error ("Couldn't opendir $scriptpath/$dir: $!\n");
@files = grep (!/^(\..*|CVS|RCS|.*~)$/, readdir (SCRIPTDIR) );
closedir (SCRIPTDIR);
foreach $test (@files)
{
-d $test and next;
push (@TESTS, "$dir/$test");
}
}
}
if (@TESTS == 0)
{
&error ("\nNo tests in $scriptpath, and none were specified.\n");
}
print "\n";
&run_each_test;
foreach $dir (@rmdirs)
{
rmdir ("$workpath/$dir");
}
$| = 1;
$categories_failed = $categories_run - $categories_passed;
$total_tests_failed = $total_tests_run - $total_tests_passed;
if ($total_tests_failed)
{
print "\n$total_tests_failed Test";
print "s" unless $total_tests_failed == 1;
print " in $categories_failed Categor";
print ($categories_failed == 1 ? "y" : "ies");
print " Failed (See .$diffext files in $workdir dir for details) :-(\n\n";
return 0;
}
else
{
print "\n$total_tests_passed Test";
print "s" unless $total_tests_passed == 1;
print " in $categories_passed Categor";
print ($categories_passed == 1 ? "y" : "ies");
print " Complete ... No Failures :-)\n\n";
return 1;
}
}
sub get_osname
{
$osname = defined($^O) ? $^O : '';
$short_filenames = 0;
(open (TOUCHFD, "> fancy.file.name") && close (TOUCHFD))
|| ($short_filenames = 1);
unlink ("fancy.file.name") || ($short_filenames = 1);
if (! $short_filenames) {
mkdir (".ostest", 0777) || &error ("Couldn't create .ostest: $!\n", 1);
open (TOUCHFD, "> .ostest>ick") && close (TOUCHFD);
chdir (".ostest") || &error ("Couldn't chdir to .ostest: $!\n", 1);
}
if (! $short_filenames && -f "ick")
{
$osname = "vos";
$vos = 1;
$pathsep = ">";
}
else
{
eval "chop (\$osname = `sh -c 'uname -nmsr 2>&1'`)";
if ($osname =~ /not found/i)
{
$osname = "(something unixy with no uname)";
}
elsif ($@ ne "" || $?)
{
eval "chop (\$osname = `sh -c 'uname -a 2>&1'`)";
if ($@ ne "" || $?)
{
$osname = "(something unixy)";
}
}
$vos = 0;
$pathsep = "/";
}
if (! $short_filenames) {
chdir ("..") || &error ("Couldn't chdir to ..: $!\n", 1);
unlink (".ostest>ick");
rmdir (".ostest") || &error ("Couldn't rmdir .ostest: $!\n", 1);
}
}
sub parse_command_line
{
@argv = @_;
if (@argv == 0)
{
@argv = @ARGV;
}
while (@argv)
{
$option = shift @argv;
if ($option =~ /^-debug$/i)
{
print "\nDEBUG ON\n";
$debug = 1;
}
elsif ($option =~ /^-usage$/i)
{
&print_usage;
exit 0;
}
elsif ($option =~ /^-(h|help)$/i)
{
&print_help;
exit 0;
}
elsif ($option =~ /^-profile$/i)
{
$profile = 1;
}
elsif ($option =~ /^-verbose$/i)
{
$verbose = 1;
}
elsif ($option =~ /^-detail$/i)
{
$detail = 1;
$verbose = 1;
}
elsif ($option =~ /^-keep$/i)
{
$keep = 1;
}
elsif (&valid_option($option))
{
}
elsif ($option =~ /^-/)
{
print "Invalid option: $option\n";
&print_usage;
exit 0;
}
else {
$option =~ s/\.pl$//;
push(@TESTS,$option);
}
}
}
sub max
{
local($num) = shift @_;
local($newnum);
while (@_)
{
$newnum = shift @_;
if ($newnum > $num)
{
$num = $newnum;
}
}
return $num;
}
sub print_centered
{
local($width, $string) = @_;
local($pad);
if (length ($string))
{
$pad = " " x ( ($width - length ($string) + 1) / 2);
print "$pad$string";
}
}
sub print_banner
{
local($info);
local($line);
local($len);
$info = "Running tests for $testee on $osname\n"; $len = &max (length ($line), length ($testee_version),
length ($banner_info), 73) + 5;
$line = ("-" x $len) . "\n";
if ($len < 78)
{
$len = 78;
}
&print_centered ($len, $line);
&print_centered ($len, $info);
&print_centered ($len, $testee_version); &print_centered ($len, $banner_info); &print_centered ($len, $line);
print "\n";
}
sub run_each_test
{
$categories_run = 0;
foreach $testname (sort @TESTS)
{
++$categories_run;
$suite_passed = 1; $num_of_logfiles = 0;
$num_of_tmpfiles = 0;
$description = "";
$details = "";
$old_makefile = undef;
$testname =~ s/^$scriptpath$pathsep//;
$perl_testname = "$scriptpath$pathsep$testname";
$testname =~ s/(\.pl|\.perl)$//;
$testpath = "$workpath$pathsep$testname";
if ($short_filenames) {
$logext = 'l';
$diffext = 'd';
$baseext = 'b';
$extext = '';
} else {
$logext = 'log';
$diffext = 'diff';
$baseext = 'base';
$extext = '.';
}
$log_filename = "$testpath.$logext";
$diff_filename = "$testpath.$diffext";
$base_filename = "$testpath.$baseext";
$tmp_filename = "$testpath.$tmpfilesuffix";
&setup_for_test;
$output = "........................................................ ";
substr($output,0,length($testname)) = "$testname ";
print $output;
$tests_run = 0;
$tests_passed = 0;
$code = do $perl_testname;
$total_tests_run += $tests_run;
$total_tests_passed += $tests_passed;
if (!defined($code))
{
$suite_passed = 0;
if (length ($@)) {
warn "\n*** Test died ($testname): $@\n";
} else {
warn "\n*** Couldn't run $perl_testname\n";
}
}
elsif ($code == -1) {
$suite_passed = 0;
}
elsif ($code != 1 && $code != -1) {
$suite_passed = 0;
warn "\n*** Test returned $code\n";
}
if ($suite_passed) {
++$categories_passed;
$status = "ok ($tests_passed passed)";
for ($i = $num_of_tmpfiles; $i; $i--)
{
&rmfiles ($tmp_filename . &num_suffix ($i) );
}
for ($i = $num_of_logfiles ? $num_of_logfiles : 1; $i; $i--)
{
&rmfiles ($log_filename . &num_suffix ($i) );
&rmfiles ($base_filename . &num_suffix ($i) );
}
}
elsif (!defined $code || $code > 0) {
$status = "FAILED ($tests_passed/$tests_run passed)";
}
elsif ($code < 0) {
$status = "N/A";
--$categories_run;
}
if ($verbose)
{
if ($detail)
{
print "\nWHAT IS BEING TESTED\n";
print "--------------------";
}
print "\n\n$description\n\n";
}
if ($detail)
{
print "\nHOW IT IS TESTED\n";
print "----------------";
print "\n\n$details\n\n";
}
print "$status\n";
}
}
sub rmfiles
{
local(@files) = @_;
if (!$keep)
{
return (unlink @files);
}
return 1;
}
sub print_standard_usage
{
local($plname,@moreusage) = @_;
local($line);
print "Usage: perl $plname [testname] [-verbose] [-detail] [-keep]\n";
print " [-profile] [-usage] [-help] "
. "[-debug]\n";
foreach $line (@moreusage)
{
print " $line\n";
}
}
sub print_standard_help
{
local(@morehelp) = @_;
local($line);
local($tline);
local($t) = " ";
$line = "Test Driver For $testee";
print "$line\n";
$line = "=" x length ($line);
print "$line\n";
&print_usage;
print "\ntestname\n"
. "${t}You may, if you wish, run only ONE test if you know the name\n"
. "${t}of that test and specify this name anywhere on the command\n"
. "${t}line. Otherwise ALL existing tests in the scripts directory\n"
. "${t}will be run.\n"
. "-verbose\n"
. "${t}If this option is given, a description of every test is\n"
. "${t}displayed before the test is run. (Not all tests may have\n"
. "${t}descriptions at this time)\n"
. "-detail\n"
. "${t}If this option is given, a detailed description of every\n"
. "${t}test is displayed before the test is run. (Not all tests\n"
. "${t}have descriptions at this time)\n"
. "-profile\n"
. "${t}If this option is given, then the profile file\n"
. "${t}is added to other profiles every time $testee is run.\n"
. "${t}This option only works on VOS at this time.\n"
. "-keep\n"
. "${t}You may give this option if you DO NOT want ANY\n"
. "${t}of the files generated by the tests to be deleted. \n"
. "${t}Without this option, all files generated by the test will\n"
. "${t}be deleted IF THE TEST PASSES.\n"
. "-debug\n"
. "${t}Use this option if you would like to see all of the system\n"
. "${t}calls issued and their return status while running the tests\n"
. "${t}This can be helpful if you're having a problem adding a test\n"
. "${t}to the suite, or if the test fails!\n";
foreach $line (@morehelp)
{
$tline = $line;
if (substr ($tline, 0, 1) eq "\t")
{
substr ($tline, 0, 1) = $t;
}
print "$tline\n";
}
}
sub get_caller
{
local($depth);
local($package);
local($filename);
local($linenum);
$depth = defined ($_[0]) ? $_[0] : 1;
($package, $filename, $linenum) = caller ($depth + 1);
return "$filename: $linenum";
}
sub error
{
local($message) = $_[0];
local($caller) = &get_caller (1);
if (defined ($_[1]))
{
$caller = &get_caller ($_[1] + 1) . " -> $caller";
}
die "$caller: $message";
}
sub compare_output
{
local($answer,$logfile) = @_;
local($slurp, $answer_matched) = ('', 0);
print "Comparing Output ........ " if $debug;
$slurp = &read_file_into_string ($logfile);
$slurp =~ s/^.*modification time .*in the future.*\n//gm;
$slurp =~ s/^.*Clock skew detected.*\n//gm;
++$tests_run;
if ($slurp eq $answer) {
$answer_matched = 1;
} else {
local ($answer_mod) = $answer;
$answer_mod =~ tr,\\,/,;
$answer_mod =~ s,\r\n,\n,gs;
$slurp =~ tr,\\,/,;
$slurp =~ s,\r\n,\n,gs;
$answer_matched = ($slurp eq $answer_mod);
}
if ($answer_matched && $test_passed)
{
print "ok\n" if $debug;
++$tests_passed;
return 1;
}
if (! $answer_matched) {
print "DIFFERENT OUTPUT\n" if $debug;
&create_file (&get_basefile, $answer);
print "\nCreating Difference File ...\n" if $debug;
local($command) = "diff -c " . &get_basefile . " " . $logfile;
&run_command_with_output(&get_difffile,$command);
}
$suite_passed = 0;
return 0;
}
sub read_file_into_string
{
local($filename) = @_;
local($oldslash) = $/;
undef $/;
open (RFISFILE, $filename) || return "";
local ($slurp) = <RFISFILE>;
close (RFISFILE);
$/ = $oldslash;
return $slurp;
}
sub attach_default_output
{
local ($filename) = @_;
local ($code);
if ($vos)
{
$code = system "++attach_default_output_hack $filename";
$code == -2 || &error ("adoh death\n", 1);
return 1;
}
open ("SAVEDOS" . $default_output_stack_level . "out", ">&STDOUT")
|| &error ("ado: $! duping STDOUT\n", 1);
open ("SAVEDOS" . $default_output_stack_level . "err", ">&STDERR")
|| &error ("ado: $! duping STDERR\n", 1);
open (STDOUT, "> " . $filename)
|| &error ("ado: $filename: $!\n", 1);
open (STDERR, ">&STDOUT")
|| &error ("ado: $filename: $!\n", 1);
$default_output_stack_level++;
}
sub detach_default_output
{
local ($code);
if ($vos)
{
$code = system "++detach_default_output_hack";
$code == -2 || &error ("ddoh death\n", 1);
return 1;
}
if (--$default_output_stack_level < 0)
{
&error ("default output stack has flown under!\n", 1);
}
close (STDOUT);
close (STDERR);
open (STDOUT, ">&SAVEDOS" . $default_output_stack_level . "out")
|| &error ("ddo: $! duping STDOUT\n", 1);
open (STDERR, ">&SAVEDOS" . $default_output_stack_level . "err")
|| &error ("ddo: $! duping STDERR\n", 1);
close ("SAVEDOS" . $default_output_stack_level . "out")
|| &error ("ddo: $! closing SCSDOSout\n", 1);
close ("SAVEDOS" . $default_output_stack_level . "err")
|| &error ("ddo: $! closing SAVEDOSerr\n", 1);
}
sub run_command
{
local ($code);
resetENV();
print "\nrun_command: @_\n" if $debug;
$code = system @_;
print "run_command: \"@_\" returned $code.\n" if $debug;
return $code;
}
sub run_command_with_output
{
local ($filename) = shift;
local ($code);
resetENV();
&attach_default_output ($filename);
$code = system @_;
&detach_default_output;
print "run_command_with_output: '@_' returned $code.\n" if $debug;
return $code;
}
sub remove_directory_tree
{
local ($targetdir) = @_;
local ($nuketop) = 1;
local ($ch);
$ch = substr ($targetdir, length ($targetdir) - 1);
if ($ch eq "/" || $ch eq $pathsep)
{
$targetdir = substr ($targetdir, 0, length ($targetdir) - 1);
$nuketop = 0;
}
if (! -e $targetdir)
{
return 1;
}
&remove_directory_tree_inner ("RDT00", $targetdir) || return 0;
if ($nuketop)
{
rmdir $targetdir || return 0;
}
return 1;
}
sub remove_directory_tree_inner
{
local ($dirhandle, $targetdir) = @_;
local ($object);
local ($subdirhandle);
opendir ($dirhandle, $targetdir) || return 0;
$subdirhandle = $dirhandle;
$subdirhandle++;
while ($object = readdir ($dirhandle))
{
if ($object =~ /^(\.\.?|CVS|RCS)$/)
{
next;
}
$object = "$targetdir$pathsep$object";
lstat ($object);
if (-d _ && &remove_directory_tree_inner ($subdirhandle, $object))
{
rmdir $object || return 0;
}
else
{
unlink $object || return 0;
}
}
closedir ($dirhandle);
return 1;
}
sub touch
{
local ($file);
foreach $file (@_) {
(open(T, ">> $file") && print(T "\n") && close(T))
|| &error("Couldn't touch $file: $!\n", 1);
}
}
sub utouch
{
local ($off) = shift;
local ($file);
&touch(@_);
local (@s) = stat($_[0]);
utime($s[8]+$off, $s[9]+$off, @_);
}
sub create_file
{
local ($filename, @lines) = @_;
open (CF, "> $filename") || &error ("Couldn't open $filename: $!\n", 1);
foreach $line (@lines)
{
print CF $line;
}
close (CF);
}
sub create_dir_tree
{
local ($basedir, %dirtree) = @_;
local ($path);
&remove_directory_tree ("$basedir");
mkdir ($basedir, 0777) || &error ("Couldn't mkdir $basedir: $!\n", 1);
foreach $path (sort keys (%dirtree))
{
if ($dirtree {$path} =~ /^DIR$/)
{
mkdir ("$basedir/$path", 0777)
|| &error ("Couldn't mkdir $basedir/$path: $!\n", 1);
}
elsif ($dirtree {$path} =~ /^FILE:(.*)$/)
{
&create_file ("$basedir/$path", $1 . "\n");
}
elsif ($dirtree {$path} =~ /^LINK:(.*)$/)
{
symlink ("$basedir/$1", "$basedir/$path")
|| &error ("Couldn't symlink $basedir/$path -> $basedir/$1: $!\n", 1);
}
else
{
&error ("Bogus dirtree type: \"$dirtree{$path}\"\n", 1);
}
}
if ($just_setup_tree)
{
die "Tree is setup...\n";
}
}
sub compare_dir_tree
{
local ($basedir, %dirtree) = @_;
local ($path);
local ($i);
local ($bogus) = 0;
local ($contents);
local ($target);
local ($fulltarget);
local ($found);
local (@files);
local (@allfiles);
opendir (DIR, $basedir) || &error ("Couldn't open $basedir: $!\n", 1);
@allfiles = grep (!/^(\.\.?|CVS|RCS)$/, readdir (DIR) );
closedir (DIR);
if ($debug)
{
print "dirtree: (%dirtree)\n$basedir: (@allfiles)\n";
}
foreach $path (sort keys (%dirtree))
{
if ($debug)
{
print "Checking $path ($dirtree{$path}).\n";
}
$found = 0;
foreach $i (0 .. $ {
if ($allfiles[$i] eq $path)
{
splice (@allfiles, $i, 1); if ($debug)
{
print " Zapped $path; files now (@allfiles).\n";
}
lstat ("$basedir/$path");
$found = 1;
last;
}
}
if (!$found)
{
print "compare_dir_tree: $path does not exist.\n";
$bogus = 1;
next;
}
if ($dirtree {$path} =~ /^DIR$/)
{
if (-d _ && opendir (DIR, "$basedir/$path") )
{
@files = readdir (DIR);
closedir (DIR);
@files = grep (!/^(\.\.?|CVS|RCS)$/ && ($_ = "$path/$_"), @files);
push (@allfiles, @files);
if ($debug)
{
print " Read in $path; new files (@files).\n";
}
}
else
{
print "compare_dir_tree: $path is not a dir.\n";
$bogus = 1;
}
}
elsif ($dirtree {$path} =~ /^FILE:(.*)$/)
{
if (-l _ || !-f _)
{
print "compare_dir_tree: $path is not a file.\n";
$bogus = 1;
next;
}
if ($1 ne "*")
{
$contents = &read_file_into_string ("$basedir/$path");
if ($contents ne "$1\n")
{
print "compare_dir_tree: $path contains wrong stuff."
. " Is:\n$contentsShould be:\n$1\n";
$bogus = 1;
}
}
}
elsif ($dirtree {$path} =~ /^LINK:(.*)$/)
{
$target = $1;
if (!-l _)
{
print "compare_dir_tree: $path is not a link.\n";
$bogus = 1;
next;
}
$contents = readlink ("$basedir/$path");
$contents =~ tr/>/\//;
$fulltarget = "$basedir/$target";
$fulltarget =~ tr/>/\//;
if (!($contents =~ /$fulltarget$/))
{
if ($debug)
{
$target = $fulltarget;
}
print "compare_dir_tree: $path should be link to $target, "
. "not $contents.\n";
$bogus = 1;
}
}
else
{
&error ("Bogus dirtree type: \"$dirtree{$path}\"\n", 1);
}
}
if ($debug)
{
print "leftovers: (@allfiles).\n";
}
foreach $file (@allfiles)
{
print "compare_dir_tree: $file should not exist.\n";
$bogus = 1;
}
return !$bogus;
}
sub num_suffix
{
local($num) = @_;
if (--$num > 0) {
return "$extext$num";
}
return "";
}
sub get_logfile
{
local($no_increment) = @_;
$num_of_logfiles += !$no_increment;
return ($log_filename . &num_suffix ($num_of_logfiles));
}
sub get_basefile
{
return ($base_filename . &num_suffix ($num_of_logfiles));
}
sub get_difffile
{
return ($diff_filename . &num_suffix ($num_of_logfiles));
}
sub get_tmpfile
{
local($no_increment) = @_;
$num_of_tmpfiles += !$no_increment;
return ($tmp_filename . &num_suffix ($num_of_tmpfiles));
}
1;