Dependencies
------------
-Python for the filters
-A C compiler for the C bindings
-Perl for the Perl tools (including subunit-diff)
-Check to run the subunit test suite.
-python-gtk2 if you wish to use subunit2gtk
-python-junitxml if you wish to use subunit2junitxml
+* Python for the filters
+* 'testtools' (On Debian and Ubuntu systems the 'python-testtools' package) for
+ the extended test API which permits attachments. Version 0.9.2 or newer is
+ required.
+* A C compiler for the C bindings
+* Perl for the Perl tools (including subunit-diff)
+* Check to run the subunit test suite.
+* python-gtk2 if you wish to use subunit2gtk
+* python-junitxml if you wish to use subunit2junitxml
* Multipart test outcomes are tentatively supported; the exact protocol
for them, both serialiser and object is not yet finalised. Testers and
- early adopters are sought.
+ early adopters are sought. As part of this and also in an attempt to
+ provider a more precise focus on the wire protocol and toolchain,
+ Subunit now depends on testtools (http://launchpad.net/testtools)
+ release 0.9.0 or newer.
* The C library now has ``subunit_test_skip``.
``addFailure``, ``addSkip`` take an optional keyword parameter ``details``
which can be used instead of the usual python unittest parameter.
When used the value of details should be a dict from ``string`` to
-``subunit.content.Content`` objects. This is a draft API being worked on with
+``testtools.content.Content`` objects. This is a draft API being worked on with
the Python Testing In Python mail list, with the goal of permitting a common
way to provide additional data beyond a traceback, such as captured data from
disk, logging messages etc.
---------------
* subunit.chunked contains HTTP chunked encoding/decoding logic.
-* subunit.content contains a minimal assumptions MIME content representation.
-* subunit.content_type contains a MIME Content-Type representation.
+* testtools.content contains a minimal assumptions MIME content representation.
+* testtools.content_type contains a MIME Content-Type representation.
* subunit.test_results contains TestResult helper classes.
"""
import unittest
import iso8601
+from testtools import content, content_type, ExtendedToOriginalDecorator
+from testtools.testresult import _StringException
-import chunked, content, content_type, details, test_results
+import chunked, details, test_results
PROGRESS_SET = 0
of mixed protocols. By default, sys.stdout will be used for
convenience.
"""
- self.client = test_results.ExtendedToOriginalDecorator(client)
+ self.client = ExtendedToOriginalDecorator(client)
if stream is None:
stream = sys.stdout
self._stream = stream
self._stream.write(line)
-class RemoteException(Exception):
- """An exception that occured remotely to Python."""
-
- def __eq__(self, other):
- try:
- return self.args == other.args
- except AttributeError:
- return False
+try:
+ from testtools.testresult import _StringException as RemoteException
+ _remote_exception_str = '_StringException' # For testing.
+except ImportError:
+ raise ImportError ("testtools.testresult does not contain _StringException, check your version.")
class TestProtocolClient(unittest.TestResult):
def RemoteError(description=""):
- if description == "":
- description = "\n"
- return (RemoteException, RemoteException(description), None)
+ return (_StringException, _StringException(description), None)
class RemotedTestCase(unittest.TestCase):
+++ /dev/null
-#
-# subunit: extensions to Python unittest to get test results from subprocesses.
-# Copyright (C) 2009 Robert Collins <robertc@robertcollins.net>
-#
-# Licensed under either the Apache License, Version 2.0 or the BSD 3-clause
-# license at the users choice. A copy of both licenses are available in the
-# project source as Apache-2.0 and BSD. You may not use this file except in
-# compliance with one of these two licences.
-#
-# Unless required by applicable law or agreed to in writing, software
-# distributed under these licenses is distributed on an "AS IS" BASIS, WITHOUT
-# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
-# license you chose for the specific language governing permissions and
-# limitations under that license.
-#
-
-"""Content - a MIME-like Content object."""
-
-from unittest import TestResult
-
-import subunit
-from subunit.content_type import ContentType
-
-
-class Content(object):
- """A MIME-like Content object.
-
- Content objects can be serialised to bytes using the iter_bytes method.
- If the Content-Type is recognised by other code, they are welcome to
- look for richer contents that mere byte serialisation - for example in
- memory object graphs etc. However, such code MUST be prepared to receive
- a generic Content object that has been reconstructed from a byte stream.
-
- :ivar content_type: The content type of this Content.
- """
-
- def __init__(self, content_type, get_bytes):
- """Create a ContentType."""
- if None in (content_type, get_bytes):
- raise ValueError("None not permitted in %r, %r" % (
- content_type, get_bytes))
- self.content_type = content_type
- self._get_bytes = get_bytes
-
- def __eq__(self, other):
- return (self.content_type == other.content_type and
- ''.join(self.iter_bytes()) == ''.join(other.iter_bytes()))
-
- def iter_bytes(self):
- """Iterate over bytestrings of the serialised content."""
- return self._get_bytes()
-
- def __repr__(self):
- return "<Content type=%r, value=%r>" % (
- self.content_type, ''.join(self.iter_bytes()))
-
-
-class TracebackContent(Content):
- """Content object for tracebacks.
-
- This adapts an exc_info tuple to the Content interface.
- text/x-traceback;language=python is used for the mime type, in order to
- provide room for other languages to format their tracebacks differently.
- """
-
- def __init__(self, err):
- """Create a TracebackContent for err."""
- if err is None:
- raise ValueError("err may not be None")
- content_type = ContentType('text', 'x-traceback',
- {"language": "python"})
- self._result = TestResult()
- super(TracebackContent, self).__init__(content_type,
- lambda:[self._result._exc_info_to_string(err,
- subunit.RemotedTestCase(''))])
+++ /dev/null
-#
-# subunit: extensions to Python unittest to get test results from subprocesses.
-# Copyright (C) 2009 Robert Collins <robertc@robertcollins.net>
-#
-# Licensed under either the Apache License, Version 2.0 or the BSD 3-clause
-# license at the users choice. A copy of both licenses are available in the
-# project source as Apache-2.0 and BSD. You may not use this file except in
-# compliance with one of these two licences.
-#
-# Unless required by applicable law or agreed to in writing, software
-# distributed under these licenses is distributed on an "AS IS" BASIS, WITHOUT
-# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
-# license you chose for the specific language governing permissions and
-# limitations under that license.
-#
-
-"""ContentType - a MIME Content Type."""
-
-class ContentType(object):
- """A content type from http://www.iana.org/assignments/media-types/
-
- :ivar type: The primary type, e.g. "text" or "application"
- :ivar subtype: The subtype, e.g. "plain" or "octet-stream"
- :ivar parameters: A dict of additional parameters specific to the
- content type.
- """
-
- def __init__(self, primary_type, sub_type, parameters=None):
- """Create a ContentType."""
- if None in (primary_type, sub_type):
- raise ValueError("None not permitted in %r, %r" % (
- primary_type, sub_type))
- self.type = primary_type
- self.subtype = sub_type
- self.parameters = parameters or {}
-
- def __eq__(self, other):
- if type(other) != ContentType:
- return False
- return self.__dict__ == other.__dict__
-
- def __repr__(self):
- return "%s/%s params=%s" % (self.type, self.subtype, self.parameters)
from cStringIO import StringIO
-import chunked, content, content_type
+from testtools import content, content_type
+
+import chunked
class DetailsParser(object):
import datetime
import iso8601
+import testtools
import subunit
def __init__(self, decorated):
"""Create a TestResultDecorator forwarding to decorated."""
# Make every decorator degrade gracefully.
- self.decorated = ExtendedToOriginalDecorator(decorated)
+ self.decorated = testtools.ExtendedToOriginalDecorator(decorated)
def startTest(self, test):
return self.decorated.startTest(test)
if id.startswith("subunit.RemotedTestCase."):
return id[len("subunit.RemotedTestCase."):]
return id
-
-
-class ExtendedToOriginalDecorator(object):
- """Permit new TestResult API code to degrade gracefully with old results.
-
- This decorates an existing TestResult and converts missing outcomes
- such as addSkip to older outcomes such as addSuccess. It also supports
- the extended details protocol. In all cases the most recent protocol
- is attempted first, and fallbacks only occur when the decorated result
- does not support the newer style of calling.
- """
-
- def __init__(self, decorated):
- self.decorated = decorated
-
- def addError(self, test, err=None, details=None):
- self._check_args(err, details)
- if details is not None:
- try:
- return self.decorated.addError(test, details=details)
- except TypeError, e:
- # have to convert
- err = self._details_to_exc_info(details)
- return self.decorated.addError(test, err)
-
- def addExpectedFailure(self, test, err=None, details=None):
- self._check_args(err, details)
- addExpectedFailure = getattr(self.decorated, 'addExpectedFailure', None)
- if addExpectedFailure is None:
- return self.addSuccess(test)
- if details is not None:
- try:
- return addExpectedFailure(test, details=details)
- except TypeError, e:
- # have to convert
- err = self._details_to_exc_info(details)
- return addExpectedFailure(test, err)
-
- def addFailure(self, test, err=None, details=None):
- self._check_args(err, details)
- if details is not None:
- try:
- return self.decorated.addFailure(test, details=details)
- except TypeError, e:
- # have to convert
- err = self._details_to_exc_info(details)
- return self.decorated.addFailure(test, err)
-
- def addSkip(self, test, reason=None, details=None):
- self._check_args(reason, details)
- addSkip = getattr(self.decorated, 'addSkip', None)
- if addSkip is None:
- return self.decorated.addSuccess(test)
- if details is not None:
- try:
- return addSkip(test, details=details)
- except TypeError, e:
- # have to convert
- reason = self._details_to_str(details)
- return addSkip(test, reason)
-
- def addUnexpectedSuccess(self, test, details=None):
- outcome = getattr(self.decorated, 'addUnexpectedSuccess', None)
- if outcome is None:
- return self.decorated.addSuccess(test)
- if details is not None:
- try:
- return outcome(test, details=details)
- except TypeError, e:
- pass
- return outcome(test)
-
- def addSuccess(self, test, details=None):
- if details is not None:
- try:
- return self.decorated.addSuccess(test, details=details)
- except TypeError, e:
- pass
- return self.decorated.addSuccess(test)
-
- def _check_args(self, err, details):
- param_count = 0
- if err is not None:
- param_count += 1
- if details is not None:
- param_count += 1
- if param_count != 1:
- raise ValueError("Must pass only one of err '%s' and details '%s"
- % (err, details))
-
- def _details_to_exc_info(self, details):
- """Convert a details dict to an exc_info tuple."""
- return subunit.RemoteError(self._details_to_str(details))
-
- def _details_to_str(self, details):
- """Convert a details dict to a string."""
- lines = []
- # sorted is for testing, may want to remove that and use a dict
- # subclass with defined order for iteritems instead.
- for key, content in sorted(details.iteritems()):
- if content.content_type.type != 'text':
- lines.append('Binary content: %s\n' % key)
- continue
- lines.append('Text attachment: %s\n' % key)
- lines.append('------------\n')
- lines.extend(content.iter_bytes())
- if not lines[-1].endswith('\n'):
- lines.append('\n')
- lines.append('------------\n')
- return ''.join(lines)
-
- def progress(self, offset, whence):
- method = getattr(self.decorated, 'progress', None)
- if method is None:
- return
- return method(offset, whence)
-
- @property
- def shouldStop(self):
- return self.decorated.shouldStop
-
- def startTest(self, test):
- return self.decorated.startTest(test)
-
- def startTestRun(self):
- try:
- return self.decorated.startTestRun()
- except AttributeError:
- return
-
- def stop(self):
- return self.decorated.stop()
-
- def stopTest(self, test):
- return self.decorated.stopTest(test)
-
- def stopTestRun(self):
- try:
- return self.decorated.stopTestRun()
- except AttributeError:
- return
-
- def tags(self, new_tags, gone_tags):
- method = getattr(self.decorated, 'tags', None)
- if method is None:
- return
- return method(new_tags, gone_tags)
-
- def time(self, a_datetime):
- method = getattr(self.decorated, 'time', None)
- if method is None:
- return
- return method(a_datetime)
-
- def wasSuccessful(self):
- return self.decorated.wasSuccessful()
-
from subunit.tests import (
TestUtil,
test_chunked,
- test_content_type,
- test_content,
test_details,
test_progress_model,
test_subunit_filter,
def test_suite():
result = TestUtil.TestSuite()
result.addTest(test_chunked.test_suite())
- result.addTest(test_content_type.test_suite())
- result.addTest(test_content.test_suite())
result.addTest(test_details.test_suite())
result.addTest(test_progress_model.test_suite())
result.addTest(test_test_results.test_suite())
+++ /dev/null
-#
-# subunit: extensions to Python unittest to get test results from subprocesses.
-# Copyright (C) 2009 Robert Collins <robertc@robertcollins.net>
-#
-# Licensed under either the Apache License, Version 2.0 or the BSD 3-clause
-# license at the users choice. A copy of both licenses are available in the
-# project source as Apache-2.0 and BSD. You may not use this file except in
-# compliance with one of these two licences.
-#
-# Unless required by applicable law or agreed to in writing, software
-# distributed under these licenses is distributed on an "AS IS" BASIS, WITHOUT
-# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
-# license you chose for the specific language governing permissions and
-# limitations under that license.
-#
-
-import unittest
-import subunit
-from subunit.content import Content, TracebackContent
-from subunit.content_type import ContentType
-
-
-def test_suite():
- loader = subunit.tests.TestUtil.TestLoader()
- result = loader.loadTestsFromName(__name__)
- return result
-
-
-class TestContent(unittest.TestCase):
-
- def test___init___None_errors(self):
- self.assertRaises(ValueError, Content, None, None)
- self.assertRaises(ValueError, Content, None, lambda:["traceback"])
- self.assertRaises(ValueError, Content,
- ContentType("text", "traceback"), None)
-
- def test___init___sets_ivars(self):
- content_type = ContentType("foo", "bar")
- content = Content(content_type, lambda:["bytes"])
- self.assertEqual(content_type, content.content_type)
- self.assertEqual(["bytes"], list(content.iter_bytes()))
-
- def test___eq__(self):
- content_type = ContentType("foo", "bar")
- content1 = Content(content_type, lambda:["bytes"])
- content2 = Content(content_type, lambda:["bytes"])
- content3 = Content(content_type, lambda:["by", "tes"])
- content4 = Content(content_type, lambda:["by", "te"])
- content5 = Content(ContentType("f","b"), lambda:["by", "tes"])
- self.assertEqual(content1, content2)
- self.assertEqual(content1, content3)
- self.assertNotEqual(content1, content4)
- self.assertNotEqual(content1, content5)
-
-
-class TestTracebackContent(unittest.TestCase):
-
- def test___init___None_errors(self):
- self.assertRaises(ValueError, TracebackContent, None)
-
- def test___init___sets_ivars(self):
- content = TracebackContent(subunit.RemoteError("weird"))
- content_type = ContentType("text", "x-traceback",
- {"language":"python"})
- self.assertEqual(content_type, content.content_type)
- result = unittest.TestResult()
- expected = result._exc_info_to_string(subunit.RemoteError("weird"),
- subunit.RemotedTestCase(''))
- self.assertEqual(expected, ''.join(list(content.iter_bytes())))
+++ /dev/null
-#
-# subunit: extensions to Python unittest to get test results from subprocesses.
-# Copyright (C) 2009 Robert Collins <robertc@robertcollins.net>
-#
-# Licensed under either the Apache License, Version 2.0 or the BSD 3-clause
-# license at the users choice. A copy of both licenses are available in the
-# project source as Apache-2.0 and BSD. You may not use this file except in
-# compliance with one of these two licences.
-#
-# Unless required by applicable law or agreed to in writing, software
-# distributed under these licenses is distributed on an "AS IS" BASIS, WITHOUT
-# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
-# license you chose for the specific language governing permissions and
-# limitations under that license.
-#
-
-import unittest
-import subunit
-from subunit.content_type import ContentType
-
-
-def test_suite():
- loader = subunit.tests.TestUtil.TestLoader()
- result = loader.loadTestsFromName(__name__)
- return result
-
-
-class TestContentType(unittest.TestCase):
-
- def test___init___None_errors(self):
- self.assertRaises(ValueError, ContentType, None, None)
- self.assertRaises(ValueError, ContentType, None, "traceback")
- self.assertRaises(ValueError, ContentType, "text", None)
-
- def test___init___sets_ivars(self):
- content_type = ContentType("foo", "bar")
- self.assertEqual("foo", content_type.type)
- self.assertEqual("bar", content_type.subtype)
- self.assertEqual({}, content_type.parameters)
-
- def test___init___with_parameters(self):
- content_type = ContentType("foo", "bar", {"quux":"thing"})
- self.assertEqual({"quux":"thing"}, content_type.parameters)
-
- def test___eq__(self):
- content_type1 = ContentType("foo", "bar", {"quux":"thing"})
- content_type2 = ContentType("foo", "bar", {"quux":"thing"})
- content_type3 = ContentType("foo", "bar", {"quux":"thing2"})
- self.assertTrue(content_type1.__eq__(content_type2))
- self.assertFalse(content_type1.__eq__(content_type3))
import os
import sys
+from testtools.content import Content, TracebackContent
+from testtools.content_type import ContentType
+
import subunit
-from subunit.content import Content, TracebackContent
-from subunit.content_type import ContentType
+from subunit import _remote_exception_str
import subunit.iso8601 as iso8601
from subunit.tests.test_test_results import (
ExtendedTestResult,
bing = subunit.RemotedTestCase("bing crosby")
an_error = subunit.RemotedTestCase("an error")
self.assertEqual(client.errors,
- [(an_error, 'RemoteException: \n\n')])
+ [(an_error, _remote_exception_str + '\n')])
self.assertEqual(
client.failures,
- [(bing, "RemoteException: Text attachment: traceback\n"
+ [(bing, _remote_exception_str + ": Text attachment: traceback\n"
"------------\nfoo.c:53:ERROR invalid state\n"
"------------\n\n")])
self.assertEqual(client.testsRun, 3)
"'A test description'>", "%r" % test)
result = unittest.TestResult()
test.run(result)
- self.assertEqual([(test, "RemoteException: "
+ self.assertEqual([(test, _remote_exception_str + ": "
"Cannot run RemotedTestCases.\n\n")],
result.errors)
self.assertEqual(1, result.testsRun)
ContentType('text', 'plain'), lambda:['serialised\nform'])}
self.sample_tb_details = dict(self.sample_details)
self.sample_tb_details['traceback'] = TracebackContent(
- subunit.RemoteError("boo qux"))
+ subunit.RemoteError("boo qux"), self.test)
def test_start_test(self):
"""Test startTest on a TestProtocolClient."""
self.test, subunit.RemoteError("boo qux"))
self.assertEqual(
self.io.getvalue(),
- 'failure: %s [\nRemoteException: boo qux\n]\n' % self.test.id())
+ ('failure: %s [\n' + _remote_exception_str + ': boo qux\n]\n')
+ % self.test.id())
def test_add_failure_details(self):
"""Test addFailure on a TestProtocolClient with details."""
self.test, details=self.sample_tb_details)
self.assertEqual(
self.io.getvalue(),
- "failure: %s [ multipart\n"
+ ("failure: %s [ multipart\n"
"Content-Type: text/plain\n"
"something\n"
"F\r\nserialised\nform0\r\n"
"Content-Type: text/x-traceback;language=python\n"
"traceback\n"
- "19\r\nRemoteException: boo qux\n0\r\n"
- "]\n" % self.test.id())
+ "1A\r\n" + _remote_exception_str + ": boo qux\n0\r\n"
+ "]\n") % self.test.id())
def test_add_error(self):
"""Test stopTest on a TestProtocolClient."""
self.test, subunit.RemoteError("phwoar crikey"))
self.assertEqual(
self.io.getvalue(),
- 'error: %s [\n'
- "RemoteException: phwoar crikey\n"
- "]\n" % self.test.id())
+ ('error: %s [\n' +
+ _remote_exception_str + ": phwoar crikey\n"
+ "]\n") % self.test.id())
def test_add_error_details(self):
"""Test stopTest on a TestProtocolClient with details."""
self.test, details=self.sample_tb_details)
self.assertEqual(
self.io.getvalue(),
- "error: %s [ multipart\n"
+ ("error: %s [ multipart\n"
"Content-Type: text/plain\n"
"something\n"
"F\r\nserialised\nform0\r\n"
"Content-Type: text/x-traceback;language=python\n"
"traceback\n"
- "19\r\nRemoteException: boo qux\n0\r\n"
- "]\n" % self.test.id())
+ "1A\r\n" + _remote_exception_str + ": boo qux\n0\r\n"
+ "]\n") % self.test.id())
def test_add_expected_failure(self):
"""Test addExpectedFailure on a TestProtocolClient."""
self.test, subunit.RemoteError("phwoar crikey"))
self.assertEqual(
self.io.getvalue(),
- 'xfail: %s [\n'
- "RemoteException: phwoar crikey\n"
- "]\n" % self.test.id())
+ ('xfail: %s [\n' +
+ _remote_exception_str + ": phwoar crikey\n"
+ "]\n") % self.test.id())
def test_add_expected_failure_details(self):
"""Test addExpectedFailure on a TestProtocolClient with details."""
self.test, details=self.sample_tb_details)
self.assertEqual(
self.io.getvalue(),
- "xfail: %s [ multipart\n"
+ ("xfail: %s [ multipart\n"
"Content-Type: text/plain\n"
"something\n"
"F\r\nserialised\nform0\r\n"
"Content-Type: text/x-traceback;language=python\n"
"traceback\n"
- "19\r\nRemoteException: boo qux\n0\r\n"
- "]\n" % self.test.id())
+ "1A\r\n"+ _remote_exception_str + ": boo qux\n0\r\n"
+ "]\n") % self.test.id())
def test_add_skip(self):
"""Test addSkip on a TestProtocolClient."""
import os
import sys
+from testtools.content_type import ContentType
+from testtools.content import Content
+
import subunit
import subunit.iso8601 as iso8601
import subunit.test_results
-from subunit.content_type import ContentType
-from subunit.content import Content
class LoggingDecorator(subunit.test_results.HookedTestResultDecorator):
self._calls.append(('time', time))
-class TestExtendedToOriginalResultDecoratorBase(unittest.TestCase):
-
- def make_26_result(self):
- self.result = Python26TestResult()
- self.make_converter()
-
- def make_27_result(self):
- self.result = Python27TestResult()
- self.make_converter()
-
- def make_converter(self):
- self.converter = \
- subunit.test_results.ExtendedToOriginalDecorator(self.result)
-
- def make_extended_result(self):
- self.result = ExtendedTestResult()
- self.make_converter()
-
- def check_outcome_details(self, outcome):
- """Call an outcome with a details dict to be passed through."""
- # This dict is /not/ convertible - thats deliberate, as it should
- # not hit the conversion code path.
- details = {'foo': 'bar'}
- getattr(self.converter, outcome)(self, details=details)
- self.assertEqual([(outcome, self, details)], self.result._calls)
-
- def get_details_and_string(self):
- """Get a details dict and expected string."""
- text1 = lambda:["1\n2\n"]
- text2 = lambda:["3\n4\n"]
- bin1 = lambda:["5\n"]
- details = {'text 1': Content(ContentType('text', 'plain'), text1),
- 'text 2': Content(ContentType('text', 'strange'), text2),
- 'bin 1': Content(ContentType('application', 'binary'), bin1)}
- return (details, "Binary content: bin 1\n"
- "Text attachment: text 1\n------------\n1\n2\n"
- "------------\nText attachment: text 2\n------------\n"
- "3\n4\n------------\n")
-
- def check_outcome_details_to_exec_info(self, outcome, expected=None):
- """Call an outcome with a details dict to be made into exc_info."""
- # The conversion is a done using RemoteError and the string contents
- # of the text types in the details dict.
- if not expected:
- expected = outcome
- details, err_str = self.get_details_and_string()
- getattr(self.converter, outcome)(self, details=details)
- err = subunit.RemoteError(err_str)
- self.assertEqual([(expected, self, err)], self.result._calls)
-
- def check_outcome_details_to_nothing(self, outcome, expected=None):
- """Call an outcome with a details dict to be swallowed."""
- if not expected:
- expected = outcome
- details = {'foo': 'bar'}
- getattr(self.converter, outcome)(self, details=details)
- self.assertEqual([(expected, self)], self.result._calls)
-
- def check_outcome_details_to_string(self, outcome):
- """Call an outcome with a details dict to be stringified."""
- details, err_str = self.get_details_and_string()
- getattr(self.converter, outcome)(self, details=details)
- self.assertEqual([(outcome, self, err_str)], self.result._calls)
-
- def check_outcome_exc_info(self, outcome, expected=None):
- """Check that calling a legacy outcome still works."""
- # calling some outcome with the legacy exc_info style api (no keyword
- # parameters) gets passed through.
- if not expected:
- expected = outcome
- err = subunit.RemoteError("foo\nbar\n")
- getattr(self.converter, outcome)(self, err)
- self.assertEqual([(expected, self, err)], self.result._calls)
-
- def check_outcome_exc_info_to_nothing(self, outcome, expected=None):
- """Check that calling a legacy outcome on a fallback works."""
- # calling some outcome with the legacy exc_info style api (no keyword
- # parameters) gets passed through.
- if not expected:
- expected = outcome
- err = subunit.RemoteError("foo\nbar\n")
- getattr(self.converter, outcome)(self, err)
- self.assertEqual([(expected, self)], self.result._calls)
-
- def check_outcome_nothing(self, outcome, expected=None):
- """Check that calling a legacy outcome still works."""
- if not expected:
- expected = outcome
- getattr(self.converter, outcome)(self)
- self.assertEqual([(expected, self)], self.result._calls)
-
- def check_outcome_string_nothing(self, outcome, expected):
- """Check that calling outcome with a string calls expected."""
- getattr(self.converter, outcome)(self, "foo")
- self.assertEqual([(expected, self)], self.result._calls)
-
- def check_outcome_string(self, outcome):
- """Check that calling outcome with a string works."""
- getattr(self.converter, outcome)(self, "foo")
- self.assertEqual([(outcome, self, "foo")], self.result._calls)
-
-
-class TestExtendedToOriginalResultDecorator(
- TestExtendedToOriginalResultDecoratorBase):
-
- def test_progress_py26(self):
- self.make_26_result()
- self.converter.progress(1, 2)
-
- def test_progress_py27(self):
- self.make_27_result()
- self.converter.progress(1, 2)
-
- def test_progress_pyextended(self):
- self.make_extended_result()
- 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)
- self.assertEqual([('startTest', self)], self.result._calls)
-
- def test_startTest_py27(self):
- self.make_27_result()
- self.converter.startTest(self)
- self.assertEqual([('startTest', self)], self.result._calls)
-
- def test_startTest_pyextended(self):
- self.make_extended_result()
- self.converter.startTest(self)
- self.assertEqual([('startTest', self)], self.result._calls)
-
- def test_startTestRun_py26(self):
- self.make_26_result()
- self.converter.startTestRun()
- self.assertEqual([], self.result._calls)
-
- def test_startTestRun_py27(self):
- self.make_27_result()
- self.converter.startTestRun()
- self.assertEqual([('startTestRun',)], self.result._calls)
-
- def test_startTestRun_pyextended(self):
- self.make_extended_result()
- self.converter.startTestRun()
- self.assertEqual([('startTestRun',)], self.result._calls)
-
- def test_stopTest_py26(self):
- self.make_26_result()
- self.converter.stopTest(self)
- self.assertEqual([('stopTest', self)], self.result._calls)
-
- def test_stopTest_py27(self):
- self.make_27_result()
- self.converter.stopTest(self)
- self.assertEqual([('stopTest', self)], self.result._calls)
-
- def test_stopTest_pyextended(self):
- self.make_extended_result()
- self.converter.stopTest(self)
- self.assertEqual([('stopTest', self)], self.result._calls)
-
- def test_stopTestRun_py26(self):
- self.make_26_result()
- self.converter.stopTestRun()
- self.assertEqual([], self.result._calls)
-
- def test_stopTestRun_py27(self):
- self.make_27_result()
- self.converter.stopTestRun()
- self.assertEqual([('stopTestRun',)], self.result._calls)
-
- def test_stopTestRun_pyextended(self):
- self.make_extended_result()
- self.converter.stopTestRun()
- self.assertEqual([('stopTestRun',)], self.result._calls)
-
- def test_tags_py26(self):
- self.make_26_result()
- self.converter.tags(1, 2)
-
- def test_tags_py27(self):
- self.make_27_result()
- self.converter.tags(1, 2)
-
- def test_tags_pyextended(self):
- self.make_extended_result()
- self.converter.tags(1, 2)
- self.assertEqual([('tags', 1, 2)], self.result._calls)
-
- def test_time_py26(self):
- self.make_26_result()
- self.converter.time(1)
-
- def test_time_py27(self):
- self.make_27_result()
- self.converter.time(1)
-
- def test_time_pyextended(self):
- self.make_extended_result()
- self.converter.time(1)
- self.assertEqual([('time', 1)], self.result._calls)
-
-
-class TestExtendedToOriginalAddError(TestExtendedToOriginalResultDecoratorBase):
-
- outcome = 'addError'
-
- def test_outcome_Original_py26(self):
- self.make_26_result()
- self.check_outcome_exc_info(self.outcome)
-
- def test_outcome_Original_py27(self):
- self.make_27_result()
- self.check_outcome_exc_info(self.outcome)
-
- def test_outcome_Original_pyextended(self):
- self.make_extended_result()
- self.check_outcome_exc_info(self.outcome)
-
- def test_outcome_Extended_py26(self):
- self.make_26_result()
- self.check_outcome_details_to_exec_info(self.outcome)
-
- def test_outcome_Extended_py27(self):
- self.make_27_result()
- self.check_outcome_details_to_exec_info(self.outcome)
-
- def test_outcome_Extended_pyextended(self):
- self.make_extended_result()
- self.check_outcome_details(self.outcome)
-
- def test_outcome__no_details(self):
- self.make_extended_result()
- self.assertRaises(ValueError,
- getattr(self.converter, self.outcome), self)
-
-
-class TestExtendedToOriginalAddFailure(
- TestExtendedToOriginalAddError):
-
- outcome = 'addFailure'
-
-
-class TestExtendedToOriginalAddExpectedFailure(
- TestExtendedToOriginalAddError):
-
- outcome = 'addExpectedFailure'
-
- def test_outcome_Original_py26(self):
- self.make_26_result()
- self.check_outcome_exc_info_to_nothing(self.outcome, 'addSuccess')
-
- def test_outcome_Extended_py26(self):
- self.make_26_result()
- self.check_outcome_details_to_nothing(self.outcome, 'addSuccess')
-
-
-
-class TestExtendedToOriginalAddSkip(
- TestExtendedToOriginalResultDecoratorBase):
-
- outcome = 'addSkip'
-
- def test_outcome_Original_py26(self):
- self.make_26_result()
- self.check_outcome_string_nothing(self.outcome, 'addSuccess')
-
- def test_outcome_Original_py27(self):
- self.make_27_result()
- self.check_outcome_string(self.outcome)
-
- def test_outcome_Original_pyextended(self):
- self.make_extended_result()
- self.check_outcome_string(self.outcome)
-
- def test_outcome_Extended_py26(self):
- self.make_26_result()
- self.check_outcome_string_nothing(self.outcome, 'addSuccess')
-
- def test_outcome_Extended_py27(self):
- self.make_27_result()
- self.check_outcome_details_to_string(self.outcome)
-
- def test_outcome_Extended_pyextended(self):
- self.make_extended_result()
- self.check_outcome_details(self.outcome)
-
- def test_outcome__no_details(self):
- self.make_extended_result()
- self.assertRaises(ValueError,
- getattr(self.converter, self.outcome), self)
-
-
-class TestExtendedToOriginalAddSuccess(
- TestExtendedToOriginalResultDecoratorBase):
-
- outcome = 'addSuccess'
- expected = 'addSuccess'
-
- def test_outcome_Original_py26(self):
- self.make_26_result()
- self.check_outcome_nothing(self.outcome, self.expected)
-
- def test_outcome_Original_py27(self):
- self.make_27_result()
- self.check_outcome_nothing(self.outcome)
-
- def test_outcome_Original_pyextended(self):
- self.make_extended_result()
- self.check_outcome_nothing(self.outcome)
-
- def test_outcome_Extended_py26(self):
- self.make_26_result()
- self.check_outcome_details_to_nothing(self.outcome, self.expected)
-
- def test_outcome_Extended_py27(self):
- self.make_27_result()
- self.check_outcome_details_to_nothing(self.outcome)
-
- def test_outcome_Extended_pyextended(self):
- self.make_extended_result()
- self.check_outcome_details(self.outcome)
-
-
-class TestExtendedToOriginalAddUnexpectedSuccess(
- TestExtendedToOriginalAddSuccess):
-
- outcome = 'addUnexpectedSuccess'
-
-
class TestHookedTestResultDecorator(unittest.TestCase):
def setUp(self):