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:
parent
28577aae92
commit
2ec5792a4b
@ -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
|
||||
|
||||
|
@ -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)
|
||||
|
@ -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,
|
||||
|
@ -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)
|
||||
|
@ -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):
|
||||
|
@ -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)
|
||||
|
@ -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
|
||||
|
||||
|
@ -1,3 +1,5 @@
|
||||
"""Tests for testtools itself."""
|
||||
|
||||
# See README for copyright and licensing details.
|
||||
|
||||
import unittest
|
||||
|
@ -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__)
|
||||
|
@ -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
|
||||
|
@ -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:
|
||||
|
Loading…
Reference in New Issue
Block a user