From 525f5f07b9954502d034ea95ccb99bc381a9b4bf Mon Sep 17 00:00:00 2001 From: Jonathan Lange Date: Mon, 18 Oct 2010 13:41:41 +0100 Subject: [PATCH] Mark unhandled errors in deferreds differently to regular errors. --- testtools/deferredruntest.py | 4 ++-- testtools/runtest.py | 11 ++++++++--- testtools/testcase.py | 18 ++++++++++-------- testtools/tests/test_deferredruntest.py | 7 +++++-- 4 files changed, 25 insertions(+), 15 deletions(-) diff --git a/testtools/deferredruntest.py b/testtools/deferredruntest.py index 4feba18..bc923f4 100644 --- a/testtools/deferredruntest.py +++ b/testtools/deferredruntest.py @@ -167,10 +167,10 @@ class AsynchronousDeferredRunTest(RunTest): successful = False # XXX: Maybe we could log creator & invoker here as well if # present. - # XXX: Is there anything flagging these as unhandled errors? for debug_info in unhandled: f = debug_info.failResult - self._got_user_exception((f.type, f.value, f.tb)) + self._got_user_exception( + (f.type, f.value, f.tb), 'unhandled-error-in-deferred') junk = spinner.clear_junk() if junk: successful = False diff --git a/testtools/runtest.py b/testtools/runtest.py index 779cdbc..3adabf0 100644 --- a/testtools/runtest.py +++ b/testtools/runtest.py @@ -146,11 +146,16 @@ class RunTest(object): except: return self._got_user_exception(sys.exc_info()) - def _got_user_exception(self, exc_info): - """Called when user code raises an exception.""" + def _got_user_exception(self, exc_info, tb_label='traceback'): + """Called when user code raises an exception. + + :param exc_info: A sys.exc_info() tuple for the user error. + :param tb_label: An optional string label for the error. If + not specified, will default to 'traceback'. + """ try: e = exc_info[1] - self.case.onException(exc_info) + self.case.onException(exc_info, tb_label=tb_label) finally: del exc_info for exc_class, handler in self.handlers: diff --git a/testtools/testcase.py b/testtools/testcase.py index 24a7b4f..b116ecc 100644 --- a/testtools/testcase.py +++ b/testtools/testcase.py @@ -120,7 +120,9 @@ class TestCase(unittest.TestCase): unittest.TestCase.__init__(self, *args, **kwargs) self._cleanups = [] self._unique_id_gen = itertools.count(1) - self._traceback_id_gen = itertools.count(0) + # Generators to ensure unique traceback ids. Maps traceback label to + # iterators. + self._traceback_id_gens = {} self.__setup_called = False self.__teardown_called = False # __details is lazy-initialized so that a constructed-but-not-run @@ -429,14 +431,14 @@ class TestCase(unittest.TestCase): prefix = self.id() return '%s-%d' % (prefix, self.getUniqueInteger()) - def onException(self, exc_info): + def onException(self, exc_info, tb_label='traceback'): """Called when an exception propogates from test code. :seealso addOnException: """ if exc_info[0] not in [ TestSkipped, _UnexpectedSuccess, _ExpectedFailure]: - self._report_traceback(exc_info) + self._report_traceback(exc_info, tb_label=tb_label) for handler in self.__exception_handlers: handler(exc_info) @@ -461,12 +463,12 @@ class TestCase(unittest.TestCase): self._add_reason(reason) result.addSkip(self, details=self.getDetails()) - def _report_traceback(self, exc_info): - tb_id = advance_iterator(self._traceback_id_gen) + def _report_traceback(self, exc_info, tb_label='traceback'): + id_gen = self._traceback_id_gens.setdefault( + tb_label, itertools.count(0)) + tb_id = advance_iterator(id_gen) if tb_id: - tb_label = 'traceback-%d' % tb_id - else: - tb_label = 'traceback' + tb_label = '%s-%d' % (tb_label, tb_id) self.addDetail(tb_label, content.TracebackContent(exc_info, self)) @staticmethod diff --git a/testtools/tests/test_deferredruntest.py b/testtools/tests/test_deferredruntest.py index 37d0eeb..093763e 100644 --- a/testtools/tests/test_deferredruntest.py +++ b/testtools/tests/test_deferredruntest.py @@ -345,7 +345,10 @@ class TestAsynchronousDeferredRunTest(TestCase): ('addError', test, None), ('stopTest', test)])) self.assertThat( - list(error.keys()), Equals(['traceback', 'traceback-1'])) + list(error.keys()), Equals([ + 'unhandled-error-in-deferred', + 'unhandled-error-in-deferred-1', + ])) def test_keyboard_interrupt_stops_test_run(self): # If we get a SIGINT during a test run, the test stops and no more @@ -438,7 +441,7 @@ class TestAsynchronousDeferredRunTest(TestCase): 'traceback', 'traceback-1', 'traceback-2', - 'traceback-3', + 'unhandled-error-in-deferred', ]))