1*cda5da8dSAndroid Build Coastguard Worker"""Test result object""" 2*cda5da8dSAndroid Build Coastguard Worker 3*cda5da8dSAndroid Build Coastguard Workerimport io 4*cda5da8dSAndroid Build Coastguard Workerimport sys 5*cda5da8dSAndroid Build Coastguard Workerimport traceback 6*cda5da8dSAndroid Build Coastguard Worker 7*cda5da8dSAndroid Build Coastguard Workerfrom . import util 8*cda5da8dSAndroid Build Coastguard Workerfrom functools import wraps 9*cda5da8dSAndroid Build Coastguard Worker 10*cda5da8dSAndroid Build Coastguard Worker__unittest = True 11*cda5da8dSAndroid Build Coastguard Worker 12*cda5da8dSAndroid Build Coastguard Workerdef failfast(method): 13*cda5da8dSAndroid Build Coastguard Worker @wraps(method) 14*cda5da8dSAndroid Build Coastguard Worker def inner(self, *args, **kw): 15*cda5da8dSAndroid Build Coastguard Worker if getattr(self, 'failfast', False): 16*cda5da8dSAndroid Build Coastguard Worker self.stop() 17*cda5da8dSAndroid Build Coastguard Worker return method(self, *args, **kw) 18*cda5da8dSAndroid Build Coastguard Worker return inner 19*cda5da8dSAndroid Build Coastguard Worker 20*cda5da8dSAndroid Build Coastguard WorkerSTDOUT_LINE = '\nStdout:\n%s' 21*cda5da8dSAndroid Build Coastguard WorkerSTDERR_LINE = '\nStderr:\n%s' 22*cda5da8dSAndroid Build Coastguard Worker 23*cda5da8dSAndroid Build Coastguard Worker 24*cda5da8dSAndroid Build Coastguard Workerclass TestResult(object): 25*cda5da8dSAndroid Build Coastguard Worker """Holder for test result information. 26*cda5da8dSAndroid Build Coastguard Worker 27*cda5da8dSAndroid Build Coastguard Worker Test results are automatically managed by the TestCase and TestSuite 28*cda5da8dSAndroid Build Coastguard Worker classes, and do not need to be explicitly manipulated by writers of tests. 29*cda5da8dSAndroid Build Coastguard Worker 30*cda5da8dSAndroid Build Coastguard Worker Each instance holds the total number of tests run, and collections of 31*cda5da8dSAndroid Build Coastguard Worker failures and errors that occurred among those test runs. The collections 32*cda5da8dSAndroid Build Coastguard Worker contain tuples of (testcase, exceptioninfo), where exceptioninfo is the 33*cda5da8dSAndroid Build Coastguard Worker formatted traceback of the error that occurred. 34*cda5da8dSAndroid Build Coastguard Worker """ 35*cda5da8dSAndroid Build Coastguard Worker _previousTestClass = None 36*cda5da8dSAndroid Build Coastguard Worker _testRunEntered = False 37*cda5da8dSAndroid Build Coastguard Worker _moduleSetUpFailed = False 38*cda5da8dSAndroid Build Coastguard Worker def __init__(self, stream=None, descriptions=None, verbosity=None): 39*cda5da8dSAndroid Build Coastguard Worker self.failfast = False 40*cda5da8dSAndroid Build Coastguard Worker self.failures = [] 41*cda5da8dSAndroid Build Coastguard Worker self.errors = [] 42*cda5da8dSAndroid Build Coastguard Worker self.testsRun = 0 43*cda5da8dSAndroid Build Coastguard Worker self.skipped = [] 44*cda5da8dSAndroid Build Coastguard Worker self.expectedFailures = [] 45*cda5da8dSAndroid Build Coastguard Worker self.unexpectedSuccesses = [] 46*cda5da8dSAndroid Build Coastguard Worker self.shouldStop = False 47*cda5da8dSAndroid Build Coastguard Worker self.buffer = False 48*cda5da8dSAndroid Build Coastguard Worker self.tb_locals = False 49*cda5da8dSAndroid Build Coastguard Worker self._stdout_buffer = None 50*cda5da8dSAndroid Build Coastguard Worker self._stderr_buffer = None 51*cda5da8dSAndroid Build Coastguard Worker self._original_stdout = sys.stdout 52*cda5da8dSAndroid Build Coastguard Worker self._original_stderr = sys.stderr 53*cda5da8dSAndroid Build Coastguard Worker self._mirrorOutput = False 54*cda5da8dSAndroid Build Coastguard Worker 55*cda5da8dSAndroid Build Coastguard Worker def printErrors(self): 56*cda5da8dSAndroid Build Coastguard Worker "Called by TestRunner after test run" 57*cda5da8dSAndroid Build Coastguard Worker 58*cda5da8dSAndroid Build Coastguard Worker def startTest(self, test): 59*cda5da8dSAndroid Build Coastguard Worker "Called when the given test is about to be run" 60*cda5da8dSAndroid Build Coastguard Worker self.testsRun += 1 61*cda5da8dSAndroid Build Coastguard Worker self._mirrorOutput = False 62*cda5da8dSAndroid Build Coastguard Worker self._setupStdout() 63*cda5da8dSAndroid Build Coastguard Worker 64*cda5da8dSAndroid Build Coastguard Worker def _setupStdout(self): 65*cda5da8dSAndroid Build Coastguard Worker if self.buffer: 66*cda5da8dSAndroid Build Coastguard Worker if self._stderr_buffer is None: 67*cda5da8dSAndroid Build Coastguard Worker self._stderr_buffer = io.StringIO() 68*cda5da8dSAndroid Build Coastguard Worker self._stdout_buffer = io.StringIO() 69*cda5da8dSAndroid Build Coastguard Worker sys.stdout = self._stdout_buffer 70*cda5da8dSAndroid Build Coastguard Worker sys.stderr = self._stderr_buffer 71*cda5da8dSAndroid Build Coastguard Worker 72*cda5da8dSAndroid Build Coastguard Worker def startTestRun(self): 73*cda5da8dSAndroid Build Coastguard Worker """Called once before any tests are executed. 74*cda5da8dSAndroid Build Coastguard Worker 75*cda5da8dSAndroid Build Coastguard Worker See startTest for a method called before each test. 76*cda5da8dSAndroid Build Coastguard Worker """ 77*cda5da8dSAndroid Build Coastguard Worker 78*cda5da8dSAndroid Build Coastguard Worker def stopTest(self, test): 79*cda5da8dSAndroid Build Coastguard Worker """Called when the given test has been run""" 80*cda5da8dSAndroid Build Coastguard Worker self._restoreStdout() 81*cda5da8dSAndroid Build Coastguard Worker self._mirrorOutput = False 82*cda5da8dSAndroid Build Coastguard Worker 83*cda5da8dSAndroid Build Coastguard Worker def _restoreStdout(self): 84*cda5da8dSAndroid Build Coastguard Worker if self.buffer: 85*cda5da8dSAndroid Build Coastguard Worker if self._mirrorOutput: 86*cda5da8dSAndroid Build Coastguard Worker output = sys.stdout.getvalue() 87*cda5da8dSAndroid Build Coastguard Worker error = sys.stderr.getvalue() 88*cda5da8dSAndroid Build Coastguard Worker if output: 89*cda5da8dSAndroid Build Coastguard Worker if not output.endswith('\n'): 90*cda5da8dSAndroid Build Coastguard Worker output += '\n' 91*cda5da8dSAndroid Build Coastguard Worker self._original_stdout.write(STDOUT_LINE % output) 92*cda5da8dSAndroid Build Coastguard Worker if error: 93*cda5da8dSAndroid Build Coastguard Worker if not error.endswith('\n'): 94*cda5da8dSAndroid Build Coastguard Worker error += '\n' 95*cda5da8dSAndroid Build Coastguard Worker self._original_stderr.write(STDERR_LINE % error) 96*cda5da8dSAndroid Build Coastguard Worker 97*cda5da8dSAndroid Build Coastguard Worker sys.stdout = self._original_stdout 98*cda5da8dSAndroid Build Coastguard Worker sys.stderr = self._original_stderr 99*cda5da8dSAndroid Build Coastguard Worker self._stdout_buffer.seek(0) 100*cda5da8dSAndroid Build Coastguard Worker self._stdout_buffer.truncate() 101*cda5da8dSAndroid Build Coastguard Worker self._stderr_buffer.seek(0) 102*cda5da8dSAndroid Build Coastguard Worker self._stderr_buffer.truncate() 103*cda5da8dSAndroid Build Coastguard Worker 104*cda5da8dSAndroid Build Coastguard Worker def stopTestRun(self): 105*cda5da8dSAndroid Build Coastguard Worker """Called once after all tests are executed. 106*cda5da8dSAndroid Build Coastguard Worker 107*cda5da8dSAndroid Build Coastguard Worker See stopTest for a method called after each test. 108*cda5da8dSAndroid Build Coastguard Worker """ 109*cda5da8dSAndroid Build Coastguard Worker 110*cda5da8dSAndroid Build Coastguard Worker @failfast 111*cda5da8dSAndroid Build Coastguard Worker def addError(self, test, err): 112*cda5da8dSAndroid Build Coastguard Worker """Called when an error has occurred. 'err' is a tuple of values as 113*cda5da8dSAndroid Build Coastguard Worker returned by sys.exc_info(). 114*cda5da8dSAndroid Build Coastguard Worker """ 115*cda5da8dSAndroid Build Coastguard Worker self.errors.append((test, self._exc_info_to_string(err, test))) 116*cda5da8dSAndroid Build Coastguard Worker self._mirrorOutput = True 117*cda5da8dSAndroid Build Coastguard Worker 118*cda5da8dSAndroid Build Coastguard Worker @failfast 119*cda5da8dSAndroid Build Coastguard Worker def addFailure(self, test, err): 120*cda5da8dSAndroid Build Coastguard Worker """Called when an error has occurred. 'err' is a tuple of values as 121*cda5da8dSAndroid Build Coastguard Worker returned by sys.exc_info().""" 122*cda5da8dSAndroid Build Coastguard Worker self.failures.append((test, self._exc_info_to_string(err, test))) 123*cda5da8dSAndroid Build Coastguard Worker self._mirrorOutput = True 124*cda5da8dSAndroid Build Coastguard Worker 125*cda5da8dSAndroid Build Coastguard Worker def addSubTest(self, test, subtest, err): 126*cda5da8dSAndroid Build Coastguard Worker """Called at the end of a subtest. 127*cda5da8dSAndroid Build Coastguard Worker 'err' is None if the subtest ended successfully, otherwise it's a 128*cda5da8dSAndroid Build Coastguard Worker tuple of values as returned by sys.exc_info(). 129*cda5da8dSAndroid Build Coastguard Worker """ 130*cda5da8dSAndroid Build Coastguard Worker # By default, we don't do anything with successful subtests, but 131*cda5da8dSAndroid Build Coastguard Worker # more sophisticated test results might want to record them. 132*cda5da8dSAndroid Build Coastguard Worker if err is not None: 133*cda5da8dSAndroid Build Coastguard Worker if getattr(self, 'failfast', False): 134*cda5da8dSAndroid Build Coastguard Worker self.stop() 135*cda5da8dSAndroid Build Coastguard Worker if issubclass(err[0], test.failureException): 136*cda5da8dSAndroid Build Coastguard Worker errors = self.failures 137*cda5da8dSAndroid Build Coastguard Worker else: 138*cda5da8dSAndroid Build Coastguard Worker errors = self.errors 139*cda5da8dSAndroid Build Coastguard Worker errors.append((subtest, self._exc_info_to_string(err, test))) 140*cda5da8dSAndroid Build Coastguard Worker self._mirrorOutput = True 141*cda5da8dSAndroid Build Coastguard Worker 142*cda5da8dSAndroid Build Coastguard Worker def addSuccess(self, test): 143*cda5da8dSAndroid Build Coastguard Worker "Called when a test has completed successfully" 144*cda5da8dSAndroid Build Coastguard Worker pass 145*cda5da8dSAndroid Build Coastguard Worker 146*cda5da8dSAndroid Build Coastguard Worker def addSkip(self, test, reason): 147*cda5da8dSAndroid Build Coastguard Worker """Called when a test is skipped.""" 148*cda5da8dSAndroid Build Coastguard Worker self.skipped.append((test, reason)) 149*cda5da8dSAndroid Build Coastguard Worker 150*cda5da8dSAndroid Build Coastguard Worker def addExpectedFailure(self, test, err): 151*cda5da8dSAndroid Build Coastguard Worker """Called when an expected failure/error occurred.""" 152*cda5da8dSAndroid Build Coastguard Worker self.expectedFailures.append( 153*cda5da8dSAndroid Build Coastguard Worker (test, self._exc_info_to_string(err, test))) 154*cda5da8dSAndroid Build Coastguard Worker 155*cda5da8dSAndroid Build Coastguard Worker @failfast 156*cda5da8dSAndroid Build Coastguard Worker def addUnexpectedSuccess(self, test): 157*cda5da8dSAndroid Build Coastguard Worker """Called when a test was expected to fail, but succeed.""" 158*cda5da8dSAndroid Build Coastguard Worker self.unexpectedSuccesses.append(test) 159*cda5da8dSAndroid Build Coastguard Worker 160*cda5da8dSAndroid Build Coastguard Worker def wasSuccessful(self): 161*cda5da8dSAndroid Build Coastguard Worker """Tells whether or not this result was a success.""" 162*cda5da8dSAndroid Build Coastguard Worker # The hasattr check is for test_result's OldResult test. That 163*cda5da8dSAndroid Build Coastguard Worker # way this method works on objects that lack the attribute. 164*cda5da8dSAndroid Build Coastguard Worker # (where would such result instances come from? old stored pickles?) 165*cda5da8dSAndroid Build Coastguard Worker return ((len(self.failures) == len(self.errors) == 0) and 166*cda5da8dSAndroid Build Coastguard Worker (not hasattr(self, 'unexpectedSuccesses') or 167*cda5da8dSAndroid Build Coastguard Worker len(self.unexpectedSuccesses) == 0)) 168*cda5da8dSAndroid Build Coastguard Worker 169*cda5da8dSAndroid Build Coastguard Worker def stop(self): 170*cda5da8dSAndroid Build Coastguard Worker """Indicates that the tests should be aborted.""" 171*cda5da8dSAndroid Build Coastguard Worker self.shouldStop = True 172*cda5da8dSAndroid Build Coastguard Worker 173*cda5da8dSAndroid Build Coastguard Worker def _exc_info_to_string(self, err, test): 174*cda5da8dSAndroid Build Coastguard Worker """Converts a sys.exc_info()-style tuple of values into a string.""" 175*cda5da8dSAndroid Build Coastguard Worker exctype, value, tb = err 176*cda5da8dSAndroid Build Coastguard Worker tb = self._clean_tracebacks(exctype, value, tb, test) 177*cda5da8dSAndroid Build Coastguard Worker tb_e = traceback.TracebackException( 178*cda5da8dSAndroid Build Coastguard Worker exctype, value, tb, 179*cda5da8dSAndroid Build Coastguard Worker capture_locals=self.tb_locals, compact=True) 180*cda5da8dSAndroid Build Coastguard Worker msgLines = list(tb_e.format()) 181*cda5da8dSAndroid Build Coastguard Worker 182*cda5da8dSAndroid Build Coastguard Worker if self.buffer: 183*cda5da8dSAndroid Build Coastguard Worker output = sys.stdout.getvalue() 184*cda5da8dSAndroid Build Coastguard Worker error = sys.stderr.getvalue() 185*cda5da8dSAndroid Build Coastguard Worker if output: 186*cda5da8dSAndroid Build Coastguard Worker if not output.endswith('\n'): 187*cda5da8dSAndroid Build Coastguard Worker output += '\n' 188*cda5da8dSAndroid Build Coastguard Worker msgLines.append(STDOUT_LINE % output) 189*cda5da8dSAndroid Build Coastguard Worker if error: 190*cda5da8dSAndroid Build Coastguard Worker if not error.endswith('\n'): 191*cda5da8dSAndroid Build Coastguard Worker error += '\n' 192*cda5da8dSAndroid Build Coastguard Worker msgLines.append(STDERR_LINE % error) 193*cda5da8dSAndroid Build Coastguard Worker return ''.join(msgLines) 194*cda5da8dSAndroid Build Coastguard Worker 195*cda5da8dSAndroid Build Coastguard Worker def _clean_tracebacks(self, exctype, value, tb, test): 196*cda5da8dSAndroid Build Coastguard Worker ret = None 197*cda5da8dSAndroid Build Coastguard Worker first = True 198*cda5da8dSAndroid Build Coastguard Worker excs = [(exctype, value, tb)] 199*cda5da8dSAndroid Build Coastguard Worker seen = {id(value)} # Detect loops in chained exceptions. 200*cda5da8dSAndroid Build Coastguard Worker while excs: 201*cda5da8dSAndroid Build Coastguard Worker (exctype, value, tb) = excs.pop() 202*cda5da8dSAndroid Build Coastguard Worker # Skip test runner traceback levels 203*cda5da8dSAndroid Build Coastguard Worker while tb and self._is_relevant_tb_level(tb): 204*cda5da8dSAndroid Build Coastguard Worker tb = tb.tb_next 205*cda5da8dSAndroid Build Coastguard Worker 206*cda5da8dSAndroid Build Coastguard Worker # Skip assert*() traceback levels 207*cda5da8dSAndroid Build Coastguard Worker if exctype is test.failureException: 208*cda5da8dSAndroid Build Coastguard Worker self._remove_unittest_tb_frames(tb) 209*cda5da8dSAndroid Build Coastguard Worker 210*cda5da8dSAndroid Build Coastguard Worker if first: 211*cda5da8dSAndroid Build Coastguard Worker ret = tb 212*cda5da8dSAndroid Build Coastguard Worker first = False 213*cda5da8dSAndroid Build Coastguard Worker else: 214*cda5da8dSAndroid Build Coastguard Worker value.__traceback__ = tb 215*cda5da8dSAndroid Build Coastguard Worker 216*cda5da8dSAndroid Build Coastguard Worker if value is not None: 217*cda5da8dSAndroid Build Coastguard Worker for c in (value.__cause__, value.__context__): 218*cda5da8dSAndroid Build Coastguard Worker if c is not None and id(c) not in seen: 219*cda5da8dSAndroid Build Coastguard Worker excs.append((type(c), c, c.__traceback__)) 220*cda5da8dSAndroid Build Coastguard Worker seen.add(id(c)) 221*cda5da8dSAndroid Build Coastguard Worker return ret 222*cda5da8dSAndroid Build Coastguard Worker 223*cda5da8dSAndroid Build Coastguard Worker def _is_relevant_tb_level(self, tb): 224*cda5da8dSAndroid Build Coastguard Worker return '__unittest' in tb.tb_frame.f_globals 225*cda5da8dSAndroid Build Coastguard Worker 226*cda5da8dSAndroid Build Coastguard Worker def _remove_unittest_tb_frames(self, tb): 227*cda5da8dSAndroid Build Coastguard Worker '''Truncates usercode tb at the first unittest frame. 228*cda5da8dSAndroid Build Coastguard Worker 229*cda5da8dSAndroid Build Coastguard Worker If the first frame of the traceback is in user code, 230*cda5da8dSAndroid Build Coastguard Worker the prefix up to the first unittest frame is returned. 231*cda5da8dSAndroid Build Coastguard Worker If the first frame is already in the unittest module, 232*cda5da8dSAndroid Build Coastguard Worker the traceback is not modified. 233*cda5da8dSAndroid Build Coastguard Worker ''' 234*cda5da8dSAndroid Build Coastguard Worker prev = None 235*cda5da8dSAndroid Build Coastguard Worker while tb and not self._is_relevant_tb_level(tb): 236*cda5da8dSAndroid Build Coastguard Worker prev = tb 237*cda5da8dSAndroid Build Coastguard Worker tb = tb.tb_next 238*cda5da8dSAndroid Build Coastguard Worker if prev is not None: 239*cda5da8dSAndroid Build Coastguard Worker prev.tb_next = None 240*cda5da8dSAndroid Build Coastguard Worker 241*cda5da8dSAndroid Build Coastguard Worker def __repr__(self): 242*cda5da8dSAndroid Build Coastguard Worker return ("<%s run=%i errors=%i failures=%i>" % 243*cda5da8dSAndroid Build Coastguard Worker (util.strclass(self.__class__), self.testsRun, len(self.errors), 244*cda5da8dSAndroid Build Coastguard Worker len(self.failures))) 245