Move transport decoration fallback to use the ExtendedToOriginal fallback.
authorRobert Collins <robertc@robertcollins.net>
Sun, 25 Oct 2009 04:36:07 +0000 (15:36 +1100)
committerRobert Collins <robertc@robertcollins.net>
Sun, 25 Oct 2009 04:36:07 +0000 (15:36 +1100)
python/subunit/test_results.py
python/subunit/tests/test_test_results.py

index fad4760bd6248819cddaea4ae58233c2e7cec198..e0891a33fad87b562af56d7ed1d4c106cf1874ec 100644 (file)
@@ -36,42 +36,20 @@ class TestResultDecorator(object):
 
     def __init__(self, decorated):
         """Create a TestResultDecorator forwarding to decorated."""
-        self.decorated = decorated
-
-    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
-        support. While newer clients won't call these methods if they don't
-        exist, they do exist on the decorator, and thus the decorator has to be
-        the one to filter them out.
-
-        :param method_name: The name of the method to call.
-        :param fallback: If not None, the fallback to call 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)
+        # Make every decorator degrade gracefully.
+        self.decorated = ExtendedToOriginalDecorator(decorated)
 
     def startTest(self, test):
         return self.decorated.startTest(test)
 
     def startTestRun(self):
-        return self._call_maybe("startTestRun", None)
+        return self.decorated.startTestRun()
 
     def stopTest(self, test):
         return self.decorated.stopTest(test)
 
     def stopTestRun(self):
-        return self._call_maybe("stopTestRun", None)
+        return self.decorated.stopTestRun()
 
     def addError(self, test, err):
         return self.decorated.addError(test, err)
@@ -83,21 +61,16 @@ class TestResultDecorator(object):
         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)
+        return self.decorated.addSkip(test, reason)
 
     def addExpectedFailure(self, test, err):
-        return self._call_maybe("addExpectedFailure",
-            self.decorated.addFailure, test, err)
+        return self.decorated.addExpectedFailure(test, err)
 
     def addUnexpectedSuccess(self, test):
-        return self._call_maybe("addUnexpectedSuccess",
-            self.decorated.addSuccess, test)
+        return self.decorated.addUnexpectedSuccess(test)
 
     def progress(self, offset, whence):
-        return self._call_maybe("progress", None, offset, whence)
+        return self.decorated.progress(offset, whence)
 
     def wasSuccessful(self):
         return self.decorated.wasSuccessful()
@@ -110,10 +83,10 @@ class TestResultDecorator(object):
         return self.decorated.stop()
 
     def tags(self, gone_tags, new_tags):
-        return self._call_maybe("tags", None, gone_tags, new_tags)
+        return self.decorated.time(gone_tags, new_tags)
 
     def time(self, a_datetime):
-        return self._call_maybe("time", None, a_datetime)
+        return self.decorated.time(a_datetime)
 
 
 class HookedTestResultDecorator(TestResultDecorator):
@@ -202,10 +175,10 @@ class AutoTimingTestResultDecorator(HookedTestResultDecorator):
         if time is not None:
             return
         time = datetime.datetime.utcnow().replace(tzinfo=iso8601.Utc())
-        self._call_maybe("time", None, time)
+        self.decorated.time(time)
 
     def progress(self, offset, whence):
-        return self._call_maybe("progress", None, offset, whence)
+        return self.decorated.progress(offset, whence)
 
     @property
     def shouldStop(self):
