[PATCH 2/3] testbot/WineRunTask: Make the Wine report parser reusable.

Francois Gouget fgouget at codeweavers.com
Wed Jun 27 01:03:59 CDT 2018


Moving it to LogUtils.pm makes it possible to reuse it in future
scripts.

Signed-off-by: Francois Gouget <fgouget at codeweavers.com>
---
 testbot/bin/WineRunTask.pl          | 276 ++-----------------------
 testbot/lib/WineTestBot/LogUtils.pm | 310 +++++++++++++++++++++++++++-
 2 files changed, 322 insertions(+), 264 deletions(-)

diff --git a/testbot/bin/WineRunTask.pl b/testbot/bin/WineRunTask.pl
index 9faae28c3..821ca55ea 100755
--- a/testbot/bin/WineRunTask.pl
+++ b/testbot/bin/WineRunTask.pl
@@ -44,6 +44,7 @@ use WineTestBot::Config;
 use WineTestBot::Jobs;
 use WineTestBot::VMs;
 use WineTestBot::Log;
+use WineTestBot::LogUtils;
 use WineTestBot::Engine::Notify;
 
 
@@ -527,275 +528,24 @@ Debug(Elapsed($Start), " Retrieving the report file to '$RptFileName'\n");
 if ($TA->GetFile($RptFileName, "$TaskDir/$RptFileName"))
 {
   chmod 0664, "$TaskDir/$RptFileName";
-  if (open(my $LogFile, "<", "$TaskDir/$RptFileName"))
-  {
-    # There is more than one test unit when running the full test suite so keep
-    # track of the current one. Note that for the TestBot we don't count or
-    # complain about misplaced skips.
-    my ($CurrentDll, $CurrentUnit) = ("", "");
-    my $UnitSize = 0;
-    my ($LineFailures, $LineTodos, $LineSkips) = (0, 0, 0);
-    my ($SummaryFailures, $SummaryTodos, $SummarySkips) = (0, 0, 0);
-    my ($CurrentIsBroken, %CurrentPids, $CurrentRc, $LogFailures);
-
-    sub CheckUnit($$)
-    {
-      my ($Unit, $Type) = @_;
-      if ($Unit eq $CurrentUnit or $CurrentUnit eq "")
-      {
-        $IsWineTest = 1;
-      }
-      # To avoid issuing many duplicate errors,
-      # only report the first misplaced message.
-      elsif ($IsWineTest and !$CurrentIsBroken)
-      {
-        LogTaskError("$CurrentDll:$CurrentUnit contains a misplaced $Type message for $Unit\n");
-        $LogFailures++;
-        $CurrentIsBroken = 1;
-      }
-    }
-
-    sub CheckSummaryCounter($$$)
-    {
-      my ($Count, $SCount, $Type) = @_;
-
-      if ($Count != 0 and $SCount == 0)
-      {
-        LogTaskError("$CurrentDll:$CurrentUnit has unaccounted for $Type messages\n");
-        $LogFailures++;
-      }
-      elsif ($Count == 0 and $SCount != 0)
-      {
-        LogTaskError("$CurrentDll:$CurrentUnit is missing some $Type messages\n");
-        $LogFailures++;
-      }
-    }
-
-    sub CloseTestUnit($)
-    {
-      my ($Last) = @_;
-
-      # Verify the summary lines
-      if (!$CurrentIsBroken)
-      {
-        CheckSummaryCounter($LineFailures, $SummaryFailures, "failure");
-        CheckSummaryCounter($LineTodos, $SummaryTodos, "todo");
-        CheckSummaryCounter($LineSkips, $SummarySkips, "skip");
-      }
-
-      # Note that the summary lines may count some failures twice
-      # so only use them as a fallback.
-      $LineFailures ||= $SummaryFailures;
-
-      if ($UnitSize > $MaxUnitSize)
-      {
-        LogTaskError("$CurrentDll:$CurrentUnit prints too much data ($UnitSize bytes)\n");
-        $LogFailures++;
-      }
-      if (!$CurrentIsBroken and defined $CurrentRc)
-      {
-        # Check the exit code, particularly against failures reported
-        # after the 'done' line (e.g. by subprocesses).
-        if ($LineFailures != 0 and $CurrentRc == 0)
-        {
-          LogTaskError("$CurrentDll:$CurrentUnit returned success despite having failures\n");
-          $LogFailures++;
-        }
-        elsif (!$IsWineTest and $CurrentRc != 0)
-        {
-          LogTaskError("The test returned a non-zero exit code\n");
-          $LogFailures++;
-        }
-        elsif ($IsWineTest and $LineFailures == 0 and $CurrentRc != 0)
-        {
-          LogTaskError("$CurrentDll:$CurrentUnit returned a non-zero exit code despite reporting no failures\n");
-          $LogFailures++;
-        }
-      }
-      # For executables TestLauncher's done line may not be recognizable.
-      elsif ($IsWineTest and !defined $CurrentRc)
-      {
-        if (!$Last)
-        {
-          LogTaskError("$CurrentDll:$CurrentUnit has no done line (or it is garbled)\n");
-        }
-        elsif ($Last and !$TaskTimedOut)
-        {
-          LogTaskError("The report seems to have been truncated\n");
-        }
-        $LogFailures++;
-      }
-
-      $LogFailures += $LineFailures;
-
-      $CurrentDll = $CurrentUnit = "";
-      $UnitSize = 0;
-      $LineFailures = $LineTodos = $LineSkips = 0;
-      $SummaryFailures = $SummaryTodos = $SummarySkips = 0;
-      $CurrentIsBroken = 0;
-      $CurrentRc = undef;
-      %CurrentPids = ();
-    }
-
-    foreach my $Line (<$LogFile>)
-    {
-      $UnitSize += length($Line);
-      if ($Line =~ m%^([_.a-z0-9-]+):([_a-z0-9]*) (start|skipped) (?:-|[/_.a-z0-9]+) (?:-|[.0-9a-f]+)\r?$%)
-      {
-        my ($Dll, $Unit, $Type) = ($1, $2, $3);
-
-        # Close the previous test unit
-        CloseTestUnit(0) if ($CurrentDll ne "");
-
-        ($CurrentDll, $CurrentUnit) = ($Dll, $Unit);
-
-        # Recognize skipped messages in case we need to skip tests in the VMs
-        $CurrentRc = 0 if ($Type eq "skipped");
-      }
-      elsif ($Line =~ /^([_a-z0-9]+)\.c:\d+: Test (?:failed|succeeded inside todo block): / or
-             ($CurrentUnit ne "" and
-              $Line =~ /($CurrentUnit)\.c:\d+: Test (?:failed|succeeded inside todo block): /))
-      {
-        CheckUnit($1, "failure");
-        $LineFailures++;
-      }
-      elsif ($Line =~ /^([_a-z0-9]+)\.c:\d+: Test marked todo: / or
-             ($CurrentUnit ne "" and
-              $Line =~ /($CurrentUnit)\.c:\d+: Test marked todo: /))
-      {
-        CheckUnit($1, "todo");
-        $LineTodos++;
-      }
-      # TestLauncher's skip message is quite broken
-      elsif ($Line =~ /^([_a-z0-9]+)(?:\.c)?:\d+:? Tests? skipped: / or
-             ($CurrentUnit ne "" and
-              $Line =~ /($CurrentUnit)(?:\.c)?:\d+:? Tests? skipped: /))
-      {
-        my $Unit = $1;
-        # Don't complain and don't count misplaced skips. Only complain if they
-        # are misreported (see CloseTestUnit). Also TestLauncher uses the wrong
-        # name in its skip message when skipping tests.
-        if ($Unit eq $CurrentUnit or $CurrentUnit eq "" or $Unit eq $CurrentDll)
-        {
-          $LineSkips++;
-        }
-      }
-      elsif ($Line =~ /^Fatal: test '([_a-z0-9]+)' does not exist/)
-      {
-        # This also replaces a test summary line.
-        $CurrentPids{0} = 1;
-        $SummaryFailures++;
-        $IsWineTest = 1;
-
-        $LineFailures++;
-      }
-      elsif ($Line =~ /^(?:([0-9a-f]+):)?([_.a-z0-9]+): unhandled exception [0-9a-fA-F]{8} at / or
-             ($CurrentUnit ne "" and
-              $Line =~ /(?:([0-9a-f]+):)?($CurrentUnit): unhandled exception [0-9a-fA-F]{8} at /))
-      {
-        my ($Pid, $Unit) = ($1, $2);
-
-        if ($Unit eq $CurrentUnit)
-        {
-          # This also replaces a test summary line.
-          $CurrentPids{$Pid || 0} = 1;
-          $SummaryFailures++;
-        }
-        CheckUnit($Unit, "unhandled exception");
-        $LineFailures++;
-      }
-      elsif ($Line =~ /^(?:([0-9a-f]+):)?([_a-z0-9]+): \d+ tests? executed \((\d+) marked as todo, (\d+) failures?\), (\d+) skipped\./ or
-             ($CurrentUnit ne "" and
-              $Line =~ /(?:([0-9a-f]+):)?($CurrentUnit): \d+ tests? executed \((\d+) marked as todo, (\d+) failures?\), (\d+) skipped\./))
-      {
-        my ($Pid, $Unit, $Todos, $Failures, $Skips) = ($1, $2, $3, $4, $5);
-
-        # Dlls that have only one test unit will run it even if there is
-        # no argument. Also TestLauncher uses the wrong name in its test
-        # summary line when skipping tests.
-        if ($Unit eq $CurrentUnit or $CurrentUnit eq "" or $Unit eq $CurrentDll)
-        {
-          # There may be more than one summary line due to child processes
-          $CurrentPids{$Pid || 0} = 1;
-          $SummaryFailures += $Failures;
-          $SummaryTodos += $Todos;
-          $SummarySkips += $Skips;
-          $IsWineTest = 1;
-        }
-        else
-        {
-          CheckUnit($Unit, "test summary") if ($Todos or $Failures);
-        }
-      }
-      elsif ($Line =~ /^([_.a-z0-9-]+):([_a-z0-9]*)(?::([0-9a-f]+))? done \((-?\d+)\)(?:\r?$| in)/ or
-             ($CurrentDll ne "" and
-              $Line =~ /(\Q$CurrentDll\E):([_a-z0-9]*)(?::([0-9a-f]+))? done \((-?\d+)\)(?:\r?$| in)/))
-      {
-        my ($Dll, $Unit, $Pid, $Rc) = ($1, $2, $3, $4);
-
-        if ($IsWineTest and ($Dll ne $CurrentDll or $Unit ne $CurrentUnit))
-        {
-          # First close the current test unit taking into account
-          # it may have been polluted by the new one.
-          $LogFailures++;
-          $CurrentIsBroken = 1;
-          CloseTestUnit(0);
-
-          # Then switch to the new one, warning it's missing a start line,
-          # and that its results may be inconsistent.
-          ($CurrentDll, $CurrentUnit) = ($Dll, $Unit);
-          LogTaskError("$Dll:$Unit had no start line (or it is garbled)\n");
-          $CurrentIsBroken = 1;
-        }
-
-        if ($Rc == 258)
-        {
-          # The done line will already be shown as a timeout (see JobDetails)
-          # so record the failure but don't add an error message.
-          $LogFailures++;
-          $CurrentIsBroken = 1;
-          $TimedOut = ($Step->Type ne "suite");
-        }
-        elsif ((!$Pid and !%CurrentPids) or
-               ($Pid and !$CurrentPids{$Pid} and !$CurrentPids{0}))
-        {
-          # The main summary line is missing
-          if ($Rc & 0xc0000000)
-          {
-            LogTaskError(sprintf("%s:%s crashed (%08x)\n", $Dll, $Unit, $Rc & 0xffffffff));
-            $LogFailures++;
-            $CurrentIsBroken = 1;
-          }
-          elsif ($IsWineTest and !$CurrentIsBroken)
-          {
-            LogTaskError("$Dll:$Unit has no test summary line (early exit of the main process?)\n");
-            $LogFailures++;
-          }
-        }
-        elsif ($Rc & 0xc0000000)
-        {
-          # We know the crash happened in the main process which means we got
-          # an "unhandled exception" message. So there is no need to add an
-          # extra message or to increment the failure count. Still note that
-          # there may be inconsistencies (e.g. unreported todos or skips).
-          $CurrentIsBroken = 1;
-        }
-        $CurrentRc = $Rc;
-      }
-    }
-    $CurrentIsBroken = 1 if ($TaskTimedOut);
-    CloseTestUnit(1);
-    close($LogFile);
 
-    # $LogFailures can legitimately be undefined in case of a timeout
-    $TaskFailures += $LogFailures || 0;
-  }
-  else
+  (my $LogFailures, my $LogErrors, $TimedOut) = ParseWineTestReport("$TaskDir/$RptFileName", $IsWineTest, $Step->Type eq "suite", $TaskTimedOut);
+  if (!defined $LogFailures and @$LogErrors == 1)
   {
+    # Could not open the file
     $NewStatus = 'boterror';
     Error "Unable to open '$RptFileName' for reading: $!\n";
     LogTaskError("Unable to open '$RptFileName' for reading: $!\n");
   }
+  else
+  {
+    # $LogFailures can legitimately be undefined in case of a timeout
+    $TaskFailures += $LogFailures || 0;
+    foreach my $Error (@$LogErrors)
+    {
+      LogTaskError("$Error\n");
+    }
+  }
 }
 elsif (!defined $TAError)
 {
diff --git a/testbot/lib/WineTestBot/LogUtils.pm b/testbot/lib/WineTestBot/LogUtils.pm
index 3dfd7c5e7..363f80827 100644
--- a/testbot/lib/WineTestBot/LogUtils.pm
+++ b/testbot/lib/WineTestBot/LogUtils.pm
@@ -27,7 +27,12 @@ WineTestBot::LogUtils - Provides functions to parse task logs
 
 
 use Exporter 'import';
-our @EXPORT = qw(GetLogFileNames GetLogLabel GetLogLineCategory ParseTaskLog);
+our @EXPORT = qw(GetLogFileNames GetLogLabel GetLogLineCategory
+                 ParseTaskLog ParseWineTestReport);
+
+use File::Basename;
+
+use WineTestBot::Config; # For $MaxUnitSize
 
 
 #
@@ -75,6 +80,309 @@ sub ParseTaskLog($$)
 }
 
 
