Add TestResultFilter filter_predicate option
authorMartin Pool <mbp@sourcefrog.net>
Wed, 5 Aug 2009 06:57:48 +0000 (16:57 +1000)
committerMartin Pool <mbp@sourcefrog.net>
Wed, 5 Aug 2009 06:57:48 +0000 (16:57 +1000)
NEWS
python/subunit/__init__.py
python/subunit/tests/test_subunit_filter.py

diff --git a/NEWS b/NEWS
index 85db6bd181cbb8c45f0678f020715181263d411c..2ad39462ac7ff1b382910c260551302e0d5334c4 100644 (file)
--- a/NEWS
+++ b/NEWS
@@ -30,6 +30,9 @@ subunit release notes
       stream to a single JUnit style XML stream using the pyjunitxml
       python library.
 
+    * ``TestResultFilter`` takes a new optional constructor parameter 
+      ``filter_predicate``.  (Martin Pool)
+
   BUG FIXES:
 
   API CHANGES:
index 49073321858e6df307b97212b2a62399ab640534..4c97015e53dead9950a2dd050147e24f1b29772b 100644 (file)
@@ -792,16 +792,22 @@ class TestResultFilter(unittest.TestResult):
     the other instance must be interrogated.
 
     :ivar result: The result that tests are passed to after filtering.
+    :ivar filter_predicate: The callback run to decide whether to pass 
+        a result.
     """
 
     def __init__(self, result, filter_error=False, filter_failure=False,
-        filter_success=True, filter_skip=False):
+        filter_success=True, filter_skip=False,
+        filter_predicate=None):
         """Create a FilterResult object filtering to result.
         
         :param filter_error: Filter out errors.
         :param filter_failure: Filter out failures.
         :param filter_success: Filter out successful tests.
         :param filter_skip: Filter out skipped tests.
+        :param filter_predicate: A callable taking (test, err) and 
+            returning True if the result should be passed through.
+            err is None for success.
         """
         unittest.TestResult.__init__(self)
         self.result = result
@@ -809,21 +815,24 @@ class TestResultFilter(unittest.TestResult):
         self._filter_failure = filter_failure
         self._filter_success = filter_success
         self._filter_skip = filter_skip
+        if filter_predicate is None:
+            filter_predicate = lambda test, err: True
+        self.filter_predicate = filter_predicate
         
     def addError(self, test, err):
-        if not self._filter_error:
+        if not self._filter_error and self.filter_predicate(test, err):
             self.result.startTest(test)
             self.result.addError(test, err)
             self.result.stopTest(test)
 
     def addFailure(self, test, err):
-        if not self._filter_failure:
+        if not self._filter_failure and self.filter_predicate(test, err):
             self.result.startTest(test)
             self.result.addFailure(test, err)
             self.result.stopTest(test)
 
     def addSkip(self, test, reason):
-        if not self._filter_skip:
+        if not self._filter_skip and self.filter_predicate(test, reason):
             self.result.startTest(test)
             # This is duplicated, it would be nice to have on a 'calls
             # TestResults' mixin perhaps.
@@ -835,7 +844,7 @@ class TestResultFilter(unittest.TestResult):
             self.result.stopTest(test)
 
     def addSuccess(self, test):
-        if not self._filter_success:
+        if not self._filter_success and self.filter_predicate(test, None):
             self.result.startTest(test)
             self.result.addSuccess(test)
             self.result.stopTest(test)
index 1341d123c586dfbc017951927ab6f55aacf8452a..e7196ffb472808d7d69d49f0b821d4f8a8a2d80a 100644 (file)
@@ -91,6 +91,19 @@ class TestTestResultFilter(unittest.TestCase):
             self.filtered_result.failures])
         self.assertEqual(5, self.filtered_result.testsRun)
 
+    def test_filter_predicate(self):
+        """You can filter by predicate callbacks"""
+        self.filtered_result = unittest.TestResult()
+        filter_cb = lambda test, err: str(err).find('error details') != -1
+        self.filter = subunit.TestResultFilter(self.filtered_result,
+            filter_predicate=filter_cb,
+            filter_success=False)
+        self.run_tests()
+        self.assertEqual(1,
+            self.filtered_result.testsRun)
+        # I'd like to test filtering the xfail but it's blocked by
+        # https://bugs.edge.launchpad.net/subunit/+bug/409193 -- mbp 20090805
+
     def run_tests(self):
         self.setUpTestStream()
         self.test = subunit.ProtocolTestCase(self.input_stream)
@@ -109,7 +122,9 @@ test failed
 tags: local
 failure failed
 test error
-error error
+error error [
+error details
+]
 test skipped
 skip skipped
 test todo