1
0
mirror of https://github.com/samba-team/samba.git synced 2025-01-11 05:18:09 +03:00

subunit/testtools: Include newer version.

This commit is contained in:
Jelmer Vernooij 2010-01-16 19:56:21 +13:00
parent 28577aae92
commit 2ec5792a4b
11 changed files with 206 additions and 23 deletions

View File

@ -213,10 +213,10 @@ class _ParserState(object):
def lineReceived(self, line):
"""a line has been received."""
parts = line.split(None, 1)
if len(parts) == 2:
if len(parts) == 2 and line.startswith(parts[0]):
cmd, rest = parts
offset = len(cmd) + 1
cmd = cmd.strip(':')
cmd = cmd.rstrip(':')
if cmd in ('test', 'testing'):
self.startTest(offset, line)
elif cmd == 'error':
@ -1111,3 +1111,16 @@ class TestResultStats(unittest.TestResult):
def wasSuccessful(self):
"""Tells whether or not this result was a success"""
return self.failed_tests == 0
def get_default_formatter():
"""Obtain the default formatter to write to.
:return: A file-like object.
"""
formatter = os.getenv("SUBUNIT_FORMATTER")
if formatter:
return os.popen(formatter, "w")
else:
return sys.stdout

View File

@ -22,7 +22,7 @@
import sys
from subunit import TestProtocolClient
from subunit import TestProtocolClient, get_default_formatter
class SubunitTestRunner(object):
@ -41,6 +41,7 @@ if __name__ == '__main__':
from unittest import TestProgram
parser = optparse.OptionParser(__doc__)
args = parser.parse_args()[1]
runner = SubunitTestRunner()
stream = get_default_formatter()
runner = SubunitTestRunner(stream)
program = TestProgram(module=None, argv=[sys.argv[0]] + args,
testRunner=runner)

View File

