diff options
| author | Robert Collins <robertc@robertcollins.net> | 2009-08-30 18:34:46 +1000 |
|---|---|---|
| committer | Robert Collins <robertc@robertcollins.net> | 2009-08-30 18:34:46 +1000 |
| commit | 613ab39dede4d24df8bc6fcdfbbb233421898904 (patch) | |
| tree | 2f6467c29e3ba5b37d28cae801d4bee2228b9f7b /python | |
| parent | 6d4b439267d1449356537128abffa0d5a228402f (diff) | |
| download | subunit-git-613ab39dede4d24df8bc6fcdfbbb233421898904.tar.gz | |
Split TestResultDecorator into hooked and non-hooked one. Also improve fallback logic for down-grade results.
Diffstat (limited to 'python')
| -rw-r--r-- | python/subunit/test_results.py | 119 |
1 files changed, 95 insertions, 24 deletions
diff --git a/python/subunit/test_results.py b/python/subunit/test_results.py index a5811aa..a3be6d9 100644 --- a/python/subunit/test_results.py +++ b/python/subunit/test_results.py @@ -23,13 +23,23 @@ import datetime import iso8601 -class HookedTestResultDecorator(object): - """A TestResult which calls a hook on every event.""" + +# NOT a TestResult, because we are implementing the interface, not inheriting +# it. +class TestResultDecorator(object): + """General pass-through decorator. + + This provides a base that other TestResults can inherit from to + gain basic forwarding functionality. It also takes care of + handling the case where the target doesn't support newer methods + or features by degrading them. + """ def __init__(self, decorated): + """Create a TestResultDecorator forwarding to decorated.""" self.decorated = decorated - def _call_maybe(self, method_name, *params): + def _call_maybe(self, method_name, fallback, *params): """Call method_name on self.decorated, if present. This is used to guard newer methods which older pythons do not @@ -38,75 +48,139 @@ class HookedTestResultDecorator(object): the one to filter them out. :param method_name: The name of the method to call. + :param fallback: If not None, the fallback to cal to handle downgrading + this method. Otherwise when method_name is not available, no + exception is raised and None is returned. :param *params: Parameters to pass to method_name. :return: The result of self.decorated.method_name(*params), if it exists, and None otherwise. """ method = getattr(self.decorated, method_name, None) if method is None: + if fallback is not None: + return fallback(*params) return return method(*params) def startTest(self, test): - self._before_event() return self.decorated.startTest(test) def startTestRun(self): + return self._call_maybe("startTestRun", None) + + def stopTest(self, test): + return self.decorated.stopTest(test) + + def stopTestRun(self): + return self._call_maybe("stopTestRun", None) + + def addError(self, test, err): + return self.decorated.addError(test, err) + + def addFailure(self, test, err): + return self.decorated.addFailure(test, err) + + def addSuccess(self, test): + return self.decorated.addSuccess(test) + + def addSkip(self, test, reason): + return self._call_maybe("addSkip", self._degrade_skip, test, reason) + + def _degrade_skip(self, test, reason): + return self.decorated.addSuccess(test) + + def addExpectedFailure(self, test, err): + return self._call_maybe("addExpectedFailure", + self.decorated.addFailure, test, err) + + def addUnexpectedSuccess(self, test): + return self._call_maybe("addUnexpectedSuccess", + self.decorated.addSuccess, test) + + def progress(self, offset, whence): + return self._call_maybe("progress", None, offset, whence) + + def wasSuccessful(self): + return self.decorated.wasSuccessful() + + @property + def shouldStop(self): + return self.decorated.shouldStop + + def stop(self): + return self.decorated.stop() + + def time(self, a_datetime): + return self._call_maybe("time", None, a_datetime) + + +class HookedTestResultDecorator(TestResultDecorator): + """A TestResult which calls a hook on every event.""" + + def __init__(self, decorated): + self.super = super(HookedTestResultDecorator, self) + self.super.__init__(decorated) + + def startTest(self, test): self._before_event() - return self._call_maybe("startTestRun") + return self.super.startTest(test) + + def startTestRun(self): + self._before_event() + return self.super.startTestRun() def stopTest(self, test): self._before_event() - return self.decorated.stopTest(test) + return self.super.stopTest(test) def stopTestRun(self): self._before_event() - return self._call_maybe("stopTestRun") + return self.super.stopTestRun() def addError(self, test, err): self._before_event() - return self.decorated.addError(test, err) + return self.super.addError(test, err) def addFailure(self, test, err): self._before_event() - return self.decorated.addFailure(test, err) + return self.super.addFailure(test, err) def addSuccess(self, test): self._before_event() - return self.decorated.addSuccess(test) + return self.super.addSuccess(test) def addSkip(self, test, reason): self._before_event() - return self._call_maybe("addSkip", test, reason) + return self.super.addSkip(test, reason) def addExpectedFailure(self, test, err): self._before_event() - return self._call_maybe("addExpectedFailure", test, err) + return self.super.addExpectedFailure(test, err) def addUnexpectedSuccess(self, test): self._before_event() - return self._call_maybe("addUnexpectedSuccess", test) + return self.super.addUnexpectedSuccess(test) def progress(self, offset, whence): self._before_event() - return self._call_maybe("progress", offset, whence) + return self.super.progress(offset, whence) def wasSuccessful(self): self._before_event() - return self.decorated.wasSuccessful() + return self.super.wasSuccessful() @property def shouldStop(self): self._before_event() - return self.decorated.shouldStop + return self.super.shouldStop def stop(self): self._before_event() - return self.decorated.stop() + return self.super.stop() def time(self, a_datetime): self._before_event() - return self._call_maybe("time", a_datetime) + return self.super.time(a_datetime) class AutoTimingTestResultDecorator(HookedTestResultDecorator): @@ -126,10 +200,10 @@ class AutoTimingTestResultDecorator(HookedTestResultDecorator): if time is not None: return time = datetime.datetime.utcnow().replace(tzinfo=iso8601.Utc()) - self._call_maybe("time", time) + self._call_maybe("time", None, time) def progress(self, offset, whence): - return self._call_maybe("progress", offset, whence) + return self._call_maybe("progress", None, offset, whence) @property def shouldStop(self): @@ -144,7 +218,4 @@ class AutoTimingTestResultDecorator(HookedTestResultDecorator): result object and disable automatic timestamps. """ self._time = a_datetime - return self._call_maybe("time", a_datetime) - - def done(self): - """Transition function until stopTestRun is used.""" + return self._call_maybe("time", None, a_datetime) |
