summaryrefslogtreecommitdiff
path: root/python/subunit/__init__.py
diff options
context:
space:
mode:
authorRobert Collins <robertc@robertcollins.net>2011-05-02 10:45:27 +1200
committerRobert Collins <robertc@robertcollins.net>2011-05-02 10:45:27 +1200
commitb67756431fd3a5ebae3f6e0eba7185656b9459d4 (patch)
treee6ce0beeec8f8b95ef736683b948911b3a13cf92 /python/subunit/__init__.py
parent8301c8f3024496f57a393a83a153c73142b445ae (diff)
parent8a5727cd20a1a7ecb2050fce2977362e6b4aa068 (diff)
downloadsubunit-git-b67756431fd3a5ebae3f6e0eba7185656b9459d4.tar.gz
Support unexpected success outcomes.
Diffstat (limited to 'python/subunit/__init__.py')
-rw-r--r--python/subunit/__init__.py67
1 files changed, 54 insertions, 13 deletions
diff --git a/python/subunit/__init__.py b/python/subunit/__init__.py
index 807b605..9d5d075 100644
--- a/python/subunit/__init__.py
+++ b/python/subunit/__init__.py
@@ -201,6 +201,7 @@ class _ParserState(object):
self._tags_sym = (_b('tags'),)
self._time_sym = (_b('time'),)
self._xfail_sym = (_b('xfail'),)
+ self._uxsuccess_sym = (_b('uxsuccess'),)
self._start_simple = _u(" [")
self._start_multipart = _u(" [ multipart")
@@ -251,6 +252,8 @@ class _ParserState(object):
self.parser.subunitLineReceived(line)
elif cmd in self._xfail_sym:
self.addExpectedFail(offset, line)
+ elif cmd in self._uxsuccess_sym:
+ self.addUnexpectedSuccess(offset, line)
else:
self.parser.stdOutLineReceived(line)
else:
@@ -314,6 +317,14 @@ class _InTest(_ParserState):
self._outcome(offset, line, self._xfail,
self.parser._reading_xfail_details)
+ def _uxsuccess(self):
+ self.parser.client.addUnexpectedSuccess(self.parser._current_test)
+
+ def addUnexpectedSuccess(self, offset, line):
+ """A 'uxsuccess:' directive has been read."""
+ self._outcome(offset, line, self._uxsuccess,
+ self.parser._reading_uxsuccess_details)
+
def _failure(self):
self.parser.client.addFailure(self.parser._current_test, details={})
@@ -425,6 +436,17 @@ class _ReadingExpectedFailureDetails(_ReadingDetails):
return "xfail"
+class _ReadingUnexpectedSuccessDetails(_ReadingDetails):
+ """State for the subunit parser when reading uxsuccess details."""
+
+ def _report_outcome(self):
+ self.parser.client.addUnexpectedSuccess(self.parser._current_test,
+ details=self.details_parser.get_details())
+
+ def _outcome_label(self):
+ return "uxsuccess"
+
+
class _ReadingSkipDetails(_ReadingDetails):
"""State for the subunit parser when reading skip details."""
@@ -481,6 +503,7 @@ class TestProtocolServer(object):
self._reading_skip_details = _ReadingSkipDetails(self)
self._reading_success_details = _ReadingSuccessDetails(self)
self._reading_xfail_details = _ReadingExpectedFailureDetails(self)
+ self._reading_uxsuccess_details = _ReadingUnexpectedSuccessDetails(self)
# start with outside test.
self._state = self._outside_test
# Avoid casts on every call
@@ -632,7 +655,8 @@ class TestProtocolClient(testresult.TestResult):
"""
self._addOutcome("failure", test, error=error, details=details)
- def _addOutcome(self, outcome, test, error=None, details=None):
+ def _addOutcome(self, outcome, test, error=None, details=None,
+ error_permitted=True):
"""Report a failure in test test.
Only one of error and details should be provided: conceptually there
@@ -646,19 +670,28 @@ class TestProtocolClient(testresult.TestResult):
exc_info tuple.
:param details: New Testing-in-python drafted API; a dict from string
to subunit.Content objects.
- """
+ :param error_permitted: If True then one and only one of error or
+ details must be supplied. If False then error must not be supplied
+ and details is still optional. """
self._stream.write(_b("%s: %s" % (outcome, test.id())))
- if error is None and details is None:
- raise ValueError
+ if error_permitted:
+ if error is None and details is None:
+ raise ValueError
+ else:
+ if error is not None:
+ raise ValueError
if error is not None:
self._stream.write(self._start_simple)
# XXX: this needs to be made much stricter, along the lines of
# Martin[gz]'s work in testtools. Perhaps subunit can use that?
for line in self._exc_info_to_unicode(error, test).splitlines():
self._stream.write(("%s\n" % line).encode('utf8'))
- else:
+ elif details is not None:
self._write_details(details)
- self._stream.write(self._end_simple)
+ else:
+ self._stream.write(_b("\n"))
+ if details or error:
+ self._stream.write(self._end_simple)
def addSkip(self, test, reason=None, details=None):
"""Report a skipped test."""
@@ -671,13 +704,21 @@ class TestProtocolClient(testresult.TestResult):
def addSuccess(self, test, details=None):
"""Report a success in a test."""
- self._stream.write(_b("successful: %s" % test.id()))
- if not details:
- self._stream.write(_b("\n"))
- else:
- self._write_details(details)
- self._stream.write(self._end_simple)
- addUnexpectedSuccess = addSuccess
+ self._addOutcome("successful", test, details=details, error_permitted=False)
+
+ def addUnexpectedSuccess(self, test, details=None):
+ """Report an unexpected success in test test.
+
+ Details can optionally be provided: conceptually there
+ are two separate methods:
+ addError(self, test)
+ addError(self, test, details)
+
+ :param details: New Testing-in-python drafted API; a dict from string
+ to subunit.Content objects.
+ """
+ self._addOutcome("uxsuccess", test, details=details,
+ error_permitted=False)
def startTest(self, test):
"""Mark a test as starting its test run."""