cachepc-qemu

Fork of AMDESE/qemu with changes for cachepc side-channel attack
git clone https://git.sinitax.com/sinitax/cachepc-qemu
Log | Files | Refs | Submodules | LICENSE | sfeed.txt

tap-driver.pl (9944B)


      1#! /usr/bin/env perl
      2# Copyright (C) 2011-2013 Free Software Foundation, Inc.
      3# Copyright (C) 2018 Red Hat, Inc.
      4#
      5# This program is free software; you can redistribute it and/or modify
      6# it under the terms of the GNU General Public License as published by
      7# the Free Software Foundation; either version 2, or (at your option)
      8# any later version.
      9#
     10# This program is distributed in the hope that it will be useful,
     11# but WITHOUT ANY WARRANTY; without even the implied warranty of
     12# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
     13# GNU General Public License for more details.
     14#
     15# You should have received a copy of the GNU General Public License
     16# along with this program.  If not, see <https://www.gnu.org/licenses/>.
     17
     18# As a special exception to the GNU General Public License, if you
     19# distribute this file as part of a program that contains a
     20# configuration script generated by Autoconf, you may include it under
     21# the same distribution terms that you use for the rest of that program.
     22
     23# ---------------------------------- #
     24#  Imports, static data, and setup.  #
     25# ---------------------------------- #
     26
     27use warnings FATAL => 'all';
     28use strict;
     29use Getopt::Long ();
     30use TAP::Parser;
     31use Term::ANSIColor qw(:constants);
     32
     33my $ME = "tap-driver.pl";
     34my $VERSION = "2018-11-30";
     35
     36my $USAGE = <<'END';
     37Usage:
     38  tap-driver [--test-name=TEST] [--color={always|never|auto}]
     39             [--verbose] [--show-failures-only]
     40END
     41
     42my $HELP = "$ME: TAP-aware test driver for QEMU testsuite harness." .
     43           "\n" . $USAGE;
     44
     45# It's important that NO_PLAN evaluates "false" as a boolean.
     46use constant NO_PLAN => 0;
     47use constant EARLY_PLAN => 1;
     48use constant LATE_PLAN => 2;
     49
     50use constant DIAG_STRING => "#";
     51
     52# ------------------- #
     53#  Global variables.  #
     54# ------------------- #
     55
     56my $testno = 0;     # Number of test results seen so far.
     57my $bailed_out = 0; # Whether a "Bail out!" directive has been seen.
     58my $failed = 0;     # Final exit code
     59
     60# Whether the TAP plan has been seen or not, and if yes, which kind
     61# it is ("early" is seen before any test result, "late" otherwise).
     62my $plan_seen = NO_PLAN;
     63
     64# ----------------- #
     65#  Option parsing.  #
     66# ----------------- #
     67
     68my %cfg = (
     69  "color" => 0,
     70  "verbose" => 0,
     71  "show-failures-only" => 0,
     72);
     73
     74my $color = "auto";
     75my $test_name = undef;
     76
     77# Perl's Getopt::Long allows options to take optional arguments after a space.
     78# Prevent --color by itself from consuming other arguments
     79foreach (@ARGV) {
     80  if ($_ eq "--color" || $_ eq "-color") {
     81    $_ = "--color=$color";
     82  }
     83}
     84
     85Getopt::Long::GetOptions
     86  (
     87    'help' => sub { print $HELP; exit 0; },
     88    'version' => sub { print "$ME $VERSION\n"; exit 0; },
     89    'test-name=s' => \$test_name,
     90    'color=s'  => \$color,
     91    'show-failures-only' => sub { $cfg{"show-failures-only"} = 1; },
     92    'verbose' => sub { $cfg{"verbose"} = 1; },
     93  ) or exit 1;
     94
     95if ($color =~ /^always$/i) {
     96  $cfg{'color'} = 1;
     97} elsif ($color =~ /^never$/i) {
     98  $cfg{'color'} = 0;
     99} elsif ($color =~ /^auto$/i) {
    100  $cfg{'color'} = (-t STDOUT);
    101} else {
    102  die "Invalid color mode: $color\n";
    103}
    104
    105# ------------- #
    106#  Prototypes.  #
    107# ------------- #
    108
    109sub colored ($$);
    110sub decorate_result ($);
    111sub extract_tap_comment ($);
    112sub handle_tap_bailout ($);
    113sub handle_tap_plan ($);
    114sub handle_tap_result ($);
    115sub is_null_string ($);
    116sub main ();
    117sub report ($;$);
    118sub stringify_result_obj ($);
    119sub testsuite_error ($);
    120
    121# -------------- #
    122#  Subroutines.  #
    123# -------------- #
    124
    125# If the given string is undefined or empty, return true, otherwise
    126# return false.  This function is useful to avoid pitfalls like:
    127#   if ($message) { print "$message\n"; }
    128# which wouldn't print anything if $message is the literal "0".
    129sub is_null_string ($)
    130{
    131  my $str = shift;
    132  return ! (defined $str and length $str);
    133}
    134
    135sub stringify_result_obj ($)
    136{
    137  my $result_obj = shift;
    138  if ($result_obj->is_unplanned || $result_obj->number != $testno)
    139    {
    140      return "ERROR";
    141    }
    142  elsif ($plan_seen == LATE_PLAN)
    143    {
    144      return "ERROR";
    145    }
    146  elsif (!$result_obj->directive)
    147    {
    148      return $result_obj->is_ok ? "PASS" : "FAIL";
    149    }
    150  elsif ($result_obj->has_todo)
    151    {
    152      return $result_obj->is_actual_ok ? "XPASS" : "XFAIL";
    153    }
    154  elsif ($result_obj->has_skip)
    155    {
    156      return $result_obj->is_ok ? "SKIP" : "FAIL";
    157    }
    158  die "$ME: INTERNAL ERROR"; # NOTREACHED
    159}
    160
    161sub colored ($$)
    162{
    163  my ($color_string, $text) = @_;
    164  return $color_string . $text . RESET;
    165}
    166
    167sub decorate_result ($)
    168{
    169  my $result = shift;
    170  return $result unless $cfg{"color"};
    171  my %color_for_result =
    172    (
    173      "ERROR" => BOLD.MAGENTA,
    174      "PASS"  => GREEN,
    175      "XPASS" => BOLD.YELLOW,
    176      "FAIL"  => BOLD.RED,
    177      "XFAIL" => YELLOW,
    178      "SKIP"  => BLUE,
    179    );
    180  if (my $color = $color_for_result{$result})
    181    {
    182      return colored ($color, $result);
    183    }
    184  else
    185    {
    186      return $result; # Don't colorize unknown stuff.
    187    }
    188}
    189
    190sub report ($;$)
    191{
    192  my ($msg, $result, $explanation) = (undef, @_);
    193  if ($result =~ /^(?:X?(?:PASS|FAIL)|SKIP|ERROR)/)
    194    {
    195      # Output on console might be colorized.
    196      $msg = decorate_result($result);
    197      if ($result =~ /^(?:PASS|XFAIL|SKIP)/)
    198        {
    199          return if $cfg{"show-failures-only"};
    200        }
    201      else
    202        {
    203          $failed = 1;
    204        }
    205    }
    206  elsif ($result eq "#")
    207    {
    208      $msg = "  ";
    209    }
    210  else
    211    {
    212      die "$ME: INTERNAL ERROR"; # NOTREACHED
    213    }
    214  $msg .= " $explanation" if defined $explanation;
    215  print $msg . "\n";
    216}
    217
    218sub testsuite_error ($)
    219{
    220  report "ERROR", "$test_name - $_[0]";
    221}
    222
    223sub handle_tap_result ($)
    224{
    225  $testno++;
    226  my $result_obj = shift;
    227
    228  my $test_result = stringify_result_obj $result_obj;
    229  my $string = $result_obj->number;
    230
    231  my $description = $result_obj->description;
    232  $string .= " $test_name" unless is_null_string $test_name;
    233  $string .= " $description" unless is_null_string $description;
    234
    235  if ($plan_seen == LATE_PLAN)
    236    {
    237      $string .= " # AFTER LATE PLAN";
    238    }
    239  elsif ($result_obj->is_unplanned)
    240    {
    241      $string .= " # UNPLANNED";
    242    }
    243  elsif ($result_obj->number != $testno)
    244    {
    245      $string .= " # OUT-OF-ORDER (expecting $testno)";
    246    }
    247  elsif (my $directive = $result_obj->directive)
    248    {
    249      $string .= " # $directive";
    250      my $explanation = $result_obj->explanation;
    251      $string .= " $explanation"
    252        unless is_null_string $explanation;
    253    }
    254
    255  report $test_result, $string;
    256}
    257
    258sub handle_tap_plan ($)
    259{
    260  my $plan = shift;
    261  if ($plan_seen)
    262    {
    263      # Error, only one plan per stream is acceptable.
    264      testsuite_error "multiple test plans";
    265      return;
    266    }
    267  # The TAP plan can come before or after *all* the TAP results; we speak
    268  # respectively of an "early" or a "late" plan.  If we see the plan line
    269  # after at least one TAP result has been seen, assume we have a late
    270  # plan; in this case, any further test result seen after the plan will
    271  # be flagged as an error.
    272  $plan_seen = ($testno >= 1 ? LATE_PLAN : EARLY_PLAN);
    273  # If $testno > 0, we have an error ("too many tests run") that will be
    274  # automatically dealt with later, so don't worry about it here.  If
    275  # $plan_seen is true, we have an error due to a repeated plan, and that
    276  # has already been dealt with above.  Otherwise, we have a valid "plan
    277  # with SKIP" specification, and should report it as a particular kind
    278  # of SKIP result.
    279  if ($plan->directive && $testno == 0)
    280    {
    281      my $explanation = is_null_string ($plan->explanation) ?
    282                        undef : "- " . $plan->explanation;
    283      report "SKIP", $explanation;
    284    }
    285}
    286
    287sub handle_tap_bailout ($)
    288{
    289  my ($bailout, $msg) = ($_[0], "Bail out!");
    290  $bailed_out = 1;
    291  $msg .= " " . $bailout->explanation
    292    unless is_null_string $bailout->explanation;
    293  testsuite_error $msg;
    294}
    295
    296sub extract_tap_comment ($)
    297{
    298  my $line = shift;
    299  if (index ($line, DIAG_STRING) == 0)
    300    {
    301      # Strip leading `DIAG_STRING' from `$line'.
    302      $line = substr ($line, length (DIAG_STRING));
    303      # And strip any leading and trailing whitespace left.
    304      $line =~ s/(?:^\s*|\s*$)//g;
    305      # Return what is left (if any).
    306      return $line;
    307    }
    308  return "";
    309}
    310
    311sub main ()
    312{
    313  my $iterator = TAP::Parser::Iterator::Stream->new(\*STDIN);
    314  my $parser = TAP::Parser->new ({iterator => $iterator });
    315
    316  STDOUT->autoflush(1);
    317  while (defined (my $cur = $parser->next))
    318    {
    319      # Parsing of TAP input should stop after a "Bail out!" directive.
    320      next if $bailed_out;
    321
    322      if ($cur->is_plan)
    323        {
    324          handle_tap_plan ($cur);
    325        }
    326      elsif ($cur->is_test)
    327        {
    328          handle_tap_result ($cur);
    329        }
    330      elsif ($cur->is_bailout)
    331        {
    332          handle_tap_bailout ($cur);
    333        }
    334      elsif ($cfg{"verbose"})
    335        {
    336          my $comment = extract_tap_comment ($cur->raw);
    337          report "#", "$comment" if length $comment;
    338       }
    339    }
    340  # A "Bail out!" directive should cause us to ignore any following TAP
    341  # error.
    342  if (!$bailed_out)
    343    {
    344      if (!$plan_seen)
    345        {
    346          testsuite_error "missing test plan";
    347        }
    348      elsif ($parser->tests_planned != $parser->tests_run)
    349        {
    350          my ($planned, $run) = ($parser->tests_planned, $parser->tests_run);
    351          my $bad_amount = $run > $planned ? "many" : "few";
    352          testsuite_error (sprintf "too %s tests run (expected %d, got %d)",
    353                                   $bad_amount, $planned, $run);
    354        }
    355    }
    356}
    357
    358# ----------- #
    359#  Main code. #
    360# ----------- #
    361
    362main;
    363exit($failed);
    364
    365# Local Variables:
    366# perl-indent-level: 2
    367# perl-continued-statement-offset: 2
    368# perl-continued-brace-offset: 0
    369# perl-brace-offset: 0
    370# perl-brace-imaginary-offset: 0
    371# perl-label-offset: -2
    372# cperl-indent-level: 2
    373# cperl-brace-offset: 0
    374# cperl-continued-brace-offset: 0
    375# cperl-label-offset: -2
    376# cperl-extra-newline-before-brace: t
    377# cperl-merge-trailing-else: nil
    378# cperl-continued-statement-offset: 2
    379# End: