Bram Moolenaar | e4f25e4 | 2017-07-07 11:54:15 +0200 | [diff] [blame] | 1 | #!/usr/bin/perl |
| 2 | |
| 3 | use strict; |
| 4 | use warnings; |
| 5 | use Getopt::Long; |
| 6 | use IO::Handle; |
| 7 | use IPC::Open2 qw( open2 ); |
| 8 | use POSIX qw( WIFEXITED WEXITSTATUS WIFSIGNALED WTERMSIG ); |
| 9 | |
| 10 | my $VALGRIND = 0; |
Bram Moolenaar | d4a5f40 | 2020-05-17 16:04:44 +0200 | [diff] [blame] | 11 | my $EXECUTABLE = "t/.libs/harness"; |
Bram Moolenaar | e4f25e4 | 2017-07-07 11:54:15 +0200 | [diff] [blame] | 12 | GetOptions( |
| 13 | 'valgrind|v+' => \$VALGRIND, |
Bram Moolenaar | d4a5f40 | 2020-05-17 16:04:44 +0200 | [diff] [blame] | 14 | 'executable|e=s' => \$EXECUTABLE |
Bram Moolenaar | e4f25e4 | 2017-07-07 11:54:15 +0200 | [diff] [blame] | 15 | ) or exit 1; |
| 16 | |
| 17 | my ( $hin, $hout, $hpid ); |
| 18 | { |
| 19 | local $ENV{LD_LIBRARY_PATH} = ".libs"; |
Bram Moolenaar | d4a5f40 | 2020-05-17 16:04:44 +0200 | [diff] [blame] | 20 | my @command = $EXECUTABLE; |
Bram Moolenaar | 37e3edc | 2018-12-15 14:49:34 +0100 | [diff] [blame] | 21 | unshift @command, "valgrind", "--tool=memcheck", "--leak-check=yes", "--num-callers=25", "--log-file=valgrind.out", "--error-exitcode=126" if $VALGRIND; |
Bram Moolenaar | e4f25e4 | 2017-07-07 11:54:15 +0200 | [diff] [blame] | 22 | |
| 23 | $hpid = open2 $hout, $hin, @command or die "Cannot open2 harness - $!"; |
| 24 | } |
| 25 | |
| 26 | my $exitcode = 0; |
| 27 | |
| 28 | my $command; |
| 29 | my @expect; |
| 30 | |
Bram Moolenaar | 88d68de | 2020-05-18 21:51:01 +0200 | [diff] [blame] | 31 | my $linenum = 0; |
| 32 | |
Bram Moolenaar | e4f25e4 | 2017-07-07 11:54:15 +0200 | [diff] [blame] | 33 | sub do_onetest |
| 34 | { |
| 35 | $hin->print( "$command\n" ); |
| 36 | undef $command; |
| 37 | |
| 38 | my $fail_printed = 0; |
| 39 | |
| 40 | while( my $outline = <$hout> ) { |
| 41 | last if $outline eq "DONE\n" or $outline eq "?\n"; |
| 42 | |
| 43 | chomp $outline; |
| 44 | |
| 45 | if( !@expect ) { |
Bram Moolenaar | 88d68de | 2020-05-18 21:51:01 +0200 | [diff] [blame] | 46 | print "# line $linenum: Test failed\n" unless $fail_printed++; |
Bram Moolenaar | e4f25e4 | 2017-07-07 11:54:15 +0200 | [diff] [blame] | 47 | print "# expected nothing more\n" . |
| 48 | "# Actual: $outline\n"; |
| 49 | next; |
| 50 | } |
| 51 | |
| 52 | my $expectation = shift @expect; |
| 53 | |
| 54 | next if $expectation eq $outline; |
| 55 | |
Bram Moolenaar | 88d68de | 2020-05-18 21:51:01 +0200 | [diff] [blame] | 56 | print "# line $linenum: Test failed\n" unless $fail_printed++; |
Bram Moolenaar | e4f25e4 | 2017-07-07 11:54:15 +0200 | [diff] [blame] | 57 | print "# Expected: $expectation\n" . |
| 58 | "# Actual: $outline\n"; |
| 59 | } |
| 60 | |
| 61 | if( @expect ) { |
Bram Moolenaar | 88d68de | 2020-05-18 21:51:01 +0200 | [diff] [blame] | 62 | print "# line $linenum: Test failed\n" unless $fail_printed++; |
Bram Moolenaar | e4f25e4 | 2017-07-07 11:54:15 +0200 | [diff] [blame] | 63 | print "# Expected: $_\n" . |
| 64 | "# didn't happen\n" for @expect; |
| 65 | } |
| 66 | |
| 67 | $exitcode = 1 if $fail_printed; |
| 68 | } |
| 69 | |
| 70 | sub do_line |
| 71 | { |
| 72 | my ( $line ) = @_; |
| 73 | |
| 74 | if( $line =~ m/^!(.*)/ ) { |
| 75 | do_onetest if defined $command; |
| 76 | print "> $1\n"; |
| 77 | } |
| 78 | |
| 79 | # Commands have capitals |
| 80 | elsif( $line =~ m/^([A-Z]+)/ ) { |
| 81 | # Some convenience formatting |
| 82 | if( $line =~ m/^(PUSH|ENCIN) (.*)$/ ) { |
| 83 | # we're evil |
| 84 | my $string = eval($2); |
| 85 | $line = "$1 " . unpack "H*", $string; |
| 86 | } |
| 87 | |
| 88 | do_onetest if defined $command; |
| 89 | |
| 90 | $command = $line; |
| 91 | undef @expect; |
| 92 | } |
| 93 | # Expectations have lowercase |
| 94 | elsif( $line =~ m/^([a-z]+)/ ) { |
| 95 | # Convenience formatting |
| 96 | if( $line =~ m/^(text|encout) (.*)$/ ) { |
| 97 | $line = "$1 " . join ",", map sprintf("%x", $_), eval($2); |
| 98 | } |
| 99 | elsif( $line =~ m/^(output) (.*)$/ ) { |
| 100 | $line = "$1 " . join ",", map sprintf("%x", $_), unpack "C*", eval($2); |
| 101 | } |
| 102 | elsif( $line =~ m/^control (.*)$/ ) { |
| 103 | $line = sprintf "control %02x", eval($1); |
| 104 | } |
| 105 | elsif( $line =~ m/^csi (\S+) (.*)$/ ) { |
| 106 | $line = sprintf "csi %02x %s", eval($1), $2; # TODO |
| 107 | } |
| 108 | elsif( $line =~ m/^(escape|osc|dcs) (.*)$/ ) { |
| 109 | $line = "$1 " . join "", map sprintf("%02x", $_), unpack "C*", eval($2); |
| 110 | } |
| 111 | elsif( $line =~ m/^putglyph (\S+) (.*)$/ ) { |
| 112 | $line = "putglyph " . join( ",", map sprintf("%x", $_), eval($1) ) . " $2"; |
| 113 | } |
| 114 | elsif( $line =~ m/^(?:movecursor|scrollrect|moverect|erase|damage|sb_pushline|sb_popline|settermprop|setmousefunc) / ) { |
| 115 | # no conversion |
| 116 | } |
| 117 | else { |
| 118 | warn "Unrecognised test expectation '$line'\n"; |
| 119 | } |
| 120 | |
| 121 | push @expect, $line; |
| 122 | } |
| 123 | # ?screen_row assertion is emulated here |
| 124 | elsif( $line =~ s/^\?screen_row\s+(\d+)\s*=\s*// ) { |
| 125 | my $row = $1; |
| 126 | my $row1 = $row + 1; |
| 127 | my $want = eval($line); |
| 128 | |
| 129 | do_onetest if defined $command; |
| 130 | |
| 131 | # TODO: may not be 80 |
| 132 | $hin->print( "\?screen_chars $row,0,$row1,80\n" ); |
| 133 | my $response = <$hout>; |
| 134 | chomp $response; |
| 135 | |
| 136 | $response = pack "C*", map hex, split m/,/, $response; |
| 137 | if( $response ne $want ) { |
Bram Moolenaar | 88d68de | 2020-05-18 21:51:01 +0200 | [diff] [blame] | 138 | print "# line $linenum: Assert ?screen_row $row failed:\n" . |
Bram Moolenaar | e4f25e4 | 2017-07-07 11:54:15 +0200 | [diff] [blame] | 139 | "# Expected: $want\n" . |
| 140 | "# Actual: $response\n"; |
| 141 | $exitcode = 1; |
| 142 | } |
| 143 | } |
| 144 | # Assertions start with '?' |
Bram Moolenaar | d098b82 | 2020-05-18 21:12:59 +0200 | [diff] [blame] | 145 | elsif( $line =~ s/^\?([a-z]+.*?=)\s*// ) { |
Bram Moolenaar | e4f25e4 | 2017-07-07 11:54:15 +0200 | [diff] [blame] | 146 | do_onetest if defined $command; |
| 147 | |
| 148 | my ( $assertion ) = $1 =~ m/^(.*)\s+=/; |
Bram Moolenaar | 88d68de | 2020-05-18 21:51:01 +0200 | [diff] [blame] | 149 | my $expectation = $line; |
Bram Moolenaar | e4f25e4 | 2017-07-07 11:54:15 +0200 | [diff] [blame] | 150 | |
| 151 | $hin->print( "\?$assertion\n" ); |
| 152 | my $response = <$hout>; defined $response or wait, die "Test harness failed - $?\n"; |
Bram Moolenaar | d098b82 | 2020-05-18 21:12:59 +0200 | [diff] [blame] | 153 | chomp $response; $response =~ s/^\s+|\s+$//g; |
Bram Moolenaar | e4f25e4 | 2017-07-07 11:54:15 +0200 | [diff] [blame] | 154 | |
Bram Moolenaar | 88d68de | 2020-05-18 21:51:01 +0200 | [diff] [blame] | 155 | # Some convenience formatting |
| 156 | if( $assertion =~ m/^screen_chars/ and $expectation =~ m/^"/ ) { |
| 157 | $expectation = join ",", map sprintf("0x%02x", ord $_), split m//, eval($expectation); |
| 158 | } |
| 159 | |
| 160 | if( $response ne $expectation ) { |
| 161 | print "# line $linenum: Assert $assertion failed:\n" . |
| 162 | "# Expected: $expectation\n" . |
Bram Moolenaar | e4f25e4 | 2017-07-07 11:54:15 +0200 | [diff] [blame] | 163 | "# Actual: $response\n"; |
| 164 | $exitcode = 1; |
| 165 | } |
| 166 | } |
| 167 | # Test controls start with '$' |
| 168 | elsif( $line =~ s/\$SEQ\s+(\d+)\s+(\d+):\s*// ) { |
| 169 | my ( $low, $high ) = ( $1, $2 ); |
| 170 | foreach my $val ( $low .. $high ) { |
| 171 | ( my $inner = $line ) =~ s/\\#/$val/g; |
| 172 | do_line( $inner ); |
| 173 | } |
| 174 | } |
| 175 | elsif( $line =~ s/\$REP\s+(\d+):\s*// ) { |
| 176 | my $count = $1; |
| 177 | do_line( $line ) for 1 .. $count; |
| 178 | } |
| 179 | else { |
| 180 | die "Unrecognised TEST line $line\n"; |
| 181 | } |
| 182 | } |
| 183 | |
| 184 | open my $test, "<", $ARGV[0] or die "Cannot open test script $ARGV[0] - $!"; |
| 185 | |
| 186 | while( my $line = <$test> ) { |
Bram Moolenaar | 88d68de | 2020-05-18 21:51:01 +0200 | [diff] [blame] | 187 | $linenum++; |
Bram Moolenaar | e4f25e4 | 2017-07-07 11:54:15 +0200 | [diff] [blame] | 188 | $line =~ s/^\s+//; |
Bram Moolenaar | e4f25e4 | 2017-07-07 11:54:15 +0200 | [diff] [blame] | 189 | chomp $line; |
Bram Moolenaar | 6fc3b59 | 2020-05-17 22:27:55 +0200 | [diff] [blame] | 190 | |
| 191 | next if $line =~ m/^(?:#|$)/; |
| 192 | last if $line eq "__END__"; |
| 193 | |
Bram Moolenaar | e4f25e4 | 2017-07-07 11:54:15 +0200 | [diff] [blame] | 194 | do_line( $line ); |
| 195 | } |
| 196 | |
| 197 | do_onetest if defined $command; |
| 198 | |
| 199 | close $hin; |
| 200 | close $hout; |
| 201 | |
| 202 | waitpid $hpid, 0; |
| 203 | if( $? ) { |
| 204 | printf STDERR "Harness exited %d\n", WEXITSTATUS($?) if WIFEXITED($?); |
| 205 | printf STDERR "Harness exit signal %d\n", WTERMSIG($?) if WIFSIGNALED($?); |
| 206 | $exitcode = WIFEXITED($?) ? WEXITSTATUS($?) : 125; |
| 207 | } |
| 208 | |
| 209 | exit $exitcode; |