VirtualBox

source: kBuild/trunk/src/kmk/tests/test_driver.pl@ 2074

Last change on this file since 2074 was 1993, checked in by bird, 16 years ago

Merged in current GNU Make code (CVS from 2008-10-28). Ref #55.

  • Property svn:eol-style set to native
File size: 30.9 KB
Line 
1#!/usr/bin/perl
2# -*-perl-*-
3#
4# Modification history:
5# Written 91-12-02 through 92-01-01 by Stephen McGee.
6# Modified 92-02-11 through 92-02-22 by Chris Arthur to further generalize.
7#
8# Copyright (C) 1991, 1992, 1993, 1994, 1995, 1996, 1997, 1998, 1999, 2000,
9# 2001, 2002, 2003, 2004, 2005, 2006, 2007 Free Software Foundation, Inc.
10# This file is part of GNU Make.
11#
12# GNU Make is free software; you can redistribute it and/or modify it under
13# the terms of the GNU General Public License as published by the Free Software
14# Foundation; either version 3 of the License, or (at your option) any later
15# version.
16#
17# GNU Make is distributed in the hope that it will be useful, but WITHOUT ANY
18# WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
19# FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
20# details.
21#
22# You should have received a copy of the GNU General Public License along with
23# this program. If not, see <http://www.gnu.org/licenses/>.
24
25
26# Test driver routines used by a number of test suites, including
27# those for SCS, make, roll_dir, and scan_deps (?).
28#
29# this routine controls the whole mess; each test suite sets up a few
30# variables and then calls &toplevel, which does all the real work.
31
32# $Id: test_driver.pl,v 1.24 2007/11/04 21:54:02 psmith Exp $
33
34
35# The number of test categories we've run
36$categories_run = 0;
37# The number of test categroies that have passed
38$categories_passed = 0;
39# The total number of individual tests that have been run
40$total_tests_run = 0;
41# The total number of individual tests that have passed
42$total_tests_passed = 0;
43# The number of tests in this category that have been run
44$tests_run = 0;
45# The number of tests in this category that have passed
46$tests_passed = 0;
47
48
49# Yeesh. This whole test environment is such a hack!
50$test_passed = 1;
51
52
53# Timeout in seconds. If the test takes longer than this we'll fail it.
54$test_timeout = 5;
55
56
57# %makeENV is the cleaned-out environment.
58%makeENV = ();
59
60# %extraENV are any extra environment variables the tests might want to set.
61# These are RESET AFTER EVERY TEST!
62%extraENV = ();
63
64# %origENV is the caller's original environment
65%origENV = %ENV;
66
67sub resetENV
68{
69 # We used to say "%ENV = ();" but this doesn't work in Perl 5.000
70 # through Perl 5.004. It was fixed in Perl 5.004_01, but we don't
71 # want to require that here, so just delete each one individually.
72 foreach $v (keys %ENV) {
73 delete $ENV{$v};
74 }
75
76 %ENV = %makeENV;
77 foreach $v (keys %extraENV) {
78 $ENV{$v} = $extraENV{$v};
79 delete $extraENV{$v};
80 }
81}
82
83sub toplevel
84{
85 # Pull in benign variables from the user's environment
86
87 foreach (# UNIX-specific things
88 'TZ', 'TMPDIR', 'HOME', 'USER', 'LOGNAME', 'PATH',
89 # Purify things
90 'PURIFYOPTIONS',
91 # Windows NT-specific stuff
92 'Path', 'SystemRoot',
93 # DJGPP-specific stuff
94 'DJDIR', 'DJGPP', 'SHELL', 'COMSPEC', 'HOSTNAME', 'LFN',
95 'FNCASE', '387', 'EMU387', 'GROUP'
96 ) {
97 $makeENV{$_} = $ENV{$_} if $ENV{$_};
98 }
99
100 # Make sure our compares are not foiled by locale differences
101
102 $makeENV{LC_ALL} = 'C';
103
104 # Replace the environment with the new one
105 #
106 %origENV = %ENV;
107
108 resetENV();
109
110 $| = 1; # unbuffered output
111
112 $debug = 0; # debug flag
113 $profile = 0; # profiling flag
114 $verbose = 0; # verbose mode flag
115 $detail = 0; # detailed verbosity
116 $keep = 0; # keep temp files around
117 $workdir = "work"; # The directory where the test will start running
118 $scriptdir = "scripts"; # The directory where we find the test scripts
119 $tmpfilesuffix = "t"; # the suffix used on tmpfiles
120 $default_output_stack_level = 0; # used by attach_default_output, etc.
121 $default_input_stack_level = 0; # used by attach_default_input, etc.
122 $cwd = "."; # don't we wish we knew
123 $cwdslash = ""; # $cwd . $pathsep, but "" rather than "./"
124 $is_kmk = 0; # kmk flag.
125 $is_fast = 0; # kmk_fgmake flag.
126
127 &get_osname; # sets $osname, $vos, $pathsep, $short_filenames,
128 # and $case_insensitive_fs
129
130 &set_defaults; # suite-defined
131
132 &parse_command_line (@ARGV);
133
134 print "OS name = `$osname'\n" if $debug;
135
136 $workpath = "$cwdslash$workdir";
137 $scriptpath = "$cwdslash$scriptdir";
138
139 &set_more_defaults; # suite-defined
140
141 &print_banner;
142
143 if (-d $workpath)
144 {
145 print "Clearing $workpath...\n";
146 &remove_directory_tree("$workpath/")
147 || &error ("Couldn't wipe out $workpath\n");
148 }
149 else
150 {
151 mkdir ($workpath, 0777) || &error ("Couldn't mkdir $workpath: $!\n");
152 }
153
154 if (!-d $scriptpath)
155 {
156 &error ("Failed to find $scriptpath containing perl test scripts.\n");
157 }
158
159 if (@TESTS)
160 {
161 print "Making work dirs...\n";
162 foreach $test (@TESTS)
163 {
164 if ($test =~ /^([^\/]+)\//)
165 {
166 $dir = $1;
167 push (@rmdirs, $dir);
168 -d "$workpath/$dir"
169 || mkdir ("$workpath/$dir", 0777)
170 || &error ("Couldn't mkdir $workpath/$dir: $!\n");
171 }
172 }
173 }
174 else
175 {
176 print "Finding tests...\n";
177 opendir (SCRIPTDIR, $scriptpath)
178 || &error ("Couldn't opendir $scriptpath: $!\n");
179 @dirs = grep (!/^(\..*|CVS|RCS)$/, readdir (SCRIPTDIR) );
180 closedir (SCRIPTDIR);
181 foreach $dir (@dirs)
182 {
183 next if ($dir =~ /^(\..*|CVS|RCS)$/ || ! -d "$scriptpath/$dir");
184 push (@rmdirs, $dir);
185 mkdir ("$workpath/$dir", 0777)
186 || &error ("Couldn't mkdir $workpath/$dir: $!\n");
187 opendir (SCRIPTDIR, "$scriptpath/$dir")
188 || &error ("Couldn't opendir $scriptpath/$dir: $!\n");
189 @files = grep (!/^(\..*|CVS|RCS|.*~)$/, readdir (SCRIPTDIR) );
190 closedir (SCRIPTDIR);
191 foreach $test (@files)
192 {
193 -d $test and next;
194 push (@TESTS, "$dir/$test");
195 }
196 }
197 }
198
199 if (@TESTS == 0)
200 {
201 &error ("\nNo tests in $scriptpath, and none were specified.\n");
202 }
203
204 print "\n";
205
206 &run_each_test;
207
208 foreach $dir (@rmdirs)
209 {
210 rmdir ("$workpath/$dir");
211 }
212
213 $| = 1;
214
215 $categories_failed = $categories_run - $categories_passed;
216 $total_tests_failed = $total_tests_run - $total_tests_passed;
217
218 if ($total_tests_failed)
219 {
220 print "\n$total_tests_failed Test";
221 print "s" unless $total_tests_failed == 1;
222 print " in $categories_failed Categor";
223 print ($categories_failed == 1 ? "y" : "ies");
224 print " Failed (See .$diffext files in $workdir dir for details) :-(\n\n";
225 return 0;
226 }
227 else
228 {
229 print "\n$total_tests_passed Test";
230 print "s" unless $total_tests_passed == 1;
231 print " in $categories_passed Categor";
232 print ($categories_passed == 1 ? "y" : "ies");
233 print " Complete ... No Failures :-)\n\n";
234 return 1;
235 }
236}
237
238sub get_osname
239{
240 # Set up an initial value. In perl5 we can do it the easy way.
241 #
242 $osname = defined($^O) ? $^O : '';
243
244 # See if the filesystem supports long file names with multiple
245 # dots. DOS doesn't.
246 $short_filenames = 0;
247 (open (TOUCHFD, "> fancy.file.name") && close (TOUCHFD))
248 || ($short_filenames = 1);
249 unlink ("fancy.file.name") || ($short_filenames = 1);
250
251 if (! $short_filenames) {
252 # Thanks go to [email protected] (Jim Meyering) for suggesting a
253 # better way of doing this. (We used to test for existence of a /mnt
254 # dir, but that apparently fails on an SGI Indigo (whatever that is).)
255 # Because perl on VOS translates /'s to >'s, we need to test for
256 # VOSness rather than testing for Unixness (ie, try > instead of /).
257
258 mkdir (".ostest", 0777) || &error ("Couldn't create .ostest: $!\n", 1);
259 open (TOUCHFD, "> .ostest>ick") && close (TOUCHFD);
260 chdir (".ostest") || &error ("Couldn't chdir to .ostest: $!\n", 1);
261 }
262
263 if (! $short_filenames && -f "ick")
264 {
265 $osname = "vos";
266 $vos = 1;
267 $pathsep = ">";
268 }
269 else
270 {
271 # the following is regrettably knarly, but it seems to be the only way
272 # to not get ugly error messages if uname can't be found.
273 # Hmmm, BSD/OS 2.0's uname -a is excessively verbose. Let's try it
274 # with switches first.
275 eval "chop (\$osname = `sh -c 'uname -nmsr 2>&1'`)";
276 if ($osname =~ /not found/i)
277 {
278 $osname = "(something unixy with no uname)";
279 }
280 elsif ($@ ne "" || $?)
281 {
282 eval "chop (\$osname = `sh -c 'uname -a 2>&1'`)";
283 if ($@ ne "" || $?)
284 {
285 $osname = "(something unixy)";
286 }
287 }
288 $vos = 0;
289 $pathsep = "/";
290 }
291
292 if (! $short_filenames) {
293 chdir ("..") || &error ("Couldn't chdir to ..: $!\n", 1);
294 unlink (".ostest>ick");
295 rmdir (".ostest") || &error ("Couldn't rmdir .ostest: $!\n", 1);
296 }
297
298 # Check for case insensitive file system (bird)
299 # The deal is that the 2nd unlink will fail because the first one
300 # will already have removed the file if the fs ignore case.
301 $case_insensitive_fs = 0;
302 my $testfile1 = $short_filenames ? "CaseFs.rmt" : "CaseInSensitiveFs.check";
303 my $testfile2 = $short_filenames ? "casEfS.rmt" : "casEiNsensitivEfS.Check";
304 (open (TOUCHFD, "> $testfile1") && close (TOUCHFD))
305 || &error ("Couldn't create $testfile1: $!\n", 1);
306 (open (TOUCHFD, "> $testfile2") && close (TOUCHFD))
307 || &error ("Couldn't create $testfile2: $!\n", 1);
308 unlink ($testfile1) || &error ("Couldn't unlink $testfile1: $!\n", 1);
309 unlink ($testfile2) || ($case_insensitive_fs = 1);
310}
311
312sub parse_command_line
313{
314 @argv = @_;
315
316 # use @ARGV if no args were passed in
317
318 if (@argv == 0)
319 {
320 @argv = @ARGV;
321 }
322
323 # look at each option; if we don't recognize it, maybe the suite-specific
324 # command line parsing code will...
325
326 while (@argv)
327 {
328 $option = shift @argv;
329 if ($option =~ /^-debug$/i)
330 {
331 print "\nDEBUG ON\n";
332 $debug = 1;
333 }
334 elsif ($option =~ /^-usage$/i)
335 {
336 &print_usage;
337 exit 0;
338 }
339 elsif ($option =~ /^-(h|help)$/i)
340 {
341 &print_help;
342 exit 0;
343 }
344 elsif ($option =~ /^-profile$/i)
345 {
346 $profile = 1;
347 }
348 elsif ($option =~ /^-verbose$/i)
349 {
350 $verbose = 1;
351 }
352 elsif ($option =~ /^-detail$/i)
353 {
354 $detail = 1;
355 $verbose = 1;
356 }
357 elsif ($option =~ /^-keep$/i)
358 {
359 $keep = 1;
360 }
361 elsif ($option =~ /^-kmk/i)
362 {
363 $is_kmk = 1;
364 }
365 elsif ($option =~ /^-fast/i)
366 {
367 $is_fast = 1;
368 }
369 elsif (&valid_option($option))
370 {
371 # The suite-defined subroutine takes care of the option
372 }
373 elsif ($option =~ /^-/)
374 {
375 print "Invalid option: $option\n";
376 &print_usage;
377 exit 0;
378 }
379 else # must be the name of a test
380 {
381 $option =~ s/\.pl$//;
382 push(@TESTS,$option);
383 }
384 }
385}
386
387sub max
388{
389 local($num) = shift @_;
390 local($newnum);
391
392 while (@_)
393 {
394 $newnum = shift @_;
395 if ($newnum > $num)
396 {
397 $num = $newnum;
398 }
399 }
400
401 return $num;
402}
403
404sub print_centered
405{
406 local($width, $string) = @_;
407 local($pad);
408
409 if (length ($string))
410 {
411 $pad = " " x ( ($width - length ($string) + 1) / 2);
412 print "$pad$string";
413 }
414}
415
416sub print_banner
417{
418 local($info);
419 local($line);
420 local($len);
421
422 $info = "Running tests for $testee on $osname\n"; # $testee is suite-defined
423 $len = &max (length ($line), length ($testee_version),
424 length ($banner_info), 73) + 5;
425 $line = ("-" x $len) . "\n";
426 if ($len < 78)
427 {
428 $len = 78;
429 }
430
431 &print_centered ($len, $line);
432 &print_centered ($len, $info);
433 &print_centered ($len, $testee_version); # suite-defined
434 &print_centered ($len, $banner_info); # suite-defined
435 &print_centered ($len, $line);
436 print "\n";
437}
438
439sub run_each_test
440{
441 $categories_run = 0;
442
443 foreach $testname (sort @TESTS)
444 {
445 ++$categories_run;
446 $suite_passed = 1; # reset by test on failure
447 $num_of_logfiles = 0;
448 $num_of_tmpfiles = 0;
449 $description = "";
450 $details = "";
451 $old_makefile = undef;
452 $testname =~ s/^$scriptpath$pathsep//;
453 $perl_testname = "$scriptpath$pathsep$testname";
454 $testname =~ s/(\.pl|\.perl)$//;
455 $testpath = "$workpath$pathsep$testname";
456 # Leave enough space in the extensions to append a number, even
457 # though it needs to fit into 8+3 limits.
458 if ($short_filenames) {
459 $logext = 'l';
460 $diffext = 'd';
461 $baseext = 'b';
462 $extext = '';
463 } else {
464 $logext = 'log';
465 $diffext = 'diff';
466 $baseext = 'base';
467 $extext = '.';
468 }
469 $log_filename = "$testpath.$logext";
470 $diff_filename = "$testpath.$diffext";
471 $base_filename = "$testpath.$baseext";
472 $tmp_filename = "$testpath.$tmpfilesuffix";
473
474 &setup_for_test; # suite-defined
475
476 $output = "........................................................ ";
477
478 substr($output,0,length($testname)) = "$testname ";
479
480 print $output;
481
482 # Run the actual test!
483 $tests_run = 0;
484 $tests_passed = 0;
485 $code = do $perl_testname;
486
487 $total_tests_run += $tests_run;
488 $total_tests_passed += $tests_passed;
489
490 # How did it go?
491 if (!defined($code))
492 {
493 $suite_passed = 0;
494 if (length ($@)) {
495 warn "\n*** Test died ($testname): $@\n";
496 } else {
497 warn "\n*** Couldn't run $perl_testname\n";
498 }
499 }
500 elsif ($code == -1) {
501 $suite_passed = 0;
502 }
503 elsif ($code != 1 && $code != -1) {
504 $suite_passed = 0;
505 warn "\n*** Test returned $code\n";
506 }
507
508 if ($suite_passed) {
509 ++$categories_passed;
510 $status = "ok ($tests_passed passed)";
511 for ($i = $num_of_tmpfiles; $i; $i--)
512 {
513 &rmfiles ($tmp_filename . &num_suffix ($i) );
514 }
515
516 for ($i = $num_of_logfiles ? $num_of_logfiles : 1; $i; $i--)
517 {
518 &rmfiles ($log_filename . &num_suffix ($i) );
519 &rmfiles ($base_filename . &num_suffix ($i) );
520 }
521 }
522 elsif (!defined $code || $code > 0) {
523 $status = "FAILED ($tests_passed/$tests_run passed)";
524 }
525 elsif ($code < 0) {
526 $status = "N/A";
527 --$categories_run;
528 }
529
530 # If the verbose option has been specified, then a short description
531 # of each test is printed before displaying the results of each test
532 # describing WHAT is being tested.
533
534 if ($verbose)
535 {
536 if ($detail)
537 {
538 print "\nWHAT IS BEING TESTED\n";
539 print "--------------------";
540 }
541 print "\n\n$description\n\n";
542 }
543
544 # If the detail option has been specified, then the details of HOW
545 # the test is testing what it says it is testing in the verbose output
546 # will be displayed here before the results of the test are displayed.
547
548 if ($detail)
549 {
550 print "\nHOW IT IS TESTED\n";
551 print "----------------";
552 print "\n\n$details\n\n";
553 }
554
555 print "$status\n";
556 }
557}
558
559# If the keep flag is not set, this subroutine deletes all filenames that
560# are sent to it.
561
562sub rmfiles
563{
564 local(@files) = @_;
565
566 if (!$keep)
567 {
568 return (unlink @files);
569 }
570
571 return 1;
572}
573
574sub print_standard_usage
575{
576 local($plname,@moreusage) = @_;
577 local($line);
578
579 print "usage:\t$plname [testname] [-verbose] [-detail] [-keep]\n";
580 print "\t\t\t[-profile] [-usage] [-help] [-debug]\n";
581 foreach (@moreusage) {
582 print "\t\t\t$_\n";
583 }
584}
585
586sub print_standard_help
587{
588 local(@morehelp) = @_;
589 local($line);
590 local($tline);
591 local($t) = " ";
592
593 $line = "Test Driver For $testee";
594 print "$line\n";
595 $line = "=" x length ($line);
596 print "$line\n";
597
598 &print_usage;
599
600 print "\ntestname\n"
601 . "${t}You may, if you wish, run only ONE test if you know the name\n"
602 . "${t}of that test and specify this name anywhere on the command\n"
603 . "${t}line. Otherwise ALL existing tests in the scripts directory\n"
604 . "${t}will be run.\n"
605 . "-verbose\n"
606 . "${t}If this option is given, a description of every test is\n"
607 . "${t}displayed before the test is run. (Not all tests may have\n"
608 . "${t}descriptions at this time)\n"
609 . "-detail\n"
610 . "${t}If this option is given, a detailed description of every\n"
611 . "${t}test is displayed before the test is run. (Not all tests\n"
612 . "${t}have descriptions at this time)\n"
613 . "-profile\n"
614 . "${t}If this option is given, then the profile file\n"
615 . "${t}is added to other profiles every time $testee is run.\n"
616 . "${t}This option only works on VOS at this time.\n"
617 . "-keep\n"
618 . "${t}You may give this option if you DO NOT want ANY\n"
619 . "${t}of the files generated by the tests to be deleted. \n"
620 . "${t}Without this option, all files generated by the test will\n"
621 . "${t}be deleted IF THE TEST PASSES.\n"
622 . "-debug\n"
623 . "${t}Use this option if you would like to see all of the system\n"
624 . "${t}calls issued and their return status while running the tests\n"
625 . "${t}This can be helpful if you're having a problem adding a test\n"
626 . "${t}to the suite, or if the test fails!\n";
627
628 foreach $line (@morehelp)
629 {
630 $tline = $line;
631 if (substr ($tline, 0, 1) eq "\t")
632 {
633 substr ($tline, 0, 1) = $t;
634 }
635 print "$tline\n";
636 }
637}
638
639#######################################################################
640########### Generic Test Driver Subroutines ###########
641#######################################################################
642
643sub get_caller
644{
645 local($depth);
646 local($package);
647 local($filename);
648 local($linenum);
649
650 $depth = defined ($_[0]) ? $_[0] : 1;
651 ($package, $filename, $linenum) = caller ($depth + 1);
652 return "$filename: $linenum";
653}
654
655sub error
656{
657 local($message) = $_[0];
658 local($caller) = &get_caller (1);
659
660 if (defined ($_[1]))
661 {
662 $caller = &get_caller ($_[1] + 1) . " -> $caller";
663 }
664
665 die "$caller: $message";
666}
667
668sub compare_output
669{
670 local($answer,$logfile) = @_;
671 local($slurp, $answer_matched) = ('', 0);
672
673 print "Comparing Output ........ " if $debug;
674
675 $slurp = &read_file_into_string ($logfile);
676
677 # For make, get rid of any time skew error before comparing--too bad this
678 # has to go into the "generic" driver code :-/
679 $slurp =~ s/^.*modification time .*in the future.*\n//gm;
680 $slurp =~ s/^.*Clock skew detected.*\n//gm;
681
682 ++$tests_run;
683
684 if ($slurp eq $answer) {
685 $answer_matched = 1;
686 } else {
687 # See if it is a slash or CRLF problem
688 local ($answer_mod, $slurp_mod) = ($answer, $slurp);
689
690 $answer_mod =~ tr,\\,/,;
691 $answer_mod =~ s,\r\n,\n,gs;
692
693 $slurp_mod =~ tr,\\,/,;
694 $slurp_mod =~ s,\r\n,\n,gs;
695
696 $answer_matched = ($slurp_mod eq $answer_mod);
697
698 # If it still doesn't match, see if the answer might be a regex.
699 if (!$answer_matched && $answer =~ m,^/(.+)/$,) {
700 $answer_matched = ($slurp =~ /$1/);
701 if (!$answer_matched && $answer_mod =~ m,^/(.+)/$,) {
702 $answer_matched = ($slurp_mod =~ /$1/);
703 }
704 }
705 }
706
707 if ($answer_matched && $test_passed)
708 {
709 print "ok\n" if $debug;
710 ++$tests_passed;
711 return 1;
712 }
713
714 if (! $answer_matched) {
715 print "DIFFERENT OUTPUT\n" if $debug;
716
717 &create_file (&get_basefile, $answer);
718
719 print "\nCreating Difference File ...\n" if $debug;
720
721 # Create the difference file
722
723 local($command) = "diff -c " . &get_basefile . " " . $logfile;
724 &run_command_with_output(&get_difffile,$command);
725 }
726
727 $suite_passed = 0;
728 return 0;
729}
730
731sub read_file_into_string
732{
733 local($filename) = @_;
734 local($oldslash) = $/;
735
736 undef $/;
737
738 open (RFISFILE, $filename) || return "";
739 local ($slurp) = <RFISFILE>;
740 close (RFISFILE);
741
742 $/ = $oldslash;
743
744 return $slurp;
745}
746
747sub attach_default_output
748{
749 local ($filename) = @_;
750 local ($code);
751
752 if ($vos)
753 {
754 $code = system "++attach_default_output_hack $filename";
755 $code == -2 || &error ("adoh death\n", 1);
756 return 1;
757 }
758
759 open ("SAVEDOS" . $default_output_stack_level . "out", ">&STDOUT")
760 || &error ("ado: $! duping STDOUT\n", 1);
761 open ("SAVEDOS" . $default_output_stack_level . "err", ">&STDERR")
762 || &error ("ado: $! duping STDERR\n", 1);
763
764 open (STDOUT, "> " . $filename)
765 || &error ("ado: $filename: $!\n", 1);
766 open (STDERR, ">&STDOUT")
767 || &error ("ado: $filename: $!\n", 1);
768
769 $default_output_stack_level++;
770}
771
772# close the current stdout/stderr, and restore the previous ones from
773# the "stack."
774
775sub detach_default_output
776{
777 local ($code);
778
779 if ($vos)
780 {
781 $code = system "++detach_default_output_hack";
782 $code == -2 || &error ("ddoh death\n", 1);
783 return 1;
784 }
785
786 if (--$default_output_stack_level < 0)
787 {
788 &error ("default output stack has flown under!\n", 1);
789 }
790
791 close (STDOUT);
792 close (STDERR);
793
794 open (STDOUT, ">&SAVEDOS" . $default_output_stack_level . "out")
795 || &error ("ddo: $! duping STDOUT\n", 1);
796 open (STDERR, ">&SAVEDOS" . $default_output_stack_level . "err")
797 || &error ("ddo: $! duping STDERR\n", 1);
798
799 close ("SAVEDOS" . $default_output_stack_level . "out")
800 || &error ("ddo: $! closing SCSDOSout\n", 1);
801 close ("SAVEDOS" . $default_output_stack_level . "err")
802 || &error ("ddo: $! closing SAVEDOSerr\n", 1);
803}
804
805# This runs a command without any debugging info.
806sub _run_command
807{
808 my $code;
809
810 # We reset this before every invocation. On Windows I think there is only
811 # one environment, not one per process, so I think that variables set in
812 # test scripts might leak into subsequent tests if this isn't reset--???
813 resetENV();
814
815 eval {
816 local $SIG{ALRM} = sub { die "timeout\n"; };
817 alarm $test_timeout;
818 $code = system @_;
819 alarm 0;
820 };
821 if ($@) {
822 # The eval failed. If it wasn't SIGALRM then die.
823 $@ eq "timeout\n" or die;
824
825 # Timed out. Resend the alarm to our process group to kill the children.
826 $SIG{ALRM} = 'IGNORE';
827 kill -14, $$;
828 $code = 14;
829 }
830
831 return $code;
832}
833
834# run one command (passed as a list of arg 0 - n), returning 0 on success
835# and nonzero on failure.
836
837sub run_command
838{
839 print "\nrun_command: @_\n" if $debug;
840 my $code = _run_command(@_);
841 print "run_command returned $code.\n" if $debug;
842
843 return $code;
844}
845
846# run one command (passed as a list of arg 0 - n, with arg 0 being the
847# second arg to this routine), returning 0 on success and non-zero on failure.
848# The first arg to this routine is a filename to connect to the stdout
849# & stderr of the child process.
850
851sub run_command_with_output
852{
853 my $filename = shift;
854
855 print "\nrun_command_with_output($filename): @_\n" if $debug;
856 &attach_default_output ($filename);
857 my $code = _run_command(@_);
858 &detach_default_output;
859 print "run_command_with_output returned $code.\n" if $debug;
860
861 return $code;
862}
863
864# performs the equivalent of an "rm -rf" on the first argument. Like
865# rm, if the path ends in /, leaves the (now empty) directory; otherwise
866# deletes it, too.
867
868sub remove_directory_tree
869{
870 local ($targetdir) = @_;
871 local ($nuketop) = 1;
872 local ($ch);
873
874 $ch = substr ($targetdir, length ($targetdir) - 1);
875 if ($ch eq "/" || $ch eq $pathsep)
876 {
877 $targetdir = substr ($targetdir, 0, length ($targetdir) - 1);
878 $nuketop = 0;
879 }
880
881 if (! -e $targetdir)
882 {
883 return 1;
884 }
885
886 &remove_directory_tree_inner ("RDT00", $targetdir) || return 0;
887 if ($nuketop)
888 {
889 rmdir $targetdir || return 0;
890 }
891
892 return 1;
893}
894
895sub remove_directory_tree_inner
896{
897 local ($dirhandle, $targetdir) = @_;
898 local ($object);
899 local ($subdirhandle);
900
901 opendir ($dirhandle, $targetdir) || return 0;
902 $subdirhandle = $dirhandle;
903 $subdirhandle++;
904 while ($object = readdir ($dirhandle))
905 {
906 if ($object =~ /^(\.\.?|CVS|RCS)$/)
907 {
908 next;
909 }
910
911 $object = "$targetdir$pathsep$object";
912 lstat ($object);
913
914 if (-d _ && &remove_directory_tree_inner ($subdirhandle, $object))
915 {
916 rmdir $object || return 0;
917 }
918 else
919 {
920 unlink $object || return 0;
921 }
922 }
923 closedir ($dirhandle);
924 return 1;
925}
926
927# We used to use this behavior for this function:
928#
929#sub touch
930#{
931# local (@filenames) = @_;
932# local ($now) = time;
933# local ($file);
934#
935# foreach $file (@filenames)
936# {
937# utime ($now, $now, $file)
938# || (open (TOUCHFD, ">> $file") && close (TOUCHFD))
939# || &error ("Couldn't touch $file: $!\n", 1);
940# }
941# return 1;
942#}
943#
944# But this behaves badly on networked filesystems where the time is
945# skewed, because it sets the time of the file based on the _local_
946# host. Normally when you modify a file, it's the _remote_ host that
947# determines the modtime, based on _its_ clock. So, instead, now we open
948# the file and write something into it to force the remote host to set
949# the modtime correctly according to its clock.
950#
951
952sub touch
953{
954 local ($file);
955
956 foreach $file (@_) {
957 (open(T, ">> $file") && print(T "\n") && close(T))
958 || &error("Couldn't touch $file: $!\n", 1);
959 }
960}
961
962# Touch with a time offset. To DTRT, call touch() then use stat() to get the
963# access/mod time for each file and apply the offset.
964
965sub utouch
966{
967 local ($off) = shift;
968 local ($file);
969
970 &touch(@_);
971
972 local (@s) = stat($_[0]);
973
974 utime($s[8]+$off, $s[9]+$off, @_);
975}
976
977# open a file, write some stuff to it, and close it.
978
979sub create_file
980{
981 local ($filename, @lines) = @_;
982
983 open (CF, "> $filename") || &error ("Couldn't open $filename: $!\n", 1);
984 foreach $line (@lines)
985 {
986 print CF $line;
987 }
988 close (CF);
989}
990
991# create a directory tree described by an associative array, wherein each
992# key is a relative pathname (using slashes) and its associated value is
993# one of:
994# DIR indicates a directory
995# FILE:contents indicates a file, which should contain contents +\n
996# LINK:target indicates a symlink, pointing to $basedir/target
997# The first argument is the dir under which the structure will be created
998# (the dir will be made and/or cleaned if necessary); the second argument
999# is the associative array.
1000
1001sub create_dir_tree
1002{
1003 local ($basedir, %dirtree) = @_;
1004 local ($path);
1005
1006 &remove_directory_tree ("$basedir");
1007 mkdir ($basedir, 0777) || &error ("Couldn't mkdir $basedir: $!\n", 1);
1008
1009 foreach $path (sort keys (%dirtree))
1010 {
1011 if ($dirtree {$path} =~ /^DIR$/)
1012 {
1013 mkdir ("$basedir/$path", 0777)
1014 || &error ("Couldn't mkdir $basedir/$path: $!\n", 1);
1015 }
1016 elsif ($dirtree {$path} =~ /^FILE:(.*)$/)
1017 {
1018 &create_file ("$basedir/$path", $1 . "\n");
1019 }
1020 elsif ($dirtree {$path} =~ /^LINK:(.*)$/)
1021 {
1022 symlink ("$basedir/$1", "$basedir/$path")
1023 || &error ("Couldn't symlink $basedir/$path -> $basedir/$1: $!\n", 1);
1024 }
1025 else
1026 {
1027 &error ("Bogus dirtree type: \"$dirtree{$path}\"\n", 1);
1028 }
1029 }
1030 if ($just_setup_tree)
1031 {
1032 die "Tree is setup...\n";
1033 }
1034}
1035
1036# compare a directory tree with an associative array in the format used
1037# by create_dir_tree, above.
1038# The first argument is the dir under which the structure should be found;
1039# the second argument is the associative array.
1040
1041sub compare_dir_tree
1042{
1043 local ($basedir, %dirtree) = @_;
1044 local ($path);
1045 local ($i);
1046 local ($bogus) = 0;
1047 local ($contents);
1048 local ($target);
1049 local ($fulltarget);
1050 local ($found);
1051 local (@files);
1052 local (@allfiles);
1053
1054 opendir (DIR, $basedir) || &error ("Couldn't open $basedir: $!\n", 1);
1055 @allfiles = grep (!/^(\.\.?|CVS|RCS)$/, readdir (DIR) );
1056 closedir (DIR);
1057 if ($debug)
1058 {
1059 print "dirtree: (%dirtree)\n$basedir: (@allfiles)\n";
1060 }
1061
1062 foreach $path (sort keys (%dirtree))
1063 {
1064 if ($debug)
1065 {
1066 print "Checking $path ($dirtree{$path}).\n";
1067 }
1068
1069 $found = 0;
1070 foreach $i (0 .. $#allfiles)
1071 {
1072 if ($allfiles[$i] eq $path)
1073 {
1074 splice (@allfiles, $i, 1); # delete it
1075 if ($debug)
1076 {
1077 print " Zapped $path; files now (@allfiles).\n";
1078 }
1079 lstat ("$basedir/$path");
1080 $found = 1;
1081 last;
1082 }
1083 }
1084
1085 if (!$found)
1086 {
1087 print "compare_dir_tree: $path does not exist.\n";
1088 $bogus = 1;
1089 next;
1090 }
1091
1092 if ($dirtree {$path} =~ /^DIR$/)
1093 {
1094 if (-d _ && opendir (DIR, "$basedir/$path") )
1095 {
1096 @files = readdir (DIR);
1097 closedir (DIR);
1098 @files = grep (!/^(\.\.?|CVS|RCS)$/ && ($_ = "$path/$_"), @files);
1099 push (@allfiles, @files);
1100 if ($debug)
1101 {
1102 print " Read in $path; new files (@files).\n";
1103 }
1104 }
1105 else
1106 {
1107 print "compare_dir_tree: $path is not a dir.\n";
1108 $bogus = 1;
1109 }
1110 }
1111 elsif ($dirtree {$path} =~ /^FILE:(.*)$/)
1112 {
1113 if (-l _ || !-f _)
1114 {
1115 print "compare_dir_tree: $path is not a file.\n";
1116 $bogus = 1;
1117 next;
1118 }
1119
1120 if ($1 ne "*")
1121 {
1122 $contents = &read_file_into_string ("$basedir/$path");
1123 if ($contents ne "$1\n")
1124 {
1125 print "compare_dir_tree: $path contains wrong stuff."
1126 . " Is:\n$contentsShould be:\n$1\n";
1127 $bogus = 1;
1128 }
1129 }
1130 }
1131 elsif ($dirtree {$path} =~ /^LINK:(.*)$/)
1132 {
1133 $target = $1;
1134 if (!-l _)
1135 {
1136 print "compare_dir_tree: $path is not a link.\n";
1137 $bogus = 1;
1138 next;
1139 }
1140
1141 $contents = readlink ("$basedir/$path");
1142 $contents =~ tr/>/\//;
1143 $fulltarget = "$basedir/$target";
1144 $fulltarget =~ tr/>/\//;
1145 if (!($contents =~ /$fulltarget$/))
1146 {
1147 if ($debug)
1148 {
1149 $target = $fulltarget;
1150 }
1151 print "compare_dir_tree: $path should be link to $target, "
1152 . "not $contents.\n";
1153 $bogus = 1;
1154 }
1155 }
1156 else
1157 {
1158 &error ("Bogus dirtree type: \"$dirtree{$path}\"\n", 1);
1159 }
1160 }
1161
1162 if ($debug)
1163 {
1164 print "leftovers: (@allfiles).\n";
1165 }
1166
1167 foreach $file (@allfiles)
1168 {
1169 print "compare_dir_tree: $file should not exist.\n";
1170 $bogus = 1;
1171 }
1172
1173 return !$bogus;
1174}
1175
1176# this subroutine generates the numeric suffix used to keep tmp filenames,
1177# log filenames, etc., unique. If the number passed in is 1, then a null
1178# string is returned; otherwise, we return ".n", where n + 1 is the number
1179# we were given.
1180
1181sub num_suffix
1182{
1183 local($num) = @_;
1184
1185 if (--$num > 0) {
1186 return "$extext$num";
1187 }
1188
1189 return "";
1190}
1191
1192# This subroutine returns a log filename with a number appended to
1193# the end corresponding to how many logfiles have been created in the
1194# current running test. An optional parameter may be passed (0 or 1).
1195# If a 1 is passed, then it does NOT increment the logfile counter
1196# and returns the name of the latest logfile. If either no parameter
1197# is passed at all or a 0 is passed, then the logfile counter is
1198# incremented and the new name is returned.
1199
1200sub get_logfile
1201{
1202 local($no_increment) = @_;
1203
1204 $num_of_logfiles += !$no_increment;
1205
1206 return ($log_filename . &num_suffix ($num_of_logfiles));
1207}
1208
1209# This subroutine returns a base (answer) filename with a number
1210# appended to the end corresponding to how many logfiles (and thus
1211# base files) have been created in the current running test.
1212# NO PARAMETERS ARE PASSED TO THIS SUBROUTINE.
1213
1214sub get_basefile
1215{
1216 return ($base_filename . &num_suffix ($num_of_logfiles));
1217}
1218
1219# This subroutine returns a difference filename with a number appended
1220# to the end corresponding to how many logfiles (and thus diff files)
1221# have been created in the current running test.
1222
1223sub get_difffile
1224{
1225 return ($diff_filename . &num_suffix ($num_of_logfiles));
1226}
1227
1228# just like logfile, only a generic tmp filename for use by the test.
1229# they are automatically cleaned up unless -keep was used, or the test fails.
1230# Pass an argument of 1 to return the same filename as the previous call.
1231
1232sub get_tmpfile
1233{
1234 local($no_increment) = @_;
1235
1236 $num_of_tmpfiles += !$no_increment;
1237
1238 return ($tmp_filename . &num_suffix ($num_of_tmpfiles));
1239}
1240
12411;
Note: See TracBrowser for help on using the repository browser.

© 2024 Oracle Support Privacy / Do Not Sell My Info Terms of Use Trademark Policy Automated Access Etiquette