blob: 9f48c5cadef1fcbe723a11140e1f8517b129879a [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 Moolenaard4a5f402020-05-17 16:04:44 +020011my $EXECUTABLE = "t/.libs/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{
20 local $ENV{LD_LIBRARY_PATH} = ".libs";
Bram Moolenaard4a5f402020-05-17 16:04:44 +020021 my @command = $EXECUTABLE;
Bram Moolenaar37e3edc2018-12-15 14:49:34 +010022 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 +020023
24 $hpid = open2 $hout, $hin, @command or die "Cannot open2 harness - $!";
25}
26
27my $exitcode = 0;
28
29my $command;
30my @expect;
31
Bram Moolenaar88d68de2020-05-18 21:51:01 +020032my $linenum = 0;
33
Bram Moolenaare4f25e42017-07-07 11:54:15 +020034sub 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 Moolenaar88d68de2020-05-18 21:51:01 +020047 print "# line $linenum: Test failed\n" unless $fail_printed++;
Bram Moolenaare4f25e42017-07-07 11:54:15 +020048 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 Moolenaar88d68de2020-05-18 21:51:01 +020057 print "# line $linenum: Test failed\n" unless $fail_printed++;
Bram Moolenaare4f25e42017-07-07 11:54:15 +020058 print "# Expected: $expectation\n" .
59 "# Actual: $outline\n";
60 }
61
62 if( @expect ) {
Bram Moolenaar88d68de2020-05-18 21:51:01 +020063 print "# line $linenum: Test failed\n" unless $fail_printed++;
Bram Moolenaare4f25e42017-07-07 11:54:15 +020064 print "# Expected: $_\n" .
65 "# didn't happen\n" for @expect;
66 }
67
68 $exitcode = 1 if $fail_printed;
Bram Moolenaarbe593bf2020-05-19 21:20:04 +020069 exit $exitcode if $exitcode and $FAIL_EARLY;
Bram Moolenaare4f25e42017-07-07 11:54:15 +020070}
71
72sub 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 Moolenaarbe593bf2020-05-19 21:20:04 +0200110 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 Moolenaare4f25e42017-07-07 11:54:15 +0200119 }
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 Moolenaar88d68de2020-05-18 21:51:01 +0200147 print "# line $linenum: Assert ?screen_row $row failed:\n" .
Bram Moolenaare4f25e42017-07-07 11:54:15 +0200148 "# Expected: $want\n" .
149 "# Actual: $response\n";
150 $exitcode = 1;
Bram Moolenaarbe593bf2020-05-19 21:20:04 +0200151 exit $exitcode if $exitcode and $FAIL_EARLY;
Bram Moolenaare4f25e42017-07-07 11:54:15 +0200152 }
153 }
154 # Assertions start with '?'
Bram Moolenaard098b822020-05-18 21:12:59 +0200155 elsif( $line =~ s/^\?([a-z]+.*?=)\s*// ) {
Bram Moolenaare4f25e42017-07-07 11:54:15 +0200156 do_onetest if defined $command;
157
158 my ( $assertion ) = $1 =~ m/^(.*)\s+=/;
Bram Moolenaar88d68de2020-05-18 21:51:01 +0200159 my $expectation = $line;
Bram Moolenaare4f25e42017-07-07 11:54:15 +0200160
161 $hin->print( "\?$assertion\n" );
162 my $response = <$hout>; defined $response or wait, die "Test harness failed - $?\n";
Bram Moolenaard098b822020-05-18 21:12:59 +0200163 chomp $response; $response =~ s/^\s+|\s+$//g;
Bram Moolenaare4f25e42017-07-07 11:54:15 +0200164
Bram Moolenaar88d68de2020-05-18 21:51:01 +0200165 # 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 Moolenaare4f25e42017-07-07 11:54:15 +0200173 "# Actual: $response\n";
174 $exitcode = 1;
Bram Moolenaarbe593bf2020-05-19 21:20:04 +0200175 exit $exitcode if $exitcode and $FAIL_EARLY;
Bram Moolenaare4f25e42017-07-07 11:54:15 +0200176 }
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
195open my $test, "<", $ARGV[0] or die "Cannot open test script $ARGV[0] - $!";
196
197while( my $line = <$test> ) {
Bram Moolenaar88d68de2020-05-18 21:51:01 +0200198 $linenum++;
Bram Moolenaare4f25e42017-07-07 11:54:15 +0200199 $line =~ s/^\s+//;
Bram Moolenaare4f25e42017-07-07 11:54:15 +0200200 chomp $line;
Bram Moolenaar6fc3b592020-05-17 22:27:55 +0200201
202 next if $line =~ m/^(?:#|$)/;
203 last if $line eq "__END__";
204
Bram Moolenaare4f25e42017-07-07 11:54:15 +0200205 do_line( $line );
206}
207
208do_onetest if defined $command;
209
210close $hin;
211close $hout;
212
213waitpid $hpid, 0;
214if( $? ) {
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
220exit $exitcode;