blob: 7d5cc7b23488fb60f377475b4d3a0dcd1b0b6d0d [file] [log] [blame]
Bram Moolenaare4f25e42017-07-07 11:54:15 +02001#!/usr/bin/perl
2
3use strict;
4use warnings;
5use Getopt::Long;
6use IO::Handle;
7use IPC::Open2 qw( open2 );
8use POSIX qw( WIFEXITED WEXITSTATUS WIFSIGNALED WTERMSIG );
9
10my $VALGRIND = 0;
Bram Moolenaar476268c2020-12-03 21:24:07 +010011my $EXECUTABLE = "t/harness";
Bram Moolenaare4f25e42017-07-07 11:54:15 +020012GetOptions(
13 'valgrind|v+' => \$VALGRIND,
Bram Moolenaarbe593bf2020-05-19 21:20:04 +020014 'executable|e=s' => \$EXECUTABLE,
15 'fail-early|F' => \(my $FAIL_EARLY),
Bram Moolenaare4f25e42017-07-07 11:54:15 +020016) or exit 1;
17
18my ( $hin, $hout, $hpid );
19{
Bram Moolenaard4a5f402020-05-17 16:04:44 +020020 my @command = $EXECUTABLE;
Bram Moolenaar37e3edc2018-12-15 14:49:34 +010021 unshift @command, "valgrind", "--tool=memcheck", "--leak-check=yes", "--num-callers=25", "--log-file=valgrind.out", "--error-exitcode=126" if $VALGRIND;
Bram Moolenaare4f25e42017-07-07 11:54:15 +020022
23 $hpid = open2 $hout, $hin, @command or die "Cannot open2 harness - $!";
24}
25
26my $exitcode = 0;
27
28my $command;
29my @expect;
30
Bram Moolenaar88d68de2020-05-18 21:51:01 +020031my $linenum = 0;
32
Bram Moolenaare4f25e42017-07-07 11:54:15 +020033sub 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 Moolenaar88d68de2020-05-18 21:51:01 +020046 print "# line $linenum: Test failed\n" unless $fail_printed++;
Bram Moolenaare4f25e42017-07-07 11:54:15 +020047 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 Moolenaar88d68de2020-05-18 21:51:01 +020056 print "# line $linenum: Test failed\n" unless $fail_printed++;
Bram Moolenaare4f25e42017-07-07 11:54:15 +020057 print "# Expected: $expectation\n" .
58 "# Actual: $outline\n";
59 }
60
61 if( @expect ) {
Bram Moolenaar88d68de2020-05-18 21:51:01 +020062 print "# line $linenum: Test failed\n" unless $fail_printed++;
Bram Moolenaare4f25e42017-07-07 11:54:15 +020063 print "# Expected: $_\n" .
64 "# didn't happen\n" for @expect;
65 }
66
67 $exitcode = 1 if $fail_printed;
Bram Moolenaarbe593bf2020-05-19 21:20:04 +020068 exit $exitcode if $exitcode and $FAIL_EARLY;
Bram Moolenaare4f25e42017-07-07 11:54:15 +020069}
70
71sub 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 Moolenaar7da34152021-11-24 19:30:55 +000088 elsif( $line =~ m/^(SELECTION \d+) +(\[?)(.*?)(\]?)$/ ) {
89 # we're evil
90 my $string = eval($3);
91 $line = "$1 $2 " . unpack( "H*", $string ) . " $4";
92 }
Bram Moolenaare4f25e42017-07-07 11:54:15 +020093
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 Moolenaarbe593bf2020-05-19 21:20:04 +0200114 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 Moolenaar83a52532020-05-20 19:30:19 +0200119 $line = "$cmd $initial" . join( "", map sprintf("%02x", $_), unpack "C*", length $data ? eval($data) : "" ) . "$final";
Bram Moolenaarbe593bf2020-05-19 21:20:04 +0200120 }
Bram Moolenaar7da34152021-11-24 19:30:55 +0000121 elsif( $line =~ m/^(escape|dcs|apc|pm|sos) (\[?)(.*?)(\]?)$/ ) {
122 $line = "$1 $2" . join( "", map sprintf("%02x", $_), unpack "C*", length $3 ? eval($3) : "" ) . "$4";
Bram Moolenaare4f25e42017-07-07 11:54:15 +0200123 }
124 elsif( $line =~ m/^putglyph (\S+) (.*)$/ ) {
125 $line = "putglyph " . join( ",", map sprintf("%x", $_), eval($1) ) . " $2";
126 }
Bram Moolenaar7da34152021-11-24 19:30:55 +0000127 elsif( $line =~ m/^(?:movecursor|scrollrect|moverect|erase|damage|sb_pushline|sb_popline|settermprop|setmousefunc|selection-query) / ) {
Bram Moolenaare4f25e42017-07-07 11:54:15 +0200128 # no conversion
129 }
Bram Moolenaar7da34152021-11-24 19:30:55 +0000130 elsif( $line =~ m/^(selection-set) (.*?) (\[?)(.*?)(\]?)$/ ) {
131 $line = "$1 $2 $3" . join( "", map sprintf("%02x", $_), unpack "C*", eval($4) ) . "$5";
132 }
Bram Moolenaare4f25e42017-07-07 11:54:15 +0200133 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;
Bram Moolenaar501e7772022-10-16 14:35:46 +0100142 my $want;
143
144 if( $line =~ m/^"/ ) {
145 $want = eval($line);
146 }
147 else {
148 # Turn 0xDD,0xDD,... directly into bytes
149 $want = pack "C*", map { hex } split m/,/, $line;
150 }
Bram Moolenaare4f25e42017-07-07 11:54:15 +0200151
152 do_onetest if defined $command;
153
Bram Moolenaar501e7772022-10-16 14:35:46 +0100154 $hin->print( "\?screen_chars $row\n" );
Bram Moolenaare4f25e42017-07-07 11:54:15 +0200155 my $response = <$hout>;
156 chomp $response;
157
Bram Moolenaar501e7772022-10-16 14:35:46 +0100158 $response = pack "C*", map { hex } split m/,/, $response;
Bram Moolenaare4f25e42017-07-07 11:54:15 +0200159 if( $response ne $want ) {
Bram Moolenaar88d68de2020-05-18 21:51:01 +0200160 print "# line $linenum: Assert ?screen_row $row failed:\n" .
Bram Moolenaare4f25e42017-07-07 11:54:15 +0200161 "# Expected: $want\n" .
162 "# Actual: $response\n";
163 $exitcode = 1;
Bram Moolenaarbe593bf2020-05-19 21:20:04 +0200164 exit $exitcode if $exitcode and $FAIL_EARLY;
Bram Moolenaare4f25e42017-07-07 11:54:15 +0200165 }
166 }
167 # Assertions start with '?'
Bram Moolenaard098b822020-05-18 21:12:59 +0200168 elsif( $line =~ s/^\?([a-z]+.*?=)\s*// ) {
Bram Moolenaare4f25e42017-07-07 11:54:15 +0200169 do_onetest if defined $command;
170
171 my ( $assertion ) = $1 =~ m/^(.*)\s+=/;
Bram Moolenaar88d68de2020-05-18 21:51:01 +0200172 my $expectation = $line;
Bram Moolenaare4f25e42017-07-07 11:54:15 +0200173
174 $hin->print( "\?$assertion\n" );
175 my $response = <$hout>; defined $response or wait, die "Test harness failed - $?\n";
Bram Moolenaard098b822020-05-18 21:12:59 +0200176 chomp $response; $response =~ s/^\s+|\s+$//g;
Bram Moolenaare4f25e42017-07-07 11:54:15 +0200177
Bram Moolenaar88d68de2020-05-18 21:51:01 +0200178 # Some convenience formatting
179 if( $assertion =~ m/^screen_chars/ and $expectation =~ m/^"/ ) {
180 $expectation = join ",", map sprintf("0x%02x", ord $_), split m//, eval($expectation);
181 }
182
183 if( $response ne $expectation ) {
184 print "# line $linenum: Assert $assertion failed:\n" .
185 "# Expected: $expectation\n" .
Bram Moolenaare4f25e42017-07-07 11:54:15 +0200186 "# Actual: $response\n";
187 $exitcode = 1;
Bram Moolenaarbe593bf2020-05-19 21:20:04 +0200188 exit $exitcode if $exitcode and $FAIL_EARLY;
Bram Moolenaare4f25e42017-07-07 11:54:15 +0200189 }
190 }
191 # Test controls start with '$'
192 elsif( $line =~ s/\$SEQ\s+(\d+)\s+(\d+):\s*// ) {
193 my ( $low, $high ) = ( $1, $2 );
194 foreach my $val ( $low .. $high ) {
195 ( my $inner = $line ) =~ s/\\#/$val/g;
196 do_line( $inner );
197 }
198 }
199 elsif( $line =~ s/\$REP\s+(\d+):\s*// ) {
200 my $count = $1;
201 do_line( $line ) for 1 .. $count;
202 }
203 else {
204 die "Unrecognised TEST line $line\n";
205 }
206}
207
208open my $test, "<", $ARGV[0] or die "Cannot open test script $ARGV[0] - $!";
209
210while( my $line = <$test> ) {
Bram Moolenaar88d68de2020-05-18 21:51:01 +0200211 $linenum++;
Bram Moolenaare4f25e42017-07-07 11:54:15 +0200212 $line =~ s/^\s+//;
Bram Moolenaare4f25e42017-07-07 11:54:15 +0200213 chomp $line;
Bram Moolenaar6fc3b592020-05-17 22:27:55 +0200214
215 next if $line =~ m/^(?:#|$)/;
216 last if $line eq "__END__";
217
Bram Moolenaare4f25e42017-07-07 11:54:15 +0200218 do_line( $line );
219}
220
221do_onetest if defined $command;
222
223close $hin;
224close $hout;
225
226waitpid $hpid, 0;
227if( $? ) {
228 printf STDERR "Harness exited %d\n", WEXITSTATUS($?) if WIFEXITED($?);
229 printf STDERR "Harness exit signal %d\n", WTERMSIG($?) if WIFSIGNALED($?);
230 $exitcode = WIFEXITED($?) ? WEXITSTATUS($?) : 125;
231}
232
233exit $exitcode;