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