+#
+# WineTest report parser
+#
+
+sub _NewCurrentUnit($$)
+{
+  my ($Dll, $Unit) = @_;
+
+  return {
+    # There is more than one test unit when running the full test suite so keep
+    # track of the current one. Note that for the TestBot we don't count or
+    # complain about misplaced skips.
+    Dll => $Dll,
+    Unit => $Unit,
+    UnitSize => 0,
+    LineFailures => 0,
+    LineTodos => 0,
+    LineSkips => 0,
+    SummaryFailures => 0,
+    SummaryTodos => 0,
+    SummarySkips => 0,
+    IsBroken => 0,
+    Rc => undef,
+    Pids => {},
+  };
+}
+
+sub _AddError($$;$)
+{
+  my ($Parser, $Error, $Cur) = @_;
+
+  $Error = "$Cur->{Dll}:$Cur->{Unit} $Error" if (defined $Cur);
+  push @{$Parser->{Errors}}, $Error;
+  $Parser->{Failures}++;
+}
+
+sub _CheckUnit($$$$)
+{
+  my ($Parser, $Cur, $Unit, $Type) = @_;
+
+  if ($Unit eq $Cur->{Unit} or $Cur->{Unit} eq "")
+  {
+    $Parser->{IsWineTest} = 1;
+  }
+  # To avoid issuing many duplicate errors,
+  # only report the first misplaced message.
+  elsif ($Parser->{IsWineTest} and !$Cur->{IsBroken})
+  {
+    _AddError($Parser, "contains a misplaced $Type message for $Unit", $Cur);
+    $Cur->{IsBroken} = 1;
+  }
+}
+
+sub _CheckSummaryCounter($$$$)
+{
+  my ($Parser, $Cur, $Field, $Type) = @_;
+
+  if ($Cur->{"Line$Field"} != 0 and $Cur->{"Summary$Field"} == 0)
+  {
+    _AddError($Parser, "has unaccounted for $Type messages", $Cur);
+  }
+  elsif ($Cur->{"Line$Field"} == 0 and $Cur->{"Summary$Field"} != 0)
+  {
+    _AddError($Parser, "is missing some $Type messages", $Cur);
+  }
+}
+
+sub _CloseTestUnit($$$)
+{
+  my ($Parser, $Cur, $Last) = @_;
+
+  # Verify the summary lines
+  if (!$Cur->{IsBroken})
+  {
+    _CheckSummaryCounter($Parser, $Cur, "Failures", "failure");
+    _CheckSummaryCounter($Parser, $Cur, "Todos", "todo");
+    _CheckSummaryCounter($Parser, $Cur, "Skips", "skip");
+  }
+
+  # Note that the summary lines may count some failures twice
+  # so only use them as a fallback.
+  $Cur->{LineFailures} ||= $Cur->{SummaryFailures};
+
+  if ($Cur->{UnitSize} > $MaxUnitSize)
+  {
+    _AddError($Parser, "prints too much data ($Cur->{UnitSize} bytes)", $Cur);
+  }
+  if (!$Cur->{IsBroken} and defined $Cur->{Rc})
+  {
+    # Check the exit code, particularly against failures reported
+    # after the 'done' line (e.g. by subprocesses).
+    if ($Cur->{LineFailures} != 0 and $Cur->{Rc} == 0)
+    {
+      _AddError($Parser, "returned success despite having failures", $Cur);
+    }
+    elsif (!$Parser->{IsWineTest} and $Cur->{Rc} != 0)
+    {
+      _AddError($Parser, "The test returned a non-zero exit code");
+    }
+    elsif ($Parser->{IsWineTest} and $Cur->{LineFailures} == 0 and $Cur->{Rc} != 0)
+    {
+      _AddError($Parser, "returned a non-zero exit code despite reporting no failures", $Cur);
+    }
+  }
+  # For executables TestLauncher's done line may not be recognizable.
+  elsif ($Parser->{IsWineTest} and !defined $Cur->{Rc})
+  {
+    if (!$Last)
+    {
+      _AddError($Parser, "has no done line (or it is garbled)", $Cur);
+    }
+    elsif ($Last and !$Parser->{TaskTimedOut})
+    {
+      _AddError($Parser, "The report seems to have been truncated");
+    }
+  }
+
+  $Parser->{Failures} += $Cur->{LineFailures};
+}
+
+=pod
+=over 12
+
+=item C<ParseWineTestReport()>
+
+Parses a Wine test report and returns the number of failures and extra errors,
+a list of extra errors, and whether the test timed out.
+
+=back
+=cut
+
+sub ParseWineTestReport($$$$)
+{
+  my ($FileName, $IsWineTest, $IsSuite, $TaskTimedOut) = @_;
+
+  my $LogFile;
+  if (!open($LogFile, "<", $FileName))
+  {
+    my $BaseName = basename($FileName);
+    return (undef, ["Unable to open '$BaseName' for reading: $!"], undef);
+  }
+
+  my $Parser = {
+    IsWineTest => $IsWineTest,
+    IsSuite => $IsSuite,
+    TaskTimedOut => $TaskTimedOut,
+
+    TimedOut => undef,
+    Failures => undef,
+    Errors => [],
+  };
+
+  my $Cur = _NewCurrentUnit("", "");
+  foreach my $Line (<$LogFile>)
+  {
+    $Cur->{UnitSize} += length($Line);
+    if ($Line =~ m%^([_.a-z0-9-]+):([_a-z0-9]*) (start|skipped) (?:-|[/_.a-z0-9]+) (?:-|[.0-9a-f]+)\r?$%)
+    {
+      my ($Dll, $Unit, $Type) = ($1, $2, $3);
+
+      # Close the previous test unit
+      _CloseTestUnit($Parser, $Cur, 0) if ($Cur->{Dll} ne "");
+      $Cur = _NewCurrentUnit($Dll, $Unit);
+
+      # Recognize skipped messages in case we need to skip tests in the VMs
+      $Cur->{Rc} = 0 if ($Type eq "skipped");
+    }
+    elsif ($Line =~ /^([_a-z0-9]+)\.c:\d+: Test (?:failed|succeeded inside todo block): / or
+           ($Cur->{Unit} ne "" and
+            $Line =~ /($Cur->{Unit})\.c:\d+: Test (?:failed|succeeded inside todo block): /))
+    {
+      _CheckUnit($Parser, $Cur, $1, "failure");
+      $Cur->{LineFailures}++;
+    }
+    elsif ($Line =~ /^([_a-z0-9]+)\.c:\d+: Test marked todo: / or
+           ($Cur->{Unit} ne "" and
+            $Line =~ /($Cur->{Unit})\.c:\d+: Test marked todo: /))
+    {
+      _CheckUnit($Parser, $Cur, $1, "todo");
+      $Cur->{LineTodos}++;
+    }
+    # TestLauncher's skip message is quite broken
+    elsif ($Line =~ /^([_a-z0-9]+)(?:\.c)?:\d+:? Tests? skipped: / or
+           ($Cur->{Unit} ne "" and
+            $Line =~ /($Cur->{Unit})(?:\.c)?:\d+:? Tests? skipped: /))
+    {
+      my $Unit = $1;
+      # Don't complain and don't count misplaced skips. Only complain if they
+      # are misreported (see _CloseTestUnit). Also TestLauncher uses the wrong
+      # name in its skip message when skipping tests.
+      if ($Unit eq $Cur->{Unit} or $Cur->{Unit} eq "" or $Unit eq $Cur->{Dll})
+      {
+        $Cur->{LineSkips}++;
+      }
+    }
+    elsif ($Line =~ /^Fatal: test '([_a-z0-9]+)' does not exist/)
+    {
+      # This also replaces a test summary line.
+      $Cur->{Pids}->{0} = 1;
+      $Cur->{SummaryFailures}++;
+      $Parser->{IsWineTest} = 1;
+
+      $Cur->{LineFailures}++;
+    }
+    elsif ($Line =~ /^(?:([0-9a-f]+):)?([_.a-z0-9]+): unhandled exception [0-9a-fA-F]{8} at / or
+           ($Cur->{Unit} ne "" and
+            $Line =~ /(?:([0-9a-f]+):)?($Cur->{Unit}): unhandled exception [0-9a-fA-F]{8} at /))
+    {
+      my ($Pid, $Unit) = ($1, $2);
+
+      if ($Unit eq $Cur->{Unit})
+      {
+        # This also replaces a test summary line.
+        $Cur->{Pids}->{$Pid || 0} = 1;
+        $Cur->{SummaryFailures}++;
+      }
+      _CheckUnit($Parser, $Cur, $Unit, "unhandled exception");
+      $Cur->{LineFailures}++;
+    }
+    elsif ($Line =~ /^(?:([0-9a-f]+):)?([_a-z0-9]+): \d+ tests? executed \((\d+) marked as todo, (\d+) failures?\), (\d+) skipped\./ or
+           ($Cur->{Unit} ne "" and
+            $Line =~ /(?:([0-9a-f]+):)?($Cur->{Unit}): \d+ tests? executed \((\d+) marked as todo, (\d+) failures?\), (\d+) skipped\./))
+    {
+      my ($Pid, $Unit, $Todos, $Failures, $Skips) = ($1, $2, $3, $4, $5);
+
+      # Dlls that have only one test unit will run it even if there is
+      # no argument. Also TestLauncher uses the wrong name in its test
+      # summary line when skipping tests.
+      if ($Unit eq $Cur->{Unit} or $Cur->{Unit} eq "" or $Unit eq $Cur->{Dll})
+      {
+        # There may be more than one summary line due to child processes
+        $Cur->{Pids}->{$Pid || 0} = 1;
+        $Cur->{SummaryFailures} += $Failures;
+        $Cur->{SummaryTodos} += $Todos;
+        $Cur->{SummarySkips} += $Skips;
+        $Parser->{IsWineTest} = 1;
+      }
+      else
+      {
+        _CheckUnit($Parser, $Cur, $Unit, "test summary") if ($Todos or $Failures);
+      }
+    }
+    elsif ($Line =~ /^([_.a-z0-9-]+):([_a-z0-9]*)(?::([0-9a-f]+))? done \((-?\d+)\)(?:\r?$| in)/ or
+           ($Cur->{Dll} ne "" and
+            $Line =~ /(\Q$Cur->{Dll}\E):([_a-z0-9]*)(?::([0-9a-f]+))? done \((-?\d+)\)(?:\r?$| in)/))
+    {
+      my ($Dll, $Unit, $Pid, $Rc) = ($1, $2, $3, $4);
+
+      if ($Parser->{IsWineTest} and ($Dll ne $Cur->{Dll} or $Unit ne $Cur->{Unit}))
+      {
+        # First close the current test unit taking into account
+        # it may have been polluted by the new one.
+        $Cur->{IsBroken} = 1;
+        _CloseTestUnit($Parser, $Cur, 0);
+
+        # Then switch to the new one, warning it's missing a start line,
+        # and that its results may be inconsistent.
+        ($Cur->{Dll}, $Cur->{Unit}) = ($Dll, $Unit);
+        _AddError($Parser, "had no start line (or it is garbled)", $Cur);
+        $Cur->{IsBroken} = 1;
+      }
+
+      if ($Rc == 258)
+      {
+        # The done line will already be shown as a timeout (see JobDetails)
+        # so record the failure but don't add an error message.
+        $Parser->{Failures}++;
+        $Cur->{IsBroken} = 1;
+        $Parser->{TimedOut} = $Parser->{IsSuite};
+      }
+      elsif ((!$Pid and !%{$Cur->{Pids}}) or
+             ($Pid and !$Cur->{Pids}->{$Pid} and !$Cur->{Pids}->{0}))
+      {
+        # The main summary line is missing
+        if ($Rc & 0xc0000000)
+        {
+          _AddError($Parser, sprintf("%s:%s crashed (%08x)", $Dll, $Unit, $Rc & 0xffffffff));
+          $Cur->{IsBroken} = 1;
+        }
+        elsif ($Parser->{IsWineTest} and !$Cur->{IsBroken})
+        {
+           _AddError($Parser, "$Dll:$Unit has no test summary line (early exit of the main process?)");
+        }
+      }
+      elsif ($Rc & 0xc0000000)
+      {
+        # We know the crash happened in the main process which means we got
+        # an "unhandled exception" message. So there is no need to add an
+        # extra message or to increment the failure count. Still note that
+        # there may be inconsistencies (e.g. unreported todos or skips).
+        $Cur->{IsBroken} = 1;
+      }
+      $Cur->{Rc} = $Rc;
+    }
+  }
+  $Cur->{IsBroken} = 1 if ($Parser->{TaskTimedOut});
+  _CloseTestUnit($Parser, $Cur, 1);
+  close($LogFile);
+
+  return ($Parser->{Failures}, $Parser->{Errors}, $Parser->{TimedOut});
+}
+
+
 #
 # Log querying and formatting
 #
-- 
2.18.0




More information about the wine-devel mailing list