@@ -220,7 +193,7 @@ class AutoTimingTestResultDecorator(HookedTestResultDecorator):
             result object and disable automatic timestamps.
         """
         self._time = a_datetime
-        return self._call_maybe("time", None, a_datetime)
+        return self.decorated.time(a_datetime)
 
 
 class ExtendedToOriginalDecorator(object):
@@ -338,6 +311,10 @@ class ExtendedToOriginalDecorator(object):
             return
         return method(offset, whence)
 
+    @property
+    def shouldStop(self):
+        return self.decorated.shouldStop
+
     def startTest(self, test):
         return self.decorated.startTest(test)
 
@@ -347,6 +324,9 @@ class ExtendedToOriginalDecorator(object):
         except AttributeError:
             return
 
+    def stop(self):
+        return self.decorated.stop()
+
     def stopTest(self, test):
         return self.decorated.stopTest(test)
 
@@ -367,3 +347,7 @@ class ExtendedToOriginalDecorator(object):
         if method is None:
             return
         return method(a_datetime)
+
+    def wasSuccessful(self):
+        return self.decorated.wasSuccessful()
+
index d333c10e390e37a2994fb31cb53fd686866c18b5..cb7b47eb1ddeda5606425b99e3a8eed526738c23 100644 (file)
@@ -64,6 +64,7 @@ class LoggingResult(object):
     
     def __init__(self):
         self._calls = []
+        self.shouldStop = False
 
 
 class Python26TestResult(LoggingResult):
@@ -81,6 +82,9 @@ class Python26TestResult(LoggingResult):
     def startTest(self, test):
         self._calls.append(('startTest', test))
 
+    def stop(self):
+        self.shouldStop = True
+
     def stopTest(self, test):
         self._calls.append(('stopTest', test))
 
@@ -259,6 +263,12 @@ class TestExtendedToOriginalResultDecorator(
         self.converter.progress(1, 2)
         self.assertEqual([('progress', 1, 2)], self.result._calls)
 
+    def test_shouldStop(self):
+        self.make_26_result()
+        self.assertEqual(False, self.converter.shouldStop)
+        self.converter.decorated.stop()
+        self.assertEqual(True, self.converter.shouldStop)
+
     def test_startTest_py26(self):
         self.make_26_result()
         self.converter.startTest(self)
@@ -476,7 +486,7 @@ class TestExtendedToOriginalAddUnexpectedSuccess(
 class TestHookedTestResultDecorator(unittest.TestCase):
 
     def setUp(self):
-        # And end to the chain
+        # An end to the chain
         terminal = unittest.TestResult()
         # Asserts that the call was made to self.result before asserter was
         # called.
@@ -484,13 +494,14 @@ class TestHookedTestResultDecorator(unittest.TestCase):
         # The result object we call, which much increase its call count.
         self.result = LoggingDecorator(asserter)
         asserter.earlier = self.result
+        self.decorated = asserter
 
     def tearDown(self):
         # The hook in self.result must have been called
         self.assertEqual(1, self.result._calls)
         # The hook in asserter must have been called too, otherwise the
         # assertion about ordering won't have completed.
-        self.assertEqual(1, self.result.decorated._calls)
+        self.assertEqual(1, self.decorated._calls)
 
     def test_startTest(self):
         self.result.startTest(self)
@@ -546,20 +557,21 @@ class TestAutoTimingTestResultDecorator(unittest.TestCase):
         # The result object under test.
         self.result = subunit.test_results.AutoTimingTestResultDecorator(
             terminal)
+        self.decorated = terminal
 
     def test_without_time_calls_time_is_called_and_not_None(self):
         self.result.startTest(self)
-        self.assertEqual(1, len(self.result.decorated._calls))
-        self.assertNotEqual(None, self.result.decorated._calls[0])
+        self.assertEqual(1, len(self.decorated._calls))
+        self.assertNotEqual(None, self.decorated._calls[0])
 
     def test_no_time_from_progress(self):
         self.result.progress(1, subunit.PROGRESS_CUR)
-        self.assertEqual(0, len(self.result.decorated._calls))
+        self.assertEqual(0, len(self.decorated._calls))
 
     def test_no_time_from_shouldStop(self):
-        self.result.decorated.stop()
+        self.decorated.stop()
         self.result.shouldStop
-        self.assertEqual(0, len(self.result.decorated._calls))
+        self.assertEqual(0, len(self.decorated._calls))
 
     def test_calling_time_inhibits_automatic_time(self):
         # Calling time() outputs a time signal immediately and prevents
@@ -568,22 +580,22 @@ class TestAutoTimingTestResultDecorator(unittest.TestCase):
         self.result.time(time)
         self.result.startTest(self)
         self.result.stopTest(self)
-        self.assertEqual(1, len(self.result.decorated._calls))
-        self.assertEqual(time, self.result.decorated._calls[0])
+        self.assertEqual(1, len(self.decorated._calls))
+        self.assertEqual(time, self.decorated._calls[0])
 
     def test_calling_time_None_enables_automatic_time(self):
         time = datetime.datetime(2009,10,11,12,13,14,15, iso8601.Utc())
         self.result.time(time)
-        self.assertEqual(1, len(self.result.decorated._calls))
-        self.assertEqual(time, self.result.decorated._calls[0])
+        self.assertEqual(1, len(self.decorated._calls))
+        self.assertEqual(time, self.decorated._calls[0])
         # Calling None passes the None through, in case other results care.
         self.result.time(None)
-        self.assertEqual(2, len(self.result.decorated._calls))
-        self.assertEqual(None, self.result.decorated._calls[1])
+        self.assertEqual(2, len(self.decorated._calls))
+        self.assertEqual(None, self.decorated._calls[1])
         # Calling other methods doesn't generate an automatic time event.
         self.result.startTest(self)
-        self.assertEqual(3, len(self.result.decorated._calls))
-        self.assertNotEqual(None, self.result.decorated._calls[2])
+        self.assertEqual(3, len(self.decorated._calls))
+        self.assertNotEqual(None, self.decorated._calls[2])
 
 
 def test_suite():