Merge tag 'input-for-v5.19-rc6' of git://git.kernel.org/pub/scm/linux/kernel/git...
[linux-2.6-microblaze.git] / scripts / dtc / of_unittest_expect
1 #!/usr/bin/perl
2 # SPDX-License-Identifier: GPL-2.0
3 #
4 # Copyright 2020, 2022 Sony Corporation
5 #
6 # Author: Frank Rowand
7
8 # This program is meant to be an aid to reading the verbose output of
9 # on the console log that results from executing the Linux kernel
10 # devicetree unittest (drivers/of/unitest.c).
11
12 $VUFX = "220201a";
13
14 use strict 'refs';
15 use strict subs;
16
17 use Getopt::Long;
18 use Text::Wrap;
19
20 # strip off everything before final "/"
21 (undef, $script_name) = split(/^.*\//, $0);
22
23 # following /usr/include/sysexits.h
24 $EX_OK=0;
25 $EX_USAGE=64;
26
27
28 #______________________________________________________________________________
29 sub compare {
30         my ($expect, $got) = @_;
31         my $expect_next;
32         my $expect_next_lit;
33         my $got_next;
34         my $type;
35
36         while ($expect) {
37
38                 ($expect_next, $type) = split(/<</, $expect);
39                 ($type) = split(/>>/, $type);
40                 $expect =~ s/^.*?>>//;  # '?' is non-greedy, minimal match
41
42                 # literal, ignore all metacharacters when used in a regex
43                 $expect_next_lit = quotemeta($expect_next);
44
45                 $got_next = $got;
46                 $got_next =~ s/^($expect_next_lit).*/\1/;
47                 $got       =~ s/^$expect_next_lit//;
48
49                 if ($expect_next ne $got_next) {
50                         return 0;
51                 }
52
53                 if ($type eq "int") {
54                         if ($got =~ /^[+-]*[0-9]+/) {
55                                 $got =~ s/^[+-]*[0-9]+//;
56                         } else {
57                                 return 0;
58                         }
59                 } elsif ($type eq "hex") {
60                         if ($got =~ /^(0x)*[0-9a-f]+/) {
61                                 $got =~ s/^(0x)*[0-9a-f]+//;
62                         } else {
63                                 return 0;
64                         }
65                 } elsif ($type eq "") {
66                         if ($expect_next ne $got_next) {
67                                 return 0;
68                         } else {
69                                 return 1;
70                         }
71                 } else {
72                         $internal_err++;
73                         print "** ERROR: special pattern not recognized: <<$type>>, CONSOLE_LOG line: $.\n";
74                         return 0;
75                 }
76
77         }
78
79         # should not get here
80         $internal_err++;
81         print "** ERROR: $script_name internal error, at end of compare(), CONSOLE_LOG line: $.\n";
82
83         return 0;
84 }
85
86
87 #______________________________________________________________________________
88 sub usage {
89
90 # ***** when editing, be careful to not put tabs in the string printed:
91
92         print STDERR
93 "
94 usage:
95
96   $script_name CONSOLE_LOG
97
98      -h                print program usage
99     --help             print program usage
100     --hide-expect      suppress output of EXPECTed lines
101     --line-num         report line number of CONSOLE_LOG
102     --no-expect-stats  do not report EXPECT statistics
103     --no-strip-ts      do not strip leading console timestamps
104     --verbose          do not suppress EXPECT begin and end lines
105     --version          print program version and exit
106
107
108   Process a console log for EXPECTed test related messages to either
109   highlight expected devicetree unittest related messages or suppress
110   the messages.  Leading console timestamps will be stripped.
111
112   Various unittests may trigger kernel messages from outside the
113   unittest code.  The unittest annotates that it expects the message
114   to occur with an 'EXPECT \\ : text' (begin) before triggering the
115   message, and an 'EXPECT / : text' (end) after triggering the message.
116
117   If an expected message does not occur, that will be reported.
118
119   For each expected message, the 'EXPECT \\ : text' (begin) and
120   'EXPECT / : text' (end), 'text' will contain the message text.
121
122   If 'EXPECT \\' (begin) and 'EXPECT /' (end) lines do not contain
123   matching 'text', that will be reported.
124
125   If EXPECT lines are nested, 'EXPECT /' (end) lines must be in the
126   reverse order of the corresponding 'EXPECT \\' (begin) lines.
127
128   'EXPECT \\ : text' (begin) and 'EXPECT / : text' (end) lines can
129   contain special patterns in 'text':
130
131      <<int>> matches: [+-]*[0-9]+
132      <<hex>> matches: (0x)*[0-9a-f]+
133
134   'EXPECT \\' (begin) and 'EXPECT /' (end) lines are suppressed.
135
136   A prefix is added to every line of output:
137
138     'ok ' Line matches an enclosing EXPECT begin/end pair
139
140     '** ' Line reports $script_name warning or error
141
142     '-> ' Line reports start or end of the unittests
143
144     '>> ' Line reports a unittest test FAIL
145
146     '   ' Lines that are not otherwise prefixed
147
148   Issues detected in CONSOLE_LOG are reported to STDOUT, not to STDERR.
149
150   Known Issues:
151
152     --line-num causes the CONSOLE_LOG line number to be printed in 4 columns.
153        If CONSOLE_LOG contains more than 9999 lines then more columns will be
154        used to report the line number for lines greater than 9999 (eg for
155        lines 10000 - 99999, 5 columns will be used).
156 ";
157
158         return {};
159 }
160
161 #______________________________________________________________________________
162 #______________________________________________________________________________
163
164 if (!GetOptions(
165         "h"               => \$help,
166         "help"            => \$help,
167         "hide-expect"     => \$hide_expect,
168         "line-num"        => \$print_line_num,
169         "no-expect-stats" => \$no_expect_stats,
170         "no-strip-ts"     => \$no_strip_ts,
171         "verbose"         => \$verbose,
172         "version"         => \$version,
173         )) {
174         print STDERR "\n";
175         print STDERR "ERROR processing command line options\n";
176         print STDERR "\n";
177         print STDERR "For help, type '$script_name --help'\n";
178         print STDERR "\n";
179
180         exit $EX_OK;
181 }
182
183
184 if ($no_strip_ts) {
185         $strip_ts = 1;
186         $no_strip_ts = 0;
187 } else {
188         $strip_ts = 0;
189         $no_strip_ts = 1;
190 }
191
192
193 # - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
194 if ($help){
195
196         &usage;
197
198         exit $EX_OK;
199 }
200
201
202 # - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
203
204 if ($version) {
205         print STDERR "\n$script_name  $VUFX\n\n";
206         print STDERR "\n";
207
208         exit $EX_OK;
209 }
210
211
212 # - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
213 if ($#ARGV != 0) {
214
215         # Limit input files to exactly one.
216         #
217         # 'while ($line = <ARGV>) {' in the code below supports multiple file
218         # names on the command line, but the EXPECT statistics are reported
219         # once for all input - it is not an expected use case to generate one
220         # set of statistics for multiple input files.
221
222         print STDERR "\n";
223         print STDERR "Required arguments: CONSOLE_LOG\n";
224         print STDERR "\n";
225
226         exit $EX_USAGE;
227 }
228
229
230 #______________________________________________________________________________
231
232 # Patterns to match 'EXPECT \ : ' (begin) and 'EXPECT / : ' (end)
233 #
234 # $exp_* are used as regex match patterns,
235 # so '\\\\' in $exp_begin matches a single '\'
236 # quotemeta() does not do the right thing in this case
237 #
238 # $pr_fmt is the prefix that unittest prints for every message
239
240 $pr_fmt = "### dt-test ### ";
241 $exp_begin = "${pr_fmt}EXPECT \\\\ : ";
242 $exp_end   = "${pr_fmt}EXPECT / : ";
243
244
245 $line_num = "";
246 $timestamp = "";
247
248 LINE:
249 while ($line = <ARGV>) {
250
251         chomp $line;
252
253         $prefix = "  ";  ## 2 characters
254
255
256         if ($strip_ts) {
257
258                 $timestamp = $line;
259
260                 if ($timestamp =~ /^\[\s*[0-9]+\.[0-9]*\] /) {
261                         ($timestamp, $null) = split(/]/, $line);
262                         $timestamp = $timestamp . "] ";
263
264                 } else {
265                         $timestamp = "";
266                 }
267         }
268
269         $line =~ s/^\[\s*[0-9]+\.[0-9]*\] //;
270
271
272         # -----  find EXPECT begin
273
274         if ($line =~ /^\s*$exp_begin/) {
275                 $data = $line;
276                 $data =~ s/^\s*$exp_begin//;
277                 push @begin, $data;
278
279                 if ($verbose) {
280                         if ($print_line_num) {
281                                 $line_num = sprintf("%4s ", $.);
282                         }
283                         printf "%s %s%s%s\n", $prefix, $line_num,  $timestamp, $line;
284                 }
285
286                 next LINE;
287         }
288
289
290         # -----  find EXPECT end
291
292         if ($line =~ /^\s*$exp_end/) {
293                 $data = $line;
294                 $data =~ s/^\s*$exp_end//;
295
296                 if ($verbose) {
297                         if ($print_line_num) {
298                                 $line_num = sprintf("%4s ", $.);
299                         }
300                         printf "%s %s%s%s\n", $prefix, $line_num,  $timestamp, $line;
301                 }
302
303                 $found = 0;
304                 $no_begin = 0;
305                 if (@found_or_begin > 0) {
306                         $begin = pop @found_or_begin;
307                         if (compare($data, $begin)) {
308                                 $found = 1;
309                         }
310                 } elsif (@begin > 0) {
311                         $begin = pop @begin;
312                 } else {
313                         $no_begin = 1;
314                 }
315
316                 if ($no_begin) {
317
318                         $expect_missing_begin++;
319                         print "** ERROR: EXPECT end without any EXPECT begin:\n";
320                         print "       end ---> $line\n";
321
322                 } elsif (! $found) {
323
324                         if ($print_line_num) {
325                                 $line_num = sprintf("%4s ", $.);
326                         }
327
328                         $expect_not_found++;
329                         printf "** %s%s$script_name WARNING - not found ---> %s\n",
330                                         $line_num,  $timestamp, $data;
331
332                 } elsif (! compare($data, $begin)) {
333
334                         $expect_missing_end++;
335                         print "** ERROR: EXPECT end does not match EXPECT begin:\n";
336                         print "       begin -> $begin\n";
337                         print "       end ---> $line\n";
338
339                 } else {
340
341                         $expect_found++;
342
343                 }
344
345                 next LINE;
346         }
347
348
349         # -----  not an EXPECT line
350
351         if (($line =~ /^${pr_fmt}start of unittest - you will see error messages$/) ||
352             ($line =~ /^${pr_fmt}end of unittest - [0-9]+ passed, [0-9]+ failed$/ )   ) {
353                 $prefix = "->"; # 2 characters
354         } elsif ($line =~ /^${pr_fmt}FAIL /) {
355                 $unittest_fail++;
356                 $prefix = ">>"; # 2 characters
357         }
358
359         $found = 0;
360         foreach $begin (@begin) {
361                 if (compare($begin, $line)) {
362                         $found = 1;
363                         last;
364                 }
365         }
366
367         if ($found) {
368                 $begin = shift @begin;
369                 while (! compare($begin, $line)) {
370                         push @found_or_begin, $begin;
371                         $begin = shift @begin;
372                 }
373                 push @found_or_begin, $line;
374
375                 if ($hide_expect) {
376                         $suppress_line = 1;
377                         next LINE;
378                 }
379                 $prefix = "ok"; # 2 characters
380         }
381
382
383         if ($print_line_num) {
384                 $line_num = sprintf("%4s ", $.);
385         }
386
387         printf "%s %s%s%s\n", $prefix, $line_num,  $timestamp, $line;
388 }
389
390 if (! $no_expect_stats) {
391         print  "\n";
392         print  "** EXPECT statistics:\n";
393         print  "**\n";
394         printf "**   EXPECT found          : %4i\n", $expect_found;
395         printf "**   EXPECT not found      : %4i\n", $expect_not_found;
396         printf "**   missing EXPECT begin  : %4i\n", $expect_missing_begin;
397         printf "**   missing EXPECT end    : %4i\n", $expect_missing_end;
398         printf "**   unittest FAIL         : %4i\n", $unittest_fail;
399         printf "**   internal error        : %4i\n", $internal_err;
400 }
401
402 if (@begin) {
403         print "** ERROR: EXPECT begin without any EXPECT end:\n";
404         print "          This list may be misleading.\n";
405         foreach $begin (@begin) {
406                 print "       begin ---> $begin\n";
407         }
408 }