Commit 3334cdf38719ad3fc45d6d311931b5b545a270db
1 parent
9f45538c
update qtest to 1.4
git-svn-id: svn+q:///qpdf/trunk@800 71b93d88-0707-0410-a8cf-f5a4172ac649
Showing
2 changed files
with
265 additions
and
100 deletions
qtest/bin/qtest-driver
| @@ -33,7 +33,7 @@ require TestDriver; | @@ -33,7 +33,7 @@ require TestDriver; | ||
| 33 | 33 | ||
| 34 | if ((@ARGV == 1) && ($ARGV[0] eq '--version')) | 34 | if ((@ARGV == 1) && ($ARGV[0] eq '--version')) |
| 35 | { | 35 | { |
| 36 | - print "$whoami version 1.3\n"; | 36 | + print "$whoami version 1.4\n"; |
| 37 | exit 0; | 37 | exit 0; |
| 38 | } | 38 | } |
| 39 | if ((@ARGV == 1) && ($ARGV[0] eq '--print-path')) | 39 | if ((@ARGV == 1) && ($ARGV[0] eq '--print-path')) |
| @@ -84,7 +84,8 @@ if (@bindirs) | @@ -84,7 +84,8 @@ if (@bindirs) | ||
| 84 | fatal("can't canonicalize path to bindir $d: $!"); | 84 | fatal("can't canonicalize path to bindir $d: $!"); |
| 85 | push(@path, $abs); | 85 | push(@path, $abs); |
| 86 | } | 86 | } |
| 87 | - my $path = join(':', @path) . ':' . $ENV{'PATH'}; | 87 | + my $sep = ($^O eq 'MSWin32' ? ';' : ':'); |
| 88 | + my $path = join($sep, @path) . $sep . $ENV{'PATH'}; | ||
| 88 | # Delete and explicitly recreate the PATH environment variable. | 89 | # Delete and explicitly recreate the PATH environment variable. |
| 89 | # This seems to be more reliable. If we just reassign, in some | 90 | # This seems to be more reliable. If we just reassign, in some |
| 90 | # cases, the modified environment is not inherited by the child | 91 | # cases, the modified environment is not inherited by the child |
| @@ -112,8 +113,18 @@ $ENV{'IN_TESTSUITE'} = 1; | @@ -112,8 +113,18 @@ $ENV{'IN_TESTSUITE'} = 1; | ||
| 112 | # be inspected by impatient test suite runners. It is not intended to | 113 | # be inspected by impatient test suite runners. It is not intended to |
| 113 | # be a "secure" (unpredictable) path. | 114 | # be a "secure" (unpredictable) path. |
| 114 | my $tempdir = File::Spec->tmpdir() . "/testtemp.$$"; | 115 | my $tempdir = File::Spec->tmpdir() . "/testtemp.$$"; |
| 116 | +my $thispid = $$; | ||
| 115 | 117 | ||
| 116 | -my $file_cleanup = new TestDriver::TmpFileDeleter([$tempdir]); | 118 | +END |
| 119 | +{ | ||
| 120 | + # We have to make sure we don't call this from the child | ||
| 121 | + # qtest-driver when fork is called. | ||
| 122 | + if ((defined $thispid) && ($$ == $thispid) && (defined $tempdir)) | ||
| 123 | + { | ||
| 124 | + local $?; | ||
| 125 | + TestDriver::rmrf($tempdir) if -d $tempdir; | ||
| 126 | + } | ||
| 127 | +} | ||
| 117 | 128 | ||
| 118 | $| = 1; | 129 | $| = 1; |
| 119 | $SIG{'PIPE'} = 'IGNORE'; | 130 | $SIG{'PIPE'} = 'IGNORE'; |
| @@ -471,6 +482,7 @@ sub parse_tc_file | @@ -471,6 +482,7 @@ sub parse_tc_file | ||
| 471 | return unless defined $tc_input; | 482 | return unless defined $tc_input; |
| 472 | 483 | ||
| 473 | my $tc = new IO::File("<$tc_input") or fatal("can't read $tc_input: $!"); | 484 | my $tc = new IO::File("<$tc_input") or fatal("can't read $tc_input: $!"); |
| 485 | + binmode $tc; | ||
| 474 | while (<$tc>) | 486 | while (<$tc>) |
| 475 | { | 487 | { |
| 476 | s/\r?\n$//s; | 488 | s/\r?\n$//s; |
| @@ -480,7 +492,7 @@ sub parse_tc_file | @@ -480,7 +492,7 @@ sub parse_tc_file | ||
| 480 | { | 492 | { |
| 481 | $tc_ignored_scopes{$1} = 1; | 493 | $tc_ignored_scopes{$1} = 1; |
| 482 | } | 494 | } |
| 483 | - elsif (m/^\s*?(\S.+?)\s+(\d+)$/) | 495 | + elsif (m/^\s*?(\S.+?)\s+(\d+)\s*$/) |
| 484 | { | 496 | { |
| 485 | my ($case, $n) = ($1, $2); | 497 | my ($case, $n) = ($1, $2); |
| 486 | if (exists $tc_cases{$case}) | 498 | if (exists $tc_cases{$case}) |
| @@ -602,6 +614,7 @@ sub tc_do_final_checks | @@ -602,6 +614,7 @@ sub tc_do_final_checks | ||
| 602 | 614 | ||
| 603 | my %seen_cases = (); | 615 | my %seen_cases = (); |
| 604 | my $tc = new IO::File("<$tc_log"); | 616 | my $tc = new IO::File("<$tc_log"); |
| 617 | + binmode $tc; | ||
| 605 | if ($tc) | 618 | if ($tc) |
| 606 | { | 619 | { |
| 607 | binmode $tc; | 620 | binmode $tc; |
| @@ -610,7 +623,7 @@ sub tc_do_final_checks | @@ -610,7 +623,7 @@ sub tc_do_final_checks | ||
| 610 | s/\r?\n$//s; | 623 | s/\r?\n$//s; |
| 611 | next if m/^\#/; | 624 | next if m/^\#/; |
| 612 | next if m/^\s*$/; | 625 | next if m/^\s*$/; |
| 613 | - if (m/^(.+) (\d+)$/) | 626 | + if (m/^(.+) (\d+)\s*$/) |
| 614 | { | 627 | { |
| 615 | $seen_cases{$1}{$2} = 1; | 628 | $seen_cases{$1}{$2} = 1; |
| 616 | } | 629 | } |
qtest/module/TestDriver.pm
| @@ -34,27 +34,6 @@ sub DESTROY | @@ -34,27 +34,6 @@ sub DESTROY | ||
| 34 | defined($$pid) && $$pid && kill 15, $$pid; | 34 | defined($$pid) && $$pid && kill 15, $$pid; |
| 35 | } | 35 | } |
| 36 | 36 | ||
| 37 | -package TestDriver::TmpFileDeleter; | ||
| 38 | - | ||
| 39 | -use vars qw($f_files); | ||
| 40 | -$f_files = 'files'; | ||
| 41 | - | ||
| 42 | -sub new | ||
| 43 | -{ | ||
| 44 | - my $class = shift; | ||
| 45 | - my $rep = +{+__PACKAGE__ => {} }; | ||
| 46 | - $rep->{+__PACKAGE__}{$f_files} = shift; | ||
| 47 | - bless $rep, $class; | ||
| 48 | -} | ||
| 49 | - | ||
| 50 | -sub DESTROY | ||
| 51 | -{ | ||
| 52 | - local $?; | ||
| 53 | - my $rep = shift; | ||
| 54 | - my $files = ($rep->{+__PACKAGE__}{$f_files}); | ||
| 55 | - map { TestDriver::rmrf($_) } @$files; | ||
| 56 | -} | ||
| 57 | - | ||
| 58 | package TestDriver; | 37 | package TestDriver; |
| 59 | 38 | ||
| 60 | use IO::Handle; | 39 | use IO::Handle; |
| @@ -122,6 +101,14 @@ my $color_red = ""; | @@ -122,6 +101,14 @@ my $color_red = ""; | ||
| 122 | my $color_magenta = ""; | 101 | my $color_magenta = ""; |
| 123 | my $color_emph = ""; | 102 | my $color_emph = ""; |
| 124 | 103 | ||
| 104 | +# MSWin32 support | ||
| 105 | +my $in_windows = 0; | ||
| 106 | +my $winbin = undef; | ||
| 107 | +if ($^O eq 'MSWin32') | ||
| 108 | +{ | ||
| 109 | + $in_windows = 1; | ||
| 110 | +} | ||
| 111 | + | ||
| 125 | sub get_tty_features | 112 | sub get_tty_features |
| 126 | { | 113 | { |
| 127 | my $got_size = 0; | 114 | my $got_size = 0; |
| @@ -157,6 +144,17 @@ sub get_tty_features | @@ -157,6 +144,17 @@ sub get_tty_features | ||
| 157 | } | 144 | } |
| 158 | eval | 145 | eval |
| 159 | { | 146 | { |
| 147 | + if ($in_windows) | ||
| 148 | + { | ||
| 149 | + eval | ||
| 150 | + { | ||
| 151 | + # If you don't have this module, you may want to set | ||
| 152 | + # the environment variable ANSI_COLORS_DISABLED to 1 | ||
| 153 | + # to avoid "garbage" output around PASSED, FAILED, | ||
| 154 | + # etc. | ||
| 155 | + require Win32::Console::ANSI; | ||
| 156 | + } | ||
| 157 | + } | ||
| 160 | require Term::ANSIColor; | 158 | require Term::ANSIColor; |
| 161 | $color_reset = Term::ANSIColor::RESET(); | 159 | $color_reset = Term::ANSIColor::RESET(); |
| 162 | $color_green = Term::ANSIColor::GREEN(); | 160 | $color_green = Term::ANSIColor::GREEN(); |
| @@ -243,7 +241,8 @@ sub new | @@ -243,7 +241,8 @@ sub new | ||
| 243 | ($ARGV[10] =~ m/^-stdout-tty=([01])$/) && | 241 | ($ARGV[10] =~ m/^-stdout-tty=([01])$/) && |
| 244 | (-d $ARGV[5]))) | 242 | (-d $ARGV[5]))) |
| 245 | { | 243 | { |
| 246 | - die +__PACKAGE__, ": improper invocation of test driver $0\n"; | 244 | + die +__PACKAGE__, ": improper invocation of test driver $0 (" . |
| 245 | + join(' ', @ARGV) . ")\n"; | ||
| 247 | } | 246 | } |
| 248 | my $fd = ($ARGV[0] eq '-fd') ? $ARGV[1] : undef; | 247 | my $fd = ($ARGV[0] eq '-fd') ? $ARGV[1] : undef; |
| 249 | my $port = ($ARGV[0] eq '-port') ? $ARGV[1] : undef; | 248 | my $port = ($ARGV[0] eq '-port') ? $ARGV[1] : undef; |
| @@ -435,7 +434,9 @@ sub prompt | @@ -435,7 +434,9 @@ sub prompt | ||
| 435 | { | 434 | { |
| 436 | print "To avoid question, place answer in" . | 435 | print "To avoid question, place answer in" . |
| 437 | " environment variable \$$env\n"; | 436 | " environment variable \$$env\n"; |
| 438 | - if (-t STDIN) | 437 | + # Note: ActiveState perl 5.10.1 gives the wrong answer for -t |
| 438 | + # STDIN. | ||
| 439 | + if ((-t STDIN) && (-t STDOUT)) | ||
| 439 | { | 440 | { |
| 440 | print "$msg "; | 441 | print "$msg "; |
| 441 | chop($answer = <STDIN>); | 442 | chop($answer = <STDIN>); |
| @@ -506,10 +507,13 @@ sub get_start_dir | @@ -506,10 +507,13 @@ sub get_start_dir | ||
| 506 | 507 | ||
| 507 | # EXIT_STATUS: the exit status of the command. Required iff the | 508 | # EXIT_STATUS: the exit status of the command. Required iff the |
| 508 | # intput is specified by COMMAND. A value of undef means that we | 509 | # intput is specified by COMMAND. A value of undef means that we |
| 509 | -# don't care about the exit status of a command. An integer | ||
| 510 | -# value is the ordinary exit status of a command. A string of | ||
| 511 | -# the form SIG:n indicates that the program has exited with | ||
| 512 | -# signal n. | 510 | +# don't care about the exit status of a command. The special |
| 511 | +# value of '!0' means we allow any abnormal exit status but we | ||
| 512 | +# don't care what the specific exit status is. An integer value | ||
| 513 | +# is the ordinary exit status of a command. A string of the form | ||
| 514 | +# SIG:n indicates that the program has exited with signal n. | ||
| 515 | +# Note that SIG:n is not reliable in a Windows (non-Cygwin) | ||
| 516 | +# environment. | ||
| 513 | 517 | ||
| 514 | # THREAD_DATA: If specified, the test output is expected to | 518 | # THREAD_DATA: If specified, the test output is expected to |
| 515 | # contain multithreaded output with output lines marked by thread | 519 | # contain multithreaded output with output lines marked by thread |
| @@ -674,7 +678,7 @@ sub runtest | @@ -674,7 +678,7 @@ sub runtest | ||
| 674 | my $pid = undef; | 678 | my $pid = undef; |
| 675 | my $pid_killer = new TestDriver::PidKiller(\$pid); | 679 | my $pid_killer = new TestDriver::PidKiller(\$pid); |
| 676 | my $in = new IO::Handle; | 680 | my $in = new IO::Handle; |
| 677 | - my $use_tempfile = ($^O eq 'MSWin32'); | 681 | + my $use_tempfile = $in_windows; |
| 678 | my $tempout_status = undef; | 682 | my $tempout_status = undef; |
| 679 | if (defined $in_string) | 683 | if (defined $in_string) |
| 680 | { | 684 | { |
| @@ -692,60 +696,48 @@ sub runtest | @@ -692,60 +696,48 @@ sub runtest | ||
| 692 | } | 696 | } |
| 693 | elsif (defined $in_command) | 697 | elsif (defined $in_command) |
| 694 | { | 698 | { |
| 695 | - my $tempfilename = "$tempdir/tempout"; | ||
| 696 | - my $tempfile = undef; | ||
| 697 | - if ($use_tempfile) | 699 | + if (ref($in_command) eq 'ARRAY') |
| 698 | { | 700 | { |
| 699 | - $tempfile = new IO::File(">$tempfilename") or | ||
| 700 | - die +(+__PACKAGE__, | ||
| 701 | - "->runtest: unable to create $tempfilename: $!\n"); | ||
| 702 | - $pid = fork; | ||
| 703 | - croak +__PACKAGE__, "->runtest: fork failed: $!\n" | ||
| 704 | - unless defined $pid; | 701 | + &QTC::TC("testdriver", "TestDriver input command array"); |
| 705 | } | 702 | } |
| 706 | - else | 703 | + elsif (ref($in_command) eq '') |
| 707 | { | 704 | { |
| 708 | - $pid = open($in, "-|"); | ||
| 709 | - croak +__PACKAGE__, "->runtest: fork failed: $!\n" | ||
| 710 | - unless defined $pid; | 705 | + &QTC::TC("testdriver", "TestDriver input command string"); |
| 711 | } | 706 | } |
| 712 | - if ($pid == 0) | 707 | + |
| 708 | + if ($use_tempfile) | ||
| 713 | { | 709 | { |
| 714 | - # child | ||
| 715 | - if (defined $tempfile) | ||
| 716 | - { | ||
| 717 | - open(STDOUT, ">&", $tempfile); | ||
| 718 | - } | ||
| 719 | - open(STDERR, ">&STDOUT"); | ||
| 720 | - open(STDIN, '<', \ ""); | ||
| 721 | - if (ref($in_command) eq 'ARRAY') | ||
| 722 | - { | ||
| 723 | - &QTC::TC("testdriver", "TestDriver input command array"); | ||
| 724 | - exec @$in_command or | ||
| 725 | - croak+(+__PACKAGE__, | ||
| 726 | - "->runtest: unable to run command ", | ||
| 727 | - join(' ', @$in_command), "\n"); | ||
| 728 | - } | ||
| 729 | - else | ||
| 730 | - { | ||
| 731 | - &QTC::TC("testdriver", "TestDriver input command string"); | ||
| 732 | - exec $in_command or | ||
| 733 | - croak+(+__PACKAGE__, | ||
| 734 | - "->runtest: unable to run command ", | ||
| 735 | - $in_command, "\n"); | ||
| 736 | - } | 710 | + my $tempout = "$tempdir/tempout"; |
| 711 | + $tempout_status = $rep->winrun( | ||
| 712 | + $in_command, File::Spec->devnull(), $tempout); | ||
| 713 | + open($in, "<$tempout") or | ||
| 714 | + croak +(+__PACKAGE__, | ||
| 715 | + "->runtest: unable to read from" . | ||
| 716 | + " input file $tempout: $!\n"); | ||
| 737 | } | 717 | } |
| 738 | else | 718 | else |
| 739 | { | 719 | { |
| 740 | - if (defined $tempfile) | 720 | + $pid = open($in, "-|"); |
| 721 | + croak +__PACKAGE__, "->runtest: fork failed: $!\n" | ||
| 722 | + unless defined $pid; | ||
| 723 | + if ($pid == 0) | ||
| 741 | { | 724 | { |
| 742 | - waitpid($pid, 0); | ||
| 743 | - $tempout_status = $?; | ||
| 744 | - $pid = undef; | ||
| 745 | - open($in, "<$tempfilename") or | ||
| 746 | - croak +(+__PACKAGE__, | ||
| 747 | - "->runtest: unable to read from" . | ||
| 748 | - " input file $tempfilename: $!\n"); | 725 | + open(STDERR, ">&STDOUT"); |
| 726 | + open(STDIN, '<', \ ""); | ||
| 727 | + if (ref($in_command) eq 'ARRAY') | ||
| 728 | + { | ||
| 729 | + exec @$in_command or | ||
| 730 | + croak+(+__PACKAGE__, | ||
| 731 | + "->runtest: unable to run command ", | ||
| 732 | + join(' ', @$in_command), "\n"); | ||
| 733 | + } | ||
| 734 | + else | ||
| 735 | + { | ||
| 736 | + exec $in_command or | ||
| 737 | + croak+(+__PACKAGE__, | ||
| 738 | + "->runtest: unable to run command ", | ||
| 739 | + $in_command, "\n"); | ||
| 740 | + } | ||
| 749 | } | 741 | } |
| 750 | } | 742 | } |
| 751 | } | 743 | } |
| @@ -758,21 +750,46 @@ sub runtest | @@ -758,21 +750,46 @@ sub runtest | ||
| 758 | # Open file handle into which to write the actual output | 750 | # Open file handle into which to write the actual output |
| 759 | my $actual = new IO::File; | 751 | my $actual = new IO::File; |
| 760 | my $actual_file = "$tempdir/actual"; | 752 | my $actual_file = "$tempdir/actual"; |
| 753 | + | ||
| 761 | if (defined $in_filter) | 754 | if (defined $in_filter) |
| 762 | { | 755 | { |
| 763 | &QTC::TC("testdriver", "TestDriver filter defined"); | 756 | &QTC::TC("testdriver", "TestDriver filter defined"); |
| 757 | + if ($use_tempfile) | ||
| 758 | + { | ||
| 759 | + my $filter_file = "$tempdir/filter"; | ||
| 760 | + open(F, ">$filter_file.1") or | ||
| 761 | + croak+(+__PACKAGE__, | ||
| 762 | + "->runtest: unable to create $filter_file.1: $!\n"); | ||
| 763 | + binmode F; | ||
| 764 | + while (<$in>) | ||
| 765 | + { | ||
| 766 | + print F; | ||
| 767 | + } | ||
| 768 | + $in->close(); | ||
| 769 | + close(F); | ||
| 770 | + $rep->winrun($in_filter, "$filter_file.1", $filter_file); | ||
| 771 | + open($in, "<$filter_file") or | ||
| 772 | + croak +(+__PACKAGE__, | ||
| 773 | + "->runtest: unable to read from" . | ||
| 774 | + " input file $filter_file: $!\n"); | ||
| 775 | + binmode $in; | ||
| 776 | + $in_filter = undef; | ||
| 777 | + } | ||
| 778 | + } | ||
| 779 | + if (defined $in_filter) | ||
| 780 | + { | ||
| 764 | # Write through filter to actual file | 781 | # Write through filter to actual file |
| 765 | open($actual, "| $in_filter > $actual_file") or | 782 | open($actual, "| $in_filter > $actual_file") or |
| 766 | - croak +(+__PACKAGE__, ": pipe to filter $in_filter failed: $!\n"); | ||
| 767 | - binmode $actual; | 783 | + croak +(+__PACKAGE__, |
| 784 | + ": pipe to filter $in_filter failed: $!\n"); | ||
| 768 | } | 785 | } |
| 769 | else | 786 | else |
| 770 | { | 787 | { |
| 771 | &QTC::TC("testdriver", "TestDriver filter not defined"); | 788 | &QTC::TC("testdriver", "TestDriver filter not defined"); |
| 772 | open($actual, ">$actual_file") or | 789 | open($actual, ">$actual_file") or |
| 773 | die +(+__PACKAGE__, ": write to $actual_file failed: $!\n"); | 790 | die +(+__PACKAGE__, ": write to $actual_file failed: $!\n"); |
| 774 | - binmode $actual; | ||
| 775 | } | 791 | } |
| 792 | + binmode $actual; | ||
| 776 | 793 | ||
| 777 | # Write from input to actual output, normalizing spaces and | 794 | # Write from input to actual output, normalizing spaces and |
| 778 | # newlines if needed | 795 | # newlines if needed |
| @@ -815,16 +832,43 @@ sub runtest | @@ -815,16 +832,43 @@ sub runtest | ||
| 815 | { | 832 | { |
| 816 | $exit_status = $?; | 833 | $exit_status = $?; |
| 817 | } | 834 | } |
| 818 | - if (WIFSIGNALED($exit_status)) | 835 | + my $exit_status_number = 0; |
| 836 | + my $exit_status_signal = 0; | ||
| 837 | + if ($in_windows) | ||
| 819 | { | 838 | { |
| 820 | - &QTC::TC("testdriver", "TestDriver exit status signal"); | 839 | + # WIFSIGNALED et al are not defined. This is emperically |
| 840 | + # what happens with MSYS 1.0.11 and ActiveState Perl | ||
| 841 | + # 5.10.1. | ||
| 842 | + if ($exit_status & 0x8000) | ||
| 843 | + { | ||
| 844 | + $exit_status_signal = 1; | ||
| 845 | + $exit_status = ($exit_status & 0xfff) >> 8; | ||
| 846 | + $exit_status = "SIG:$exit_status"; | ||
| 847 | + } | ||
| 848 | + elsif ($exit_status >= 256) | ||
| 849 | + { | ||
| 850 | + $exit_status_number = 1; | ||
| 851 | + $exit_status = $exit_status >> 8; | ||
| 852 | + } | ||
| 853 | + } | ||
| 854 | + elsif (WIFSIGNALED($exit_status)) | ||
| 855 | + { | ||
| 856 | + $exit_status_signal = 1; | ||
| 821 | $exit_status = "SIG:" . WTERMSIG($exit_status); | 857 | $exit_status = "SIG:" . WTERMSIG($exit_status); |
| 822 | } | 858 | } |
| 823 | elsif (WIFEXITED($exit_status)) | 859 | elsif (WIFEXITED($exit_status)) |
| 824 | { | 860 | { |
| 825 | - &QTC::TC("testdriver", "TestDriver exit status number"); | 861 | + $exit_status_number = 1; |
| 826 | $exit_status = WEXITSTATUS($exit_status); | 862 | $exit_status = WEXITSTATUS($exit_status); |
| 827 | } | 863 | } |
| 864 | + if ($exit_status_number) | ||
| 865 | + { | ||
| 866 | + &QTC::TC("testdriver", "TestDriver exit status number"); | ||
| 867 | + } | ||
| 868 | + if ($exit_status_signal) | ||
| 869 | + { | ||
| 870 | + &QTC::TC("testdriver", "TestDriver exit status signal"); | ||
| 871 | + } | ||
| 828 | } | 872 | } |
| 829 | $? = 0; | 873 | $? = 0; |
| 830 | $actual->close(); | 874 | $actual->close(); |
| @@ -837,9 +881,15 @@ sub runtest | @@ -837,9 +881,15 @@ sub runtest | ||
| 837 | 881 | ||
| 838 | # Compare exit statuses. This expression is always true when the | 882 | # Compare exit statuses. This expression is always true when the |
| 839 | # input was not from a command. | 883 | # input was not from a command. |
| 840 | - my $status_match = ((! defined $out_exit_status) || | ||
| 841 | - ((defined $exit_status) && | ||
| 842 | - ($exit_status eq $out_exit_status))); | 884 | + if ((defined $out_exit_status) && ($out_exit_status eq '!0')) |
| 885 | + { | ||
| 886 | + &QTC::TC("testdriver", "TestDriver non-zero exit status"); | ||
| 887 | + } | ||
| 888 | + my $status_match = | ||
| 889 | + ((! defined $out_exit_status) || | ||
| 890 | + ((defined $exit_status) && | ||
| 891 | + ( (($out_exit_status eq '!0') && ($exit_status ne 0)) || | ||
| 892 | + ($exit_status eq $out_exit_status) ))); | ||
| 843 | 893 | ||
| 844 | # Compare actual output with expected output. | 894 | # Compare actual output with expected output. |
| 845 | my $expected_file = undef; | 895 | my $expected_file = undef; |
| @@ -923,9 +973,9 @@ sub runtest | @@ -923,9 +973,9 @@ sub runtest | ||
| 923 | else | 973 | else |
| 924 | { | 974 | { |
| 925 | $output_diff = "$tempdir/difference"; | 975 | $output_diff = "$tempdir/difference"; |
| 926 | - my $r = safe_pipe(['diff', '-a', '-u', | ||
| 927 | - $expected_file, $actual_file], | ||
| 928 | - $output_diff); | 976 | + my $r = $rep->safe_pipe(['diff', '-a', '-u', |
| 977 | + $expected_file, $actual_file], | ||
| 978 | + $output_diff); | ||
| 929 | $output_match = ($r == 0); | 979 | $output_match = ($r == 0); |
| 930 | } | 980 | } |
| 931 | } | 981 | } |
| @@ -1228,6 +1278,7 @@ sub print_testid | @@ -1228,6 +1278,7 @@ sub print_testid | ||
| 1228 | my $tc_filename = $ENV{'TC_FILENAME'} || ""; | 1278 | my $tc_filename = $ENV{'TC_FILENAME'} || ""; |
| 1229 | if ($tc_filename && open(F, ">>$tc_filename")) | 1279 | if ($tc_filename && open(F, ">>$tc_filename")) |
| 1230 | { | 1280 | { |
| 1281 | + binmode F; | ||
| 1231 | printf F "# $category %2d (%s)\n", $testnum, $description; | 1282 | printf F "# $category %2d (%s)\n", $testnum, $description; |
| 1232 | close(F); | 1283 | close(F); |
| 1233 | } | 1284 | } |
| @@ -1331,6 +1382,7 @@ sub analyze_threaded_output | @@ -1331,6 +1382,7 @@ sub analyze_threaded_output | ||
| 1331 | my ($file, $threads, $seqgroups, $errors) = @_; | 1382 | my ($file, $threads, $seqgroups, $errors) = @_; |
| 1332 | my $sequence_checking = 1; | 1383 | my $sequence_checking = 1; |
| 1333 | open(F, "<$file") or die +__PACKAGE__, ": can't open $file: $!\n"; | 1384 | open(F, "<$file") or die +__PACKAGE__, ": can't open $file: $!\n"; |
| 1385 | + binmode F; | ||
| 1334 | my $cur_thread = undef; | 1386 | my $cur_thread = undef; |
| 1335 | while (<F>) | 1387 | while (<F>) |
| 1336 | { | 1388 | { |
| @@ -1376,6 +1428,10 @@ sub handle_line | @@ -1376,6 +1428,10 @@ sub handle_line | ||
| 1376 | "$file:$.: no input file for thread $thread; " . | 1428 | "$file:$.: no input file for thread $thread; " . |
| 1377 | "sequence checking abandoned\n"); | 1429 | "sequence checking abandoned\n"); |
| 1378 | } | 1430 | } |
| 1431 | + else | ||
| 1432 | + { | ||
| 1433 | + binmode $fh; | ||
| 1434 | + } | ||
| 1379 | $threads->{$thread} = $fh; | 1435 | $threads->{$thread} = $fh; |
| 1380 | } | 1436 | } |
| 1381 | my $known = defined($threads->{$thread}); | 1437 | my $known = defined($threads->{$thread}); |
| @@ -1463,6 +1519,7 @@ sub output_line | @@ -1463,6 +1519,7 @@ sub output_line | ||
| 1463 | { | 1519 | { |
| 1464 | my ($file, $line) = @_; | 1520 | my ($file, $line) = @_; |
| 1465 | open(O, ">>$file") or die +__PACKAGE__, ": can't open $file: $!\n"; | 1521 | open(O, ">>$file") or die +__PACKAGE__, ": can't open $file: $!\n"; |
| 1522 | + binmode O; | ||
| 1466 | print O $line or die +__PACKAGE__, ": can't append to $file: $!\n"; | 1523 | print O $line or die +__PACKAGE__, ": can't append to $file: $!\n"; |
| 1467 | close(O) or die +__PACKAGE__, ": close $file failed: $!\n"; | 1524 | close(O) or die +__PACKAGE__, ": close $file failed: $!\n"; |
| 1468 | } | 1525 | } |
| @@ -1473,6 +1530,7 @@ sub create_if_missing | @@ -1473,6 +1530,7 @@ sub create_if_missing | ||
| 1473 | if (! -e $file) | 1530 | if (! -e $file) |
| 1474 | { | 1531 | { |
| 1475 | open(O, ">$file") or die +__PACKAGE__, ": can't create $file: $!\n"; | 1532 | open(O, ">$file") or die +__PACKAGE__, ": can't create $file: $!\n"; |
| 1533 | + binmode O; | ||
| 1476 | print O $line; | 1534 | print O $line; |
| 1477 | close(O); | 1535 | close(O); |
| 1478 | } | 1536 | } |
| @@ -1485,6 +1543,7 @@ sub split_combined | @@ -1485,6 +1543,7 @@ sub split_combined | ||
| 1485 | my $tempdir = $rep->_tempdir(); | 1543 | my $tempdir = $rep->_tempdir(); |
| 1486 | 1544 | ||
| 1487 | open(C, "<$combined") or die +__PACKAGE__, ": can't open $combined: $!\n"; | 1545 | open(C, "<$combined") or die +__PACKAGE__, ": can't open $combined: $!\n"; |
| 1546 | + binmode C; | ||
| 1488 | my %files = (); | 1547 | my %files = (); |
| 1489 | my $last_thread_fh = undef; | 1548 | my $last_thread_fh = undef; |
| 1490 | while (<C>) | 1549 | while (<C>) |
| @@ -1544,6 +1603,7 @@ sub cache_open | @@ -1544,6 +1603,7 @@ sub cache_open | ||
| 1544 | unlink $file; | 1603 | unlink $file; |
| 1545 | my $fh = new IO::File(">$file") or | 1604 | my $fh = new IO::File(">$file") or |
| 1546 | die +__PACKAGE__, ": can't open $file: $!\n"; | 1605 | die +__PACKAGE__, ": can't open $file: $!\n"; |
| 1606 | + binmode $fh; | ||
| 1547 | $cache->{$file} = $fh; | 1607 | $cache->{$file} = $fh; |
| 1548 | } | 1608 | } |
| 1549 | $cache->{$file}; | 1609 | $cache->{$file}; |
| @@ -1581,20 +1641,13 @@ sub rmrf | @@ -1581,20 +1641,13 @@ sub rmrf | ||
| 1581 | 1641 | ||
| 1582 | sub safe_pipe | 1642 | sub safe_pipe |
| 1583 | { | 1643 | { |
| 1644 | + my $rep = shift; | ||
| 1584 | my ($cmd, $outfile) = @_; | 1645 | my ($cmd, $outfile) = @_; |
| 1585 | my $result = 0; | 1646 | my $result = 0; |
| 1586 | 1647 | ||
| 1587 | - if ($^O eq 'MSWin32') | 1648 | + if ($in_windows) |
| 1588 | { | 1649 | { |
| 1589 | - my @cmd = @$cmd; | ||
| 1590 | - my $cmd_str = shift(@cmd); | ||
| 1591 | - while (@cmd) | ||
| 1592 | - { | ||
| 1593 | - my $arg = shift(@cmd); | ||
| 1594 | - $cmd_str .= " \"$arg\""; | ||
| 1595 | - } | ||
| 1596 | - $cmd_str .= " > $outfile 2>&1"; | ||
| 1597 | - $result = system($cmd_str); | 1650 | + $result = $rep->winrun($cmd, File::Spec->devnull(), $outfile); |
| 1598 | } | 1651 | } |
| 1599 | else | 1652 | else |
| 1600 | { | 1653 | { |
| @@ -1624,6 +1677,105 @@ sub safe_pipe | @@ -1624,6 +1677,105 @@ sub safe_pipe | ||
| 1624 | 1677 | ||
| 1625 | $result; | 1678 | $result; |
| 1626 | } | 1679 | } |
| 1680 | + | ||
| 1681 | +sub winrun | ||
| 1682 | +{ | ||
| 1683 | + # This function does several things to make running stuff on | ||
| 1684 | + # Windows look sort of like running things on UNIX. It assumes | ||
| 1685 | + # MinGW perl is running in an MSYS/MinGW environment. | ||
| 1686 | + # | ||
| 1687 | + # * When an MSYS/MinGW program is run with system("..."), its | ||
| 1688 | + # newlines generate \r\n, but when it's run from MSYS sh, its | ||
| 1689 | + # newlines generate \n. We want \n for UNIX-like programs. | ||
| 1690 | + # | ||
| 1691 | + # * system("...") in perl doesn't have any special magic to | ||
| 1692 | + # handle #! lines in scripts. A lot of test suites will count | ||
| 1693 | + # on that. | ||
| 1694 | + # | ||
| 1695 | + # * There's no Windows equivalent to execve with separate | ||
| 1696 | + # arguments, so all sorts of fancy quoting is necessary when * | ||
| 1697 | + # dealing with arguments with spaces, etc. | ||
| 1698 | + # | ||
| 1699 | + # * Pipes work unreliably. Fork emulation is very incomplete. | ||
| 1700 | + # | ||
| 1701 | + # To work around these issues, we ensure that everything is | ||
| 1702 | + # actually executed from the MSYS /bin/sh. We find the actual | ||
| 1703 | + # path of that and then write a shell script which we explicitly | ||
| 1704 | + # invoke as an argument to /bin/sh. If we have a string that we | ||
| 1705 | + # want executed with /bin/sh, we include the string in the shell | ||
| 1706 | + # script. If we have an array, we pass the array on the | ||
| 1707 | + # commandline to the shell script and let it preserve spacing. We | ||
| 1708 | + # also do our output redirection in the shell script itself since | ||
| 1709 | + # redirection of STDOUT and STDERR doesn't carry forward to | ||
| 1710 | + # programs invoked by programs we invoke. Finally, we filter out | ||
| 1711 | + # errors generated by the script itself, since it is supposed to | ||
| 1712 | + # be an invisible buffer for smoother execution of programs. | ||
| 1713 | + # Experience shows that its output comes from things like printing | ||
| 1714 | + # the names of signals generated by subsidiary programs. | ||
| 1715 | + | ||
| 1716 | + my $rep = shift; | ||
| 1717 | + my ($in_command, $in, $out) = @_; | ||
| 1718 | + my $tempdir = $rep->_tempdir(); | ||
| 1719 | + my $tempfilename = "$tempdir/winrun.tmp"; | ||
| 1720 | + if (! defined $winbin) | ||
| 1721 | + { | ||
| 1722 | + my $comspec = $ENV{'COMSPEC'}; | ||
| 1723 | + $comspec =~ s,\\,/,g; | ||
| 1724 | + if ((system("sh -c 'cd /bin; $comspec /c cd'" . | ||
| 1725 | + " > $tempfilename") == 0) && | ||
| 1726 | + open(F, "<$tempfilename")) | ||
| 1727 | + { | ||
| 1728 | + $winbin = <F>; | ||
| 1729 | + close(F); | ||
| 1730 | + $winbin =~ s,[\r\n],,g; | ||
| 1731 | + $winbin =~ s,\\,/,g; | ||
| 1732 | + } | ||
| 1733 | + if (! defined $winbin) | ||
| 1734 | + { | ||
| 1735 | + die +__PACKAGE__, ": unable to find windows path to /bin\n"; | ||
| 1736 | + } | ||
| 1737 | + } | ||
| 1738 | + my $script = "$tempdir/tmpscript"; | ||
| 1739 | + open(F, ">$script") or | ||
| 1740 | + croak +(+__PACKAGE__, | ||
| 1741 | + "->runtest: unable to open $script to write: $!\n"); | ||
| 1742 | + binmode F; | ||
| 1743 | + print F "exec >$tempfilename\n"; | ||
| 1744 | + print F "exec 2>&1\n"; | ||
| 1745 | + print F "exec <$in\n"; | ||
| 1746 | + my @cmd = ("$winbin/sh", $script); | ||
| 1747 | + if (ref($in_command) eq 'ARRAY') | ||
| 1748 | + { | ||
| 1749 | + # For debugging, write out the args | ||
| 1750 | + foreach my $arg (@$in_command) | ||
| 1751 | + { | ||
| 1752 | + print F "# $arg\n"; | ||
| 1753 | + } | ||
| 1754 | + print F '"$@"', "\n"; | ||
| 1755 | + push(@cmd, @$in_command); | ||
| 1756 | + } | ||
| 1757 | + else | ||
| 1758 | + { | ||
| 1759 | + print F "$in_command\n"; | ||
| 1760 | + } | ||
| 1761 | + close(F); | ||
| 1762 | + my $status = system @cmd; | ||
| 1763 | + if (open(IN, "<$tempfilename") && | ||
| 1764 | + open(OUT, ">$out")) | ||
| 1765 | + { | ||
| 1766 | + binmode IN; | ||
| 1767 | + binmode OUT; | ||
| 1768 | + while (<IN>) | ||
| 1769 | + { | ||
| 1770 | + next if m/^$script:/; | ||
| 1771 | + print OUT; | ||
| 1772 | + } | ||
| 1773 | + close(IN); | ||
| 1774 | + close(OUT); | ||
| 1775 | + } | ||
| 1776 | + $status; | ||
| 1777 | +} | ||
| 1778 | + | ||
| 1627 | 1; | 1779 | 1; |
| 1628 | 1780 | ||
| 1629 | # | 1781 | # |