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