1# Copyright (c) 2013 The Chromium Authors. All rights reserved.
2# Use of this source code is governed by a BSD-style license that can be
3# found in the LICENSE file.
4
5"""Module containing base test results classes."""
6
7class ResultType(object):
8  """Class enumerating test types."""
9  PASS = 'PASS'
10  FAIL = 'FAIL'
11  CRASH = 'CRASH'
12  TIMEOUT = 'TIMEOUT'
13  UNKNOWN = 'UNKNOWN'
14
15  @staticmethod
16  def GetTypes():
17    """Get a list of all test types."""
18    return [ResultType.PASS, ResultType.FAIL, ResultType.CRASH,
19            ResultType.TIMEOUT, ResultType.UNKNOWN]
20
21
22class BaseTestResult(object):
23  """Base class for a single test result."""
24
25  def __init__(self, name, test_type, log=''):
26    """Construct a BaseTestResult.
27
28    Args:
29      name: Name of the test which defines uniqueness.
30      test_type: Type of the test result as defined in ResultType.
31      log: An optional string listing any errors.
32    """
33    assert name
34    assert test_type in ResultType.GetTypes()
35    self._name = name
36    self._test_type = test_type
37    self._log = log
38
39  def __str__(self):
40    return self._name
41
42  def __repr__(self):
43    return self._name
44
45  def __cmp__(self, other):
46    # pylint: disable=W0212
47    return cmp(self._name, other._name)
48
49  def __hash__(self):
50    return hash(self._name)
51
52  def SetName(self, name):
53    """Set the test name.
54
55    Because we're putting this into a set, this should only be used if moving
56    this test result into another set.
57    """
58    self._name = name
59
60  def GetName(self):
61    """Get the test name."""
62    return self._name
63
64  def GetType(self):
65    """Get the test result type."""
66    return self._test_type
67
68  def GetLog(self):
69    """Get the test log."""
70    return self._log
71
72
73class TestRunResults(object):
74  """Set of results for a test run."""
75
76  def __init__(self):
77    self._results = set()
78
79  def GetLogs(self):
80    """Get the string representation of all test logs."""
81    s = []
82    for test_type in ResultType.GetTypes():
83      if test_type != ResultType.PASS:
84        for t in sorted(self._GetType(test_type)):
85          log = t.GetLog()
86          if log:
87            s.append('[%s] %s:' % (test_type, t))
88            s.append(log)
89    return '\n'.join(s)
90
91  def GetGtestForm(self):
92    """Get the gtest string representation of this object."""
93    s = []
94    plural = lambda n, s, p: '%d %s' % (n, p if n != 1 else s)
95    tests = lambda n: plural(n, 'test', 'tests')
96
97    s.append('[==========] %s ran.' % (tests(len(self.GetAll()))))
98    s.append('[  PASSED  ] %s.' % (tests(len(self.GetPass()))))
99
100    not_passed = self.GetNotPass()
101    if len(not_passed) > 0:
102      s.append('[  FAILED  ] %s, listed below:' % tests(len(self.GetNotPass())))
103      for t in self.GetFail():
104        s.append('[  FAILED  ] %s' % str(t))
105      for t in self.GetCrash():
106        s.append('[  FAILED  ] %s (CRASHED)' % str(t))
107      for t in self.GetTimeout():
108        s.append('[  FAILED  ] %s (TIMEOUT)' % str(t))
109      for t in self.GetUnknown():
110        s.append('[  FAILED  ] %s (UNKNOWN)' % str(t))
111      s.append('')
112      s.append(plural(len(not_passed), 'FAILED TEST', 'FAILED TESTS'))
113    return '\n'.join(s)
114
115  def GetShortForm(self):
116    """Get the short string representation of this object."""
117    s = []
118    s.append('ALL: %d' % len(self._results))
119    for test_type in ResultType.GetTypes():
120      s.append('%s: %d' % (test_type, len(self._GetType(test_type))))
121    return ''.join([x.ljust(15) for x in s])
122
123  def __str__(self):
124    return self.GetLongForm()
125
126  def AddResult(self, result):
127    """Add |result| to the set.
128
129    Args:
130      result: An instance of BaseTestResult.
131    """
132    assert isinstance(result, BaseTestResult)
133    self._results.add(result)
134
135  def AddResults(self, results):
136    """Add |results| to the set.
137
138    Args:
139      results: An iterable of BaseTestResult objects.
140    """
141    for t in results:
142      self.AddResult(t)
143
144  def AddTestRunResults(self, results):
145    """Add the set of test results from |results|.
146
147    Args:
148      results: An instance of TestRunResults.
149    """
150    assert isinstance(results, TestRunResults)
151    # pylint: disable=W0212
152    self._results.update(results._results)
153
154  def GetAll(self):
155    """Get the set of all test results."""
156    return self._results.copy()
157
158  def _GetType(self, test_type):
159    """Get the set of test results with the given test type."""
160    return set(t for t in self._results if t.GetType() == test_type)
161
162  def GetPass(self):
163    """Get the set of all passed test results."""
164    return self._GetType(ResultType.PASS)
165
166  def GetFail(self):
167    """Get the set of all failed test results."""
168    return self._GetType(ResultType.FAIL)
169
170  def GetCrash(self):
171    """Get the set of all crashed test results."""
172    return self._GetType(ResultType.CRASH)
173
174  def GetTimeout(self):
175    """Get the set of all timed out test results."""
176    return self._GetType(ResultType.TIMEOUT)
177
178  def GetUnknown(self):
179    """Get the set of all unknown test results."""
180    return self._GetType(ResultType.UNKNOWN)
181
182  def GetNotPass(self):
183    """Get the set of all non-passed test results."""
184    return self.GetAll() - self.GetPass()
185
186  def DidRunPass(self):
187    """Return whether the test run was successful."""
188    return not self.GetNotPass()
189