Back to home page

OSCL-LXR

 
 

    


0001 #!/usr/bin/perl
0002 # SPDX-License-Identifier: GPL-2.0
0003 #
0004 # Copyright 2020, 2022 Sony Corporation
0005 #
0006 # Author: Frank Rowand
0007 
0008 # This program is meant to be an aid to reading the verbose output of
0009 # on the console log that results from executing the Linux kernel
0010 # devicetree unittest (drivers/of/unitest.c).
0011 
0012 $VUFX = "220201a";
0013 
0014 use strict 'refs';
0015 use strict subs;
0016 
0017 use Getopt::Long;
0018 use Text::Wrap;
0019 
0020 # strip off everything before final "/"
0021 (undef, $script_name) = split(/^.*\//, $0);
0022 
0023 # following /usr/include/sysexits.h
0024 $EX_OK=0;
0025 $EX_USAGE=64;
0026 
0027 
0028 #______________________________________________________________________________
0029 sub compare {
0030     my ($expect, $got) = @_;
0031     my $expect_next;
0032     my $expect_next_lit;
0033     my $got_next;
0034     my $type;
0035 
0036     while ($expect) {
0037 
0038         ($expect_next, $type) = split(/<</, $expect);
0039         ($type) = split(/>>/, $type);
0040         $expect =~ s/^.*?>>//;  # '?' is non-greedy, minimal match
0041 
0042         # literal, ignore all metacharacters when used in a regex
0043         $expect_next_lit = quotemeta($expect_next);
0044 
0045         $got_next = $got;
0046         $got_next =~ s/^($expect_next_lit).*/\1/;
0047         $got       =~ s/^$expect_next_lit//;
0048 
0049         if ($expect_next ne $got_next) {
0050             return 0;
0051         }
0052 
0053         if ($type eq "int") {
0054             if ($got =~ /^[+-]*[0-9]+/) {
0055                 $got =~ s/^[+-]*[0-9]+//;
0056             } else {
0057                 return 0;
0058             }
0059         } elsif ($type eq "hex") {
0060             if ($got =~ /^(0x)*[0-9a-f]+/) {
0061                 $got =~ s/^(0x)*[0-9a-f]+//;
0062             } else {
0063                 return 0;
0064             }
0065         } elsif ($type eq "") {
0066             if ($expect_next ne $got_next) {
0067                 return 0;
0068             } else {
0069                 return 1;
0070             }
0071         } else {
0072             $internal_err++;
0073             print "** ERROR: special pattern not recognized: <<$type>>, CONSOLE_LOG line: $.\n";
0074             return 0;
0075         }
0076 
0077     }
0078 
0079     # should not get here
0080     $internal_err++;
0081     print "** ERROR: $script_name internal error, at end of compare(), CONSOLE_LOG line: $.\n";
0082 
0083     return 0;
0084 }
0085 
0086 
0087 #______________________________________________________________________________
0088 sub usage {
0089 
0090 # ***** when editing, be careful to not put tabs in the string printed:
0091 
0092     print STDERR
0093 "
0094 usage:
0095 
0096   $script_name CONSOLE_LOG
0097 
0098      -h                print program usage
0099     --help             print program usage
0100     --hide-expect      suppress output of EXPECTed lines
0101     --line-num         report line number of CONSOLE_LOG
0102     --no-expect-stats  do not report EXPECT statistics
0103     --no-strip-ts      do not strip leading console timestamps
0104     --verbose          do not suppress EXPECT begin and end lines
0105     --version          print program version and exit
0106 
0107 
0108   Process a console log for EXPECTed test related messages to either
0109   highlight expected devicetree unittest related messages or suppress
0110   the messages.  Leading console timestamps will be stripped.
0111 
0112   Various unittests may trigger kernel messages from outside the
0113   unittest code.  The unittest annotates that it expects the message
0114   to occur with an 'EXPECT \\ : text' (begin) before triggering the
0115   message, and an 'EXPECT / : text' (end) after triggering the message.
0116 
0117   If an expected message does not occur, that will be reported.
0118 
0119   For each expected message, the 'EXPECT \\ : text' (begin) and
0120   'EXPECT / : text' (end), 'text' will contain the message text.
0121 
0122   If 'EXPECT \\' (begin) and 'EXPECT /' (end) lines do not contain
0123   matching 'text', that will be reported.
0124 
0125   If EXPECT lines are nested, 'EXPECT /' (end) lines must be in the
0126   reverse order of the corresponding 'EXPECT \\' (begin) lines.
0127 
0128   'EXPECT \\ : text' (begin) and 'EXPECT / : text' (end) lines can
0129   contain special patterns in 'text':
0130 
0131      <<int>> matches: [+-]*[0-9]+
0132      <<hex>> matches: (0x)*[0-9a-f]+
0133 
0134   'EXPECT \\' (begin) and 'EXPECT /' (end) lines are suppressed.
0135 
0136   A prefix is added to every line of output:
0137 
0138     'ok ' Line matches an enclosing EXPECT begin/end pair
0139 
0140     '** ' Line reports $script_name warning or error
0141 
0142     '-> ' Line reports start or end of the unittests
0143 
0144     '>> ' Line reports a unittest test FAIL
0145 
0146     '   ' Lines that are not otherwise prefixed
0147 
0148   Issues detected in CONSOLE_LOG are reported to STDOUT, not to STDERR.
0149 
0150   Known Issues:
0151 
0152     --line-num causes the CONSOLE_LOG line number to be printed in 4 columns.
0153        If CONSOLE_LOG contains more than 9999 lines then more columns will be
0154        used to report the line number for lines greater than 9999 (eg for
0155        lines 10000 - 99999, 5 columns will be used).
0156 ";
0157 
0158     return {};
0159 }
0160 
0161 #______________________________________________________________________________
0162 #______________________________________________________________________________
0163 
0164 if (!GetOptions(
0165     "h"               => \$help,
0166     "help"            => \$help,
0167     "hide-expect"     => \$hide_expect,
0168     "line-num"        => \$print_line_num,
0169     "no-expect-stats" => \$no_expect_stats,
0170     "no-strip-ts"     => \$no_strip_ts,
0171     "verbose"         => \$verbose,
0172     "version"         => \$version,
0173     )) {
0174     print STDERR "\n";
0175     print STDERR "ERROR processing command line options\n";
0176     print STDERR "\n";
0177     print STDERR "For help, type '$script_name --help'\n";
0178     print STDERR "\n";
0179 
0180     exit $EX_OK;
0181 }
0182 
0183 
0184 if ($no_strip_ts) {
0185     $strip_ts = 1;
0186     $no_strip_ts = 0;
0187 } else {
0188     $strip_ts = 0;
0189     $no_strip_ts = 1;
0190 }
0191 
0192 
0193 # - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
0194 if ($help){
0195 
0196     &usage;
0197 
0198     exit $EX_OK;
0199 }
0200 
0201 
0202 # - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
0203 
0204 if ($version) {
0205     print STDERR "\n$script_name  $VUFX\n\n";
0206     print STDERR "\n";
0207 
0208     exit $EX_OK;
0209 }
0210 
0211 
0212 # - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
0213 if ($#ARGV != 0) {
0214 
0215     # Limit input files to exactly one.
0216     #
0217     # 'while ($line = <ARGV>) {' in the code below supports multiple file
0218     # names on the command line, but the EXPECT statistics are reported
0219     # once for all input - it is not an expected use case to generate one
0220     # set of statistics for multiple input files.
0221 
0222     print STDERR "\n";
0223     print STDERR "Required arguments: CONSOLE_LOG\n";
0224     print STDERR "\n";
0225 
0226     exit $EX_USAGE;
0227 }
0228 
0229 
0230 #______________________________________________________________________________
0231 
0232 # Patterns to match 'EXPECT \ : ' (begin) and 'EXPECT / : ' (end)
0233 #
0234 # $exp_* are used as regex match patterns,
0235 # so '\\\\' in $exp_begin matches a single '\'
0236 # quotemeta() does not do the right thing in this case
0237 #
0238 # $pr_fmt is the prefix that unittest prints for every message
0239 
0240 $pr_fmt = "### dt-test ### ";
0241 $exp_begin = "${pr_fmt}EXPECT \\\\ : ";
0242 $exp_end   = "${pr_fmt}EXPECT / : ";
0243 
0244 
0245 $line_num = "";
0246 $timestamp = "";
0247 
0248 LINE:
0249 while ($line = <ARGV>) {
0250 
0251     chomp $line;
0252 
0253     $prefix = "  ";  ## 2 characters
0254 
0255 
0256     if ($strip_ts) {
0257 
0258         $timestamp = $line;
0259 
0260         if ($timestamp =~ /^\[\s*[0-9]+\.[0-9]*\] /) {
0261             ($timestamp, $null) = split(/]/, $line);
0262             $timestamp = $timestamp . "] ";
0263 
0264         } else {
0265             $timestamp = "";
0266         }
0267     }
0268 
0269     $line =~ s/^\[\s*[0-9]+\.[0-9]*\] //;
0270 
0271 
0272     # -----  find EXPECT begin
0273 
0274     if ($line =~ /^\s*$exp_begin/) {
0275         $data = $line;
0276         $data =~ s/^\s*$exp_begin//;
0277         push @begin, $data;
0278 
0279         if ($verbose) {
0280             if ($print_line_num) {
0281                 $line_num = sprintf("%4s ", $.);
0282             }
0283             printf "%s %s%s%s\n", $prefix, $line_num,  $timestamp, $line;
0284         }
0285 
0286         next LINE;
0287     }
0288 
0289 
0290     # -----  find EXPECT end
0291 
0292     if ($line =~ /^\s*$exp_end/) {
0293         $data = $line;
0294         $data =~ s/^\s*$exp_end//;
0295 
0296         if ($verbose) {
0297             if ($print_line_num) {
0298                 $line_num = sprintf("%4s ", $.);
0299             }
0300             printf "%s %s%s%s\n", $prefix, $line_num,  $timestamp, $line;
0301         }
0302 
0303         $found = 0;
0304         $no_begin = 0;
0305         if (@found_or_begin > 0) {
0306             $begin = pop @found_or_begin;
0307             if (compare($data, $begin)) {
0308                 $found = 1;
0309             }
0310         } elsif (@begin > 0) {
0311             $begin = pop @begin;
0312         } else {
0313             $no_begin = 1;
0314         }
0315 
0316         if ($no_begin) {
0317 
0318             $expect_missing_begin++;
0319             print "** ERROR: EXPECT end without any EXPECT begin:\n";
0320             print "       end ---> $line\n";
0321 
0322         } elsif (! $found) {
0323 
0324             if ($print_line_num) {
0325                 $line_num = sprintf("%4s ", $.);
0326             }
0327 
0328             $expect_not_found++;
0329             printf "** %s%s$script_name WARNING - not found ---> %s\n",
0330                     $line_num,  $timestamp, $data;
0331 
0332         } elsif (! compare($data, $begin)) {
0333 
0334             $expect_missing_end++;
0335             print "** ERROR: EXPECT end does not match EXPECT begin:\n";
0336             print "       begin -> $begin\n";
0337             print "       end ---> $line\n";
0338 
0339         } else {
0340 
0341             $expect_found++;
0342 
0343         }
0344 
0345         next LINE;
0346     }
0347 
0348 
0349     # -----  not an EXPECT line
0350 
0351     if (($line =~ /^${pr_fmt}start of unittest - you will see error messages$/) ||
0352         ($line =~ /^${pr_fmt}end of unittest - [0-9]+ passed, [0-9]+ failed$/ )   ) {
0353         $prefix = "->"; # 2 characters
0354     } elsif ($line =~ /^${pr_fmt}FAIL /) {
0355         $unittest_fail++;
0356         $prefix = ">>"; # 2 characters
0357     }
0358 
0359     $found = 0;
0360     foreach $begin (@begin) {
0361         if (compare($begin, $line)) {
0362             $found = 1;
0363             last;
0364         }
0365     }
0366 
0367     if ($found) {
0368         $begin = shift @begin;
0369         while (! compare($begin, $line)) {
0370             push @found_or_begin, $begin;
0371             $begin = shift @begin;
0372         }
0373         push @found_or_begin, $line;
0374 
0375         if ($hide_expect) {
0376             $suppress_line = 1;
0377             next LINE;
0378         }
0379         $prefix = "ok"; # 2 characters
0380     }
0381 
0382 
0383     if ($print_line_num) {
0384         $line_num = sprintf("%4s ", $.);
0385     }
0386 
0387     printf "%s %s%s%s\n", $prefix, $line_num,  $timestamp, $line;
0388 }
0389 
0390 if (! $no_expect_stats) {
0391     print  "\n";
0392     print  "** EXPECT statistics:\n";
0393     print  "**\n";
0394     printf "**   EXPECT found          : %4i\n", $expect_found;
0395     printf "**   EXPECT not found      : %4i\n", $expect_not_found;
0396     printf "**   missing EXPECT begin  : %4i\n", $expect_missing_begin;
0397     printf "**   missing EXPECT end    : %4i\n", $expect_missing_end;
0398     printf "**   unittest FAIL         : %4i\n", $unittest_fail;
0399     printf "**   internal error        : %4i\n", $internal_err;
0400 }
0401 
0402 if (@begin) {
0403     print "** ERROR: EXPECT begin without any EXPECT end:\n";
0404     print "          This list may be misleading.\n";
0405     foreach $begin (@begin) {
0406         print "       begin ---> $begin\n";
0407     }
0408 }