# Copyright (c) 2009-2016 testtools developers. See LICENSE for details. """Doubles of test result objects, useful for testing unittest code.""" from collections import namedtuple from testtools.tags import TagContext __all__ = [ 'Python26TestResult', 'Python27TestResult', 'ExtendedTestResult', 'TwistedTestResult', 'StreamResult', ] class LoggingBase: """Basic support for logging of results.""" def __init__(self, event_log=None): if event_log is None: event_log = [] self._events = event_log class Python26TestResult(LoggingBase): """A precisely python 2.6 like test result, that logs.""" def __init__(self, event_log=None): super().__init__(event_log=event_log) self.shouldStop = False self._was_successful = True self.testsRun = 0 def addError(self, test, err): self._was_successful = False self._events.append(('addError', test, err)) def addFailure(self, test, err): self._was_successful = False self._events.append(('addFailure', test, err)) def addSuccess(self, test): self._events.append(('addSuccess', test)) def startTest(self, test): self._events.append(('startTest', test)) self.testsRun += 1 def stop(self): self.shouldStop = True def stopTest(self, test): self._events.append(('stopTest', test)) def wasSuccessful(self): return self._was_successful class Python27TestResult(Python26TestResult): """A precisely python 2.7 like test result, that logs.""" def __init__(self, event_log=None): super().__init__(event_log) self.failfast = False def addError(self, test, err): super().addError(test, err) if self.failfast: self.stop() def addFailure(self, test, err): super().addFailure(test, err) if self.failfast: self.stop() def addExpectedFailure(self, test, err): self._events.append(('addExpectedFailure', test, err)) def addSkip(self, test, reason): self._events.append(('addSkip', test, reason)) def addUnexpectedSuccess(self, test): self._events.append(('addUnexpectedSuccess', test)) if self.failfast: self.stop() def startTestRun(self): self._events.append(('startTestRun',)) def stopTestRun(self): self._events.append(('stopTestRun',)) class ExtendedTestResult(Python27TestResult): """A test result like the proposed extended unittest result API.""" def __init__(self, event_log=None): super().__init__(event_log) self._tags = TagContext() def addError(self, test, err=None, details=None): self._was_successful = False self._events.append(('addError', test, err or details)) def addFailure(self, test, err=None, details=None): self._was_successful = False self._events.append(('addFailure', test, err or details)) def addExpectedFailure(self, test, err=None, details=None): self._events.append(('addExpectedFailure', test, err or details)) def addSkip(self, test, reason=None, details=None): self._events.append(('addSkip', test, reason or details)) def addSuccess(self, test, details=None): if details: self._events.append(('addSuccess', test, details)) else: self._events.append(('addSuccess', test)) def addUnexpectedSuccess(self, test, details=None): self._was_successful = False if details is not None: self._events.append(('addUnexpectedSuccess', test, details)) else: self._events.append(('addUnexpectedSuccess', test)) def progress(self, offset, whence): self._events.append(('progress', offset, whence)) def startTestRun(self): super().startTestRun() self._was_successful = True self._tags = TagContext() def startTest(self, test): super().startTest(test) self._tags = TagContext(self._tags) def stopTest(self, test): self._tags = self._tags.parent super().stopTest(test) @property def current_tags(self): return self._tags.get_current_tags() def tags(self, new_tags, gone_tags): self._tags.change_tags(new_tags, gone_tags) self._events.append(('tags', new_tags, gone_tags)) def time(self, time): self._events.append(('time', time)) def wasSuccessful(self): return self._was_successful class TwistedTestResult(LoggingBase): """ Emulate the relevant bits of :py:class:`twisted.trial.itrial.IReporter`. Used to ensure that we can use ``trial`` as a test runner. """ def __init__(self, event_log=None): super().__init__(event_log=event_log) self._was_successful = True self.testsRun = 0 def startTest(self, test): self.testsRun += 1 self._events.append(('startTest', test)) def stopTest(self, test): self._events.append(('stopTest', test)) def addSuccess(self, test): self._events.append(('addSuccess', test)) def addError(self, test, error): self._was_successful = False self._events.append(('addError', test, error)) def addFailure(self, test, error): self._was_successful = False self._events.append(('addFailure', test, error)) def addExpectedFailure(self, test, failure, todo=None): self._events.append(('addExpectedFailure', test, failure)) def addUnexpectedSuccess(self, test, todo=None): self._events.append(('addUnexpectedSuccess', test)) def addSkip(self, test, reason): self._events.append(('addSkip', test, reason)) def wasSuccessful(self): return self._was_successful def done(self): pass class StreamResult(LoggingBase): """A StreamResult implementation for testing. All events are logged to _events. """ def startTestRun(self): self._events.append(('startTestRun',)) def stopTestRun(self): self._events.append(('stopTestRun',)) def status(self, test_id=None, test_status=None, test_tags=None, runnable=True, file_name=None, file_bytes=None, eof=False, mime_type=None, route_code=None, timestamp=None): self._events.append( _StatusEvent( 'status', test_id, test_status, test_tags, runnable, file_name, file_bytes, eof, mime_type, route_code, timestamp)) # Convenience for easier access to status fields _StatusEvent = namedtuple( "_Event", [ "name", "test_id", "test_status", "test_tags", "runnable", "file_name", "file_bytes", "eof", "mime_type", "route_code", "timestamp"])