@ -124,6 +124,10 @@ class TestTestProtocolServerStartTest(unittest.TestCase):
self.assertEqual(self.client._events,
[('startTest', subunit.RemotedTestCase("old mcdonald"))])
def test_indented_test_colon_ignored(self):
self.protocol.lineReceived(" test: old mcdonald\n")
self.assertEqual([], self.client._events)
def test_start_testing_colon(self):
self.protocol.lineReceived("testing: old mcdonald\n")
self.assertEqual(self.client._events,

View File

@ -44,7 +44,7 @@ class Content(object):
no charset parameter is present in the MIME type. (This is somewhat
arbitrary, but consistent with RFC2617 3.7.1).
:raises: ValueError If the content type is not text/*.
:raises ValueError: If the content type is not text/\*.
"""
if self.content_type.type != "text":
raise ValueError("Not a text type %r" % self.content_type)

View File

@ -9,7 +9,7 @@ class ContentType(object):
: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.
content type.
"""
def __init__(self, primary_type, sub_type, parameters=None):

View File

@ -14,7 +14,10 @@ __metaclass__ = type
__all__ = [
'DocTestMatches',
'Equals',
'MatchesAll',
'MatchesAny',
'NotEquals',
'Not',
]
import doctest
@ -135,6 +138,36 @@ class EqualsMismatch:
return "%r != %r" % (self.expected, self.other)
class NotEquals:
"""Matches if the items are not equal.
In most cases, this is equivalent to `Not(Equals(foo))`. The difference
only matters when testing `__ne__` implementations.
"""
def __init__(self, expected):
self.expected = expected
def __str__(self):
return 'NotEquals(%r)' % (self.expected,)
def match(self, other):
if self.expected != other:
return None
return NotEqualsMismatch(self.expected, other)
class NotEqualsMismatch:
"""Two things are the same."""
def __init__(self, expected, other):
self.expected = expected
self.other = other
def describe(self):
return '%r == %r' % (self.expected, self.other)
class MatchesAny:
"""Matches if any of the matchers it is created with match."""
@ -155,6 +188,27 @@ class MatchesAny:
str(matcher) for matcher in self.matchers])
class MatchesAll:
"""Matches if all of the matchers it is created with match."""
def __init__(self, *matchers):
self.matchers = matchers
def __str__(self):
return 'MatchesAll(%s)' % ', '.join(map(str, self.matchers))
def match(self, matchee):
results = []
for matcher in self.matchers:
mismatch = matcher.match(matchee)
if mismatch is not None:
results.append(mismatch)
if results:
return MismatchesAll(results)
else:
return None
class MismatchesAll:
"""A mismatch with many child mismatches."""
@ -167,3 +221,31 @@ class MismatchesAll:
descriptions.append(mismatch.describe())
descriptions.append("]\n")
return '\n'.join(descriptions)
class Not:
"""Inverts a matcher."""
def __init__(self, matcher):
self.matcher = matcher
def __str__(self):
return 'Not(%s)' % (self.matcher,)
def match(self, other):
mismatch = self.matcher.match(other)
if mismatch is None:
return MatchedUnexpectedly(self.matcher, other)
else:
return None
class MatchedUnexpectedly:
"""A thing matched when it wasn't supposed to."""
def __init__(self, matcher, other):
self.matcher = matcher
self.other = other
def describe(self):
return "%r matches %s" % (self.other, self.matcher)

View File

@ -203,15 +203,26 @@ class TestCase(unittest.TestCase):
self.assertTrue(
needle in haystack, '%r not in %r' % (needle, haystack))
def assertIs(self, expected, observed):
"""Assert that `expected` is `observed`."""
self.assertTrue(
expected is observed, '%r is not %r' % (expected, observed))
def assertIs(self, expected, observed, message=''):
"""Assert that 'expected' is 'observed'.
def assertIsNot(self, expected, observed):
"""Assert that `expected` is not `observed`."""
:param expected: The expected value.
:param observed: The observed value.
:param message: An optional message describing the error.
"""
if message:
message = ': ' + message
self.assertTrue(
expected is not observed, '%r is %r' % (expected, observed))
expected is observed,
'%r is not %r%s' % (expected, observed, message))
def assertIsNot(self, expected, observed, message=''):
"""Assert that 'expected' is not 'observed'."""
if message:
message = ': ' + message
self.assertTrue(
expected is not observed,
'%r is %r%s' % (expected, observed, message))
def assertNotIn(self, needle, haystack):
"""Assert that needle is not in haystack."""
@ -358,7 +369,11 @@ class TestCase(unittest.TestCase):
"""
self.setUp()
if not self.__setup_called:
raise ValueError("setUp was not called")
raise ValueError(
"TestCase.setUp was not called. Have you upcalled all the "
"way up the hierarchy from your setUp? e.g. Call "
"super(%s, self).setUp() from your setUp()."
% self.__class__.__name__)
def _run_teardown(self, result):
"""Run the tearDown function for this test.
@ -369,7 +384,11 @@ class TestCase(unittest.TestCase):
"""
self.tearDown()
if not self.__teardown_called:
raise ValueError("teardown was not called")
raise ValueError(
"TestCase.tearDown was not called. Have you upcalled all the "
"way up the hierarchy from your tearDown? e.g. Call "
"super(%s, self).tearDown() from your tearDown()."
% self.__class__.__name__)
def _run_test_method(self, result):
"""Run the test method for this test.
@ -395,14 +414,19 @@ class TestCase(unittest.TestCase):
self.__teardown_called = True
# Python 2.4 did not know how to deep copy functions.
if types.FunctionType not in copy._deepcopy_dispatch:
copy._deepcopy_dispatch[types.FunctionType] = copy._deepcopy_atomic
# Python 2.4 did not know how to copy functions.
if types.FunctionType not in copy._copy_dispatch:
copy._copy_dispatch[types.FunctionType] = copy._copy_immutable
def clone_test_with_new_id(test, new_id):
"""Copy a TestCase, and give the copied test a new id."""
newTest = copy.deepcopy(test)
"""Copy a TestCase, and give the copied test a new id.
This is only expected to be used on tests that have been constructed but
not executed.
"""
newTest = copy.copy(test)
newTest.id = lambda: new_id
return newTest

View File

@ -1,3 +1,5 @@
"""Tests for testtools itself."""
# See README for copyright and licensing details.
import unittest

View File

@ -12,6 +12,9 @@ from testtools.matchers import (
Equals,
DocTestMatches,
MatchesAny,
MatchesAll,
Not,
NotEquals,
)
@ -81,6 +84,31 @@ class TestEqualsInterface(TestCase, TestMatchersInterface):
describe_examples = [("1 != 2", 2, Equals(1))]
class TestNotEqualsInterface(TestCase, TestMatchersInterface):
matches_matcher = NotEquals(1)
matches_matches = [2]
matches_mismatches = [1]
str_examples = [
("NotEquals(1)", NotEquals(1)), ("NotEquals('1')", NotEquals('1'))]
describe_examples = [("1 == 1", 1, NotEquals(1))]
class TestNotInterface(TestCase, TestMatchersInterface):
matches_matcher = Not(Equals(1))
matches_matches = [2]
matches_mismatches = [1]
str_examples = [
("Not(Equals(1))", Not(Equals(1))),
("Not(Equals('1'))", Not(Equals('1')))]
describe_examples = [('1 matches Equals(1)', 1, Not(Equals(1)))]
class TestMatchersAnyInterface(TestCase, TestMatchersInterface):
matches_matcher = MatchesAny(DocTestMatches("1"), DocTestMatches("2"))
@ -108,6 +136,23 @@ Got:
"3", MatchesAny(DocTestMatches("1"), DocTestMatches("2")))]
class TestMatchesAllInterface(TestCase, TestMatchersInterface):
matches_matcher = MatchesAll(NotEquals(1), NotEquals(2))
matches_matches = [3, 4]
matches_mismatches = [1, 2]
str_examples = [
("MatchesAll(NotEquals(1), NotEquals(2))",
MatchesAll(NotEquals(1), NotEquals(2)))]
describe_examples = [("""Differences: [
1 == 1
]
""",
1, MatchesAll(NotEquals(1), NotEquals(2)))]
def test_suite():
from unittest import TestLoader
return TestLoader().loadTestsFromName(__name__)

View File

@ -223,6 +223,12 @@ class TestAssertions(TestCase):
self.assertFails('None is not 42', self.assertIs, None, 42)
self.assertFails('[42] is not [42]', self.assertIs, [42], [42])
def test_assertIs_fails_with_message(self):
# assertIs raises assertion errors if one object is not identical to
# another, and includes a user-supplied message, if it's provided.
self.assertFails(
'None is not 42: foo bar', self.assertIs, None, 42, 'foo bar')
def test_assertIsNot(self):
# assertIsNot asserts that an object is not identical to another
# object.
@ -238,6 +244,12 @@ class TestAssertions(TestCase):
self.assertFails(
'[42] is [42]', self.assertIsNot, some_list, some_list)
def test_assertIsNot_fails_with_message(self):
# assertIsNot raises assertion errors if one object is identical to
# another, and includes a user-supplied message if it's provided.
self.assertFails(
'None is None: foo bar', self.assertIsNot, None, None, "foo bar")
def test_assertThat_matches_clean(self):
class Matcher:
def match(self, foo):
@ -303,12 +315,12 @@ class TestAddCleanup(TestCase):
self.assertEqual(messages, [call[0] for call in self._result_calls])
def assertTestLogEqual(self, messages):
"""Assert that the call log equals `messages`."""
"""Assert that the call log equals 'messages'."""
case = self._result_calls[0][1]
self.assertEqual(messages, case._calls)
def logAppender(self, message):
"""A cleanup that appends `message` to the tests log.
"""A cleanup that appends 'message' to the tests log.
Cleanups are callables that are added to a test by addCleanup. To
verify that our cleanups run in the right order, we add strings to a

View File

@ -28,7 +28,7 @@ else:
def iterate_tests(test_suite_or_case):
"""Iterate through all of the test cases in `test_suite_or_case`."""
"""Iterate through all of the test cases in 'test_suite_or_case'."""
try:
suite = iter(test_suite_or_case)
except TypeError: