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 | 476268c | 2020-12-03 21:24:07 +0100 | [diff] [blame] | 11 | my $EXECUTABLE = "t/harness"; |
Bram Moolenaar | e4f25e4 | 2017-07-07 11:54:15 +0200 | [diff] [blame] | 12 | GetOptions( |
| 13 | 'valgrind|v+' => \$VALGRIND, |
Bram Moolenaar | be593bf | 2020-05-19 21:20:04 +0200 | [diff] [blame] | 14 | 'executable|e=s' => \$EXECUTABLE, |
| 15 | 'fail-early|F' => \(my $FAIL_EARLY), |
Bram Moolenaar | e4f25e4 | 2017-07-07 11:54:15 +0200 | [diff] [blame] | 16 | ) or exit 1; |
| 17 | |
| 18 | my ( $hin, $hout, $hpid ); |
| 19 | { |
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; |
Bram Moolenaar | be593bf | 2020-05-19 21:20:04 +0200 | [diff] [blame] | 68 | exit $exitcode if $exitcode and $FAIL_EARLY; |
Bram Moolenaar | e4f25e4 | 2017-07-07 11:54:15 +0200 | [diff] [blame] | 69 | } |
| 70 | |
| 71 | sub do_line |
| 72 | { |
| 73 | my ( $line ) = @_; |
| 74 | |
| 75 | if( $line =~ m/^!(.*)/ ) { |
| 76 | do_onetest if defined $command; |
| 77 | print "> $1\n"; |
| 78 | } |
| 79 | |
| 80 | # Commands have capitals |
| 81 | elsif( $line =~ m/^([A-Z]+)/ ) { |
| 82 | # Some convenience formatting |
| 83 | if( $line =~ m/^(PUSH|ENCIN) (.*)$/ ) { |
| 84 | # we're evil |
| 85 | my $string = eval($2); |
| 86 | $line = "$1 " . unpack "H*", $string; |
| 87 | } |
Bram Moolenaar | 7da3415 | 2021-11-24 19:30:55 +0000 | [diff] [blame] | 88 | elsif( $line =~ m/^(SELECTION \d+) +(\[?)(.*?)(\]?)$/ ) { |
| 89 | # we're evil |
| 90 | my $string = eval($3); |
| 91 | $line = "$1 $2 " . unpack( "H*", $string ) . " $4"; |
| 92 | } |
Bram Moolenaar | e4f25e4 | 2017-07-07 11:54:15 +0200 | [diff] [blame] | 93 | |
| 94 | do_onetest if defined $command; |
| 95 | |
| 96 | $command = $line; |
| 97 | undef @expect; |
| 98 | } |
| 99 | # Expectations have lowercase |
| 100 | elsif( $line =~ m/^([a-z]+)/ ) { |
| 101 | # Convenience formatting |
| 102 | if( $line =~ m/^(text|encout) (.*)$/ ) { |
| 103 | $line = "$1 " . join ",", map sprintf("%x", $_), eval($2); |
| 104 | } |
| 105 | elsif( $line =~ m/^(output) (.*)$/ ) { |
| 106 | $line = "$1 " . join ",", map sprintf("%x", $_), unpack "C*", eval($2); |
| 107 | } |
| 108 | elsif( $line =~ m/^control (.*)$/ ) { |
| 109 | $line = sprintf "control %02x", eval($1); |
| 110 | } |
| 111 | elsif( $line =~ m/^csi (\S+) (.*)$/ ) { |
| 112 | $line = sprintf "csi %02x %s", eval($1), $2; # TODO |
| 113 | } |
Bram Moolenaar | be593bf | 2020-05-19 21:20:04 +0200 | [diff] [blame] | 114 | elsif( $line =~ m/^(osc) (\[\d+)? *(.*?)(\]?)$/ ) { |
| 115 | my ( $cmd, $initial, $data, $final ) = ( $1, $2, $3, $4 ); |
| 116 | $initial //= ""; |
| 117 | $initial .= ";" if $initial =~ m/\d+/; |
| 118 | |
Bram Moolenaar | 83a5253 | 2020-05-20 19:30:19 +0200 | [diff] [blame] | 119 | $line = "$cmd $initial" . join( "", map sprintf("%02x", $_), unpack "C*", length $data ? eval($data) : "" ) . "$final"; |
Bram Moolenaar | be593bf | 2020-05-19 21:20:04 +0200 | [diff] [blame] | 120 | } |
Bram Moolenaar | 7da3415 | 2021-11-24 19:30:55 +0000 | [diff] [blame] | 121 | elsif( $line =~ m/^(escape|dcs|apc|pm|sos) (\[?)(.*?)(\]?)$/ ) { |
| 122 | $line = "$1 $2" . join( "", map sprintf("%02x", $_), unpack "C*", length $3 ? eval($3) : "" ) . "$4"; |
Bram Moolenaar | e4f25e4 | 2017-07-07 11:54:15 +0200 | [diff] [blame] | 123 | } |
| 124 | elsif( $line =~ m/^putglyph (\S+) (.*)$/ ) { |
| 125 | $line = "putglyph " . join( ",", map sprintf("%x", $_), eval($1) ) . " $2"; |
| 126 | } |
Bram Moolenaar | 7da3415 | 2021-11-24 19:30:55 +0000 | [diff] [blame] | 127 | elsif( $line =~ m/^(?:movecursor|scrollrect|moverect|erase|damage|sb_pushline|sb_popline|settermprop|setmousefunc|selection-query) / ) { |
Bram Moolenaar | e4f25e4 | 2017-07-07 11:54:15 +0200 | [diff] [blame] | 128 | # no conversion |
| 129 | } |
Bram Moolenaar | 7da3415 | 2021-11-24 19:30:55 +0000 | [diff] [blame] | 130 | elsif( $line =~ m/^(selection-set) (.*?) (\[?)(.*?)(\]?)$/ ) { |
| 131 | $line = "$1 $2 $3" . join( "", map sprintf("%02x", $_), unpack "C*", eval($4) ) . "$5"; |
| 132 | } |
Bram Moolenaar | e4f25e4 | 2017-07-07 11:54:15 +0200 | [diff] [blame] | 133 | else { |
| 134 | warn "Unrecognised test expectation '$line'\n"; |
| 135 | } |
| 136 | |
| 137 | push @expect, $line; |
| 138 | } |
| 139 | # ?screen_row assertion is emulated here |
| 140 | elsif( $line =~ s/^\?screen_row\s+(\d+)\s*=\s*// ) { |
| 141 | my $row = $1; |
| 142 | my $row1 = $row + 1; |
| 143 | my $want = eval($line); |
| 144 | |
| 145 | do_onetest if defined $command; |
| 146 | |
| 147 | # TODO: may not be 80 |
| 148 | $hin->print( "\?screen_chars $row,0,$row1,80\n" ); |
| 149 | my $response = <$hout>; |
| 150 | chomp $response; |
| 151 | |
| 152 | $response = pack "C*", map hex, split m/,/, $response; |
| 153 | if( $response ne $want ) { |
Bram Moolenaar | 88d68de | 2020-05-18 21:51:01 +0200 | [diff] [blame] | 154 | print "# line $linenum: Assert ?screen_row $row failed:\n" . |
Bram Moolenaar | e4f25e4 | 2017-07-07 11:54:15 +0200 | [diff] [blame] | 155 | "# Expected: $want\n" . |
| 156 | "# Actual: $response\n"; |
| 157 | $exitcode = 1; |
Bram Moolenaar | be593bf | 2020-05-19 21:20:04 +0200 | [diff] [blame] | 158 | exit $exitcode if $exitcode and $FAIL_EARLY; |
Bram Moolenaar | e4f25e4 | 2017-07-07 11:54:15 +0200 | [diff] [blame] | 159 | } |
| 160 | } |
| 161 | # Assertions start with '?' |
Bram Moolenaar | d098b82 | 2020-05-18 21:12:59 +0200 | [diff] [blame] | 162 | elsif( $line =~ s/^\?([a-z]+.*?=)\s*// ) { |
Bram Moolenaar | e4f25e4 | 2017-07-07 11:54:15 +0200 | [diff] [blame] | 163 | do_onetest if defined $command; |
| 164 | |
| 165 | my ( $assertion ) = $1 =~ m/^(.*)\s+=/; |
Bram Moolenaar | 88d68de | 2020-05-18 21:51:01 +0200 | [diff] [blame] | 166 | my $expectation = $line; |
Bram Moolenaar | e4f25e4 | 2017-07-07 11:54:15 +0200 | [diff] [blame] | 167 | |
| 168 | $hin->print( "\?$assertion\n" ); |
| 169 | my $response = <$hout>; defined $response or wait, die "Test harness failed - $?\n"; |
Bram Moolenaar | d098b82 | 2020-05-18 21:12:59 +0200 | [diff] [blame] | 170 | chomp $response; $response =~ s/^\s+|\s+$//g; |
Bram Moolenaar | e4f25e4 | 2017-07-07 11:54:15 +0200 | [diff] [blame] | 171 | |
Bram Moolenaar | 88d68de | 2020-05-18 21:51:01 +0200 | [diff] [blame] | 172 | # Some convenience formatting |
| 173 | if( $assertion =~ m/^screen_chars/ and $expectation =~ m/^"/ ) { |
| 174 | $expectation = join ",", map sprintf("0x%02x", ord $_), split m//, eval($expectation); |
| 175 | } |
| 176 | |
| 177 | if( $response ne $expectation ) { |
| 178 | print "# line $linenum: Assert $assertion failed:\n" . |
| 179 | "# Expected: $expectation\n" . |
Bram Moolenaar | e4f25e4 | 2017-07-07 11:54:15 +0200 | [diff] [blame] | 180 | "# Actual: $response\n"; |
| 181 | $exitcode = 1; |
Bram Moolenaar | be593bf | 2020-05-19 21:20:04 +0200 | [diff] [blame] | 182 | exit $exitcode if $exitcode and $FAIL_EARLY; |
Bram Moolenaar | e4f25e4 | 2017-07-07 11:54:15 +0200 | [diff] [blame] | 183 | } |
| 184 | } |
| 185 | # Test controls start with '$' |
| 186 | elsif( $line =~ s/\$SEQ\s+(\d+)\s+(\d+):\s*// ) { |
| 187 | my ( $low, $high ) = ( $1, $2 ); |
| 188 | foreach my $val ( $low .. $high ) { |
| 189 | ( my $inner = $line ) =~ s/\\#/$val/g; |
| 190 | do_line( $inner ); |
| 191 | } |
| 192 | } |
| 193 | elsif( $line =~ s/\$REP\s+(\d+):\s*// ) { |
| 194 | my $count = $1; |
| 195 | do_line( $line ) for 1 .. $count; |
| 196 | } |
| 197 | else { |
| 198 | die "Unrecognised TEST line $line\n"; |
| 199 | } |
| 200 | } |
| 201 | |
| 202 | open my $test, "<", $ARGV[0] or die "Cannot open test script $ARGV[0] - $!"; |
| 203 | |
| 204 | while( my $line = <$test> ) { |
Bram Moolenaar | 88d68de | 2020-05-18 21:51:01 +0200 | [diff] [blame] | 205 | $linenum++; |
Bram Moolenaar | e4f25e4 | 2017-07-07 11:54:15 +0200 | [diff] [blame] | 206 | $line =~ s/^\s+//; |
Bram Moolenaar | e4f25e4 | 2017-07-07 11:54:15 +0200 | [diff] [blame] | 207 | chomp $line; |
Bram Moolenaar | 6fc3b59 | 2020-05-17 22:27:55 +0200 | [diff] [blame] | 208 | |
| 209 | next if $line =~ m/^(?:#|$)/; |
| 210 | last if $line eq "__END__"; |
| 211 | |
Bram Moolenaar | e4f25e4 | 2017-07-07 11:54:15 +0200 | [diff] [blame] | 212 | do_line( $line ); |
| 213 | } |
| 214 | |
| 215 | do_onetest if defined $command; |
| 216 | |
| 217 | close $hin; |
| 218 | close $hout; |
| 219 | |
| 220 | waitpid $hpid, 0; |
| 221 | if( $? ) { |
| 222 | printf STDERR "Harness exited %d\n", WEXITSTATUS($?) if WIFEXITED($?); |
| 223 | printf STDERR "Harness exit signal %d\n", WTERMSIG($?) if WIFSIGNALED($?); |
| 224 | $exitcode = WIFEXITED($?) ? WEXITSTATUS($?) : 125; |
| 225 | } |
| 226 | |
| 227 | exit $exitcode; |