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