summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJonathan Lange <jml@mumak.net>2015-12-23 09:42:25 +0000
committerJonathan Lange <jml@mumak.net>2015-12-23 09:42:25 +0000
commit476ff2d0df1118a3c4571d5e80ab95a7884ec98a (patch)
treebc8aeb4679e6970838066781fffb5a99300ae13b
parent7015ae5def59e6756abdb05d43c5b8f521c3f6e4 (diff)
parent4febe2e751454131515ef5eed94fcd958c4fbfb1 (diff)
downloadtesttools-476ff2d0df1118a3c4571d5e80ab95a7884ec98a.tar.gz
Merge branch 'master' into assert_raises_regexp
-rw-r--r--.travis.yml1
-rw-r--r--NEWS15
-rw-r--r--README.rst2
-rw-r--r--doc/overview.rst2
-rw-r--r--testtools/matchers/_basic.py69
-rw-r--r--testtools/matchers/_datastructures.py4
-rw-r--r--testtools/testcase.py3
-rw-r--r--testtools/tests/matchers/test_basic.py69
-rw-r--r--testtools/tests/matchers/test_datastructures.py10
-rw-r--r--testtools/tests/matchers/test_dict.py12
-rw-r--r--testtools/tests/matchers/test_exception.py2
-rw-r--r--testtools/tests/matchers/test_higherorder.py17
-rw-r--r--testtools/tests/test_testcase.py6
13 files changed, 151 insertions, 61 deletions
diff --git a/.travis.yml b/.travis.yml
index 5535154..f7d8a97 100644
--- a/.travis.yml
+++ b/.travis.yml
@@ -5,6 +5,7 @@ python:
- "2.7"
- "3.3"
- "3.4"
+ - "3.5"
- "pypy"
# We have to pin Jinja2 < 2.7 for Python 3.2 because 2.7 drops/breaks support:
diff --git a/NEWS b/NEWS
index fdf8aa4..fa9a03d 100644
--- a/NEWS
+++ b/NEWS
@@ -9,14 +9,27 @@ Next
Improvements
------------
+* Python 3.5 added to the list of supported platforms. (Jonathan Lange)
+
* ``MatchesListwise`` has more informative error when lengths don't match.
(Jonathan Lange)
+* The short form of errors for failed binary comparisions will now put the
+ expected value on the _right_. This means that ``assertThat(2, Equals(3))``
+ will raise an error saying ``2 != 3``.
+ (Jonathan Lange, #1525227)
+
Changes
-------
* Add a new test dependency of testscenarios. (Robert Collins)
-
+
+* Getting ``expected`` or ``observed`` attributes from binary comparison
+ mismatches (e.g. ``Equals(2).match(3).expected``) is now deprecated.
+ (Jonathan Lange)
+
+* Last release of testtools to support Python 3.2. (Jonathan Lange)
+
1.8.1
~~~~~
diff --git a/README.rst b/README.rst
index 9cff307..d2ff7e0 100644
--- a/README.rst
+++ b/README.rst
@@ -31,7 +31,7 @@ under the same license as Python, see LICENSE for details.
Required Dependencies
---------------------
- * Python 2.6+ or 3.0+ / pypy (2.x+)
+ * Python 2.6+ or 3.2+ / pypy (2.x+)
If you would like to use testtools for earlier Python's, please use testtools
0.9.15.
diff --git a/doc/overview.rst b/doc/overview.rst
index bf62a8e..c22967b 100644
--- a/doc/overview.rst
+++ b/doc/overview.rst
@@ -93,7 +93,7 @@ Cross-Python compatibility
--------------------------
testtools gives you the very latest in unit testing technology in a way that
-will work with Python 2.6, 2.7, 3.1 and 3.2.
+will work with Python 2.6, 2.7, 3.2, 3.3, 3.4, and 3.5.
If you wish to use testtools with Python 2.4 or 2.5, then please use testtools
0.9.15. Up to then we supported Python 2.4 and 2.5, but we found the
diff --git a/testtools/matchers/_basic.py b/testtools/matchers/_basic.py
index 2d9f143..e9eeaee 100644
--- a/testtools/matchers/_basic.py
+++ b/testtools/matchers/_basic.py
@@ -17,6 +17,7 @@ __all__ = [
import operator
from pprint import pformat
import re
+import warnings
from ..compat import (
_isbytes,
@@ -57,7 +58,7 @@ class _BinaryComparison(object):
def match(self, other):
if self.comparator(other, self.expected):
return None
- return _BinaryMismatch(self.expected, self.mismatch_string, other)
+ return _BinaryMismatch(other, self.mismatch_string, self.expected)
def comparator(self, expected, other):
raise NotImplementedError(self.comparator)
@@ -66,19 +67,43 @@ class _BinaryComparison(object):
class _BinaryMismatch(Mismatch):
"""Two things did not match."""
- def __init__(self, expected, mismatch_string, other):
- self.expected = expected
+ def __init__(self, actual, mismatch_string, reference,
+ reference_on_right=True):
+ self._actual = actual
self._mismatch_string = mismatch_string
- self.other = other
+ self._reference = reference
+ self._reference_on_right = reference_on_right
+
+ @property
+ def expected(self):
+ warnings.warn(
+ '%s.expected deprecated after 1.8.1' % (self.__class__.__name__,),
+ DeprecationWarning,
+ stacklevel=2,
+ )
+ return self._reference
+
+ @property
+ def other(self):
+ warnings.warn(
+ '%s.other deprecated after 1.8.1' % (self.__class__.__name__,),
+ DeprecationWarning,
+ stacklevel=2,
+ )
+ return self._actual
def describe(self):
- left = repr(self.expected)
- right = repr(self.other)
- if len(left) + len(right) > 70:
+ actual = repr(self._actual)
+ reference = repr(self._reference)
+ if len(actual) + len(reference) > 70:
return "%s:\nreference = %s\nactual = %s\n" % (
- self._mismatch_string, _format(self.expected),
- _format(self.other))
+ self._mismatch_string, _format(self._reference),
+ _format(self._actual))
else:
+ if self._reference_on_right:
+ left, right = actual, reference
+ else:
+ left, right = reference, actual
return "%s %s %s" % (left, self._mismatch_string, right)
@@ -89,6 +114,26 @@ class Equals(_BinaryComparison):
mismatch_string = '!='
+class _FlippedEquals(object):
+ """Matches if the items are equal.
+
+ Exactly like ``Equals`` except that the short mismatch message is "
+ $reference != $actual" rather than "$actual != $reference". This allows
+ for ``TestCase.assertEqual`` to use a matcher but still have the order of
+ items in the error message align with the order of items in the call to
+ the assertion.
+ """
+
+ def __init__(self, expected):
+ self._expected = expected
+
+ def match(self, other):
+ mismatch = Equals(self._expected).match(other)
+ if not mismatch:
+ return None
+ return _BinaryMismatch(other, '!=', self._expected, False)
+
+
class NotEquals(_BinaryComparison):
"""Matches if the items are not equal.
@@ -111,14 +156,14 @@ class LessThan(_BinaryComparison):
"""Matches if the item is less than the matchers reference object."""
comparator = operator.__lt__
- mismatch_string = 'is not >'
+ mismatch_string = '>='
class GreaterThan(_BinaryComparison):
"""Matches if the item is greater than the matchers reference object."""
comparator = operator.__gt__
- mismatch_string = 'is not <'
+ mismatch_string = '<='
class SameMembers(Matcher):
@@ -143,7 +188,7 @@ class SameMembers(Matcher):
return PostfixedMismatch(
"\nmissing: %s\nextra: %s" % (
_format(expected_only), _format(observed_only)),
- _BinaryMismatch(self.expected, 'elements differ', observed))
+ _BinaryMismatch(observed, 'elements differ', self.expected))
class DoesNotStartWith(Mismatch):
diff --git a/testtools/matchers/_datastructures.py b/testtools/matchers/_datastructures.py
index 67286b5..1e9e933 100644
--- a/testtools/matchers/_datastructures.py
+++ b/testtools/matchers/_datastructures.py
@@ -39,12 +39,12 @@ class MatchesListwise(object):
>>> MatchesListwise([Equals(1), Equals(2)]).match([1, 2])
>>> print (MatchesListwise([Equals(1), Equals(2)]).match([2, 1]).describe())
Differences: [
- 1 != 2
2 != 1
+ 1 != 2
]
>>> matcher = MatchesListwise([Equals(1), Equals(2)], first_only=True)
>>> print (matcher.match([3, 4]).describe())
- 1 != 3
+ 3 != 1
"""
def __init__(self, matchers, first_only=False):
diff --git a/testtools/testcase.py b/testtools/testcase.py
index afb9c6c..dfd9f06 100644
--- a/testtools/testcase.py
+++ b/testtools/testcase.py
@@ -48,6 +48,7 @@ from testtools.matchers import (
Not,
Raises,
)
+from testtools.matchers._basic import _FlippedEquals
from testtools.monkey import patch
from testtools.runtest import RunTest
from testtools.testresult import (
@@ -346,7 +347,7 @@ class TestCase(unittest.TestCase):
:param observed: The observed value.
:param message: An optional message to include in the error.
"""
- matcher = Equals(expected)
+ matcher = _FlippedEquals(expected)
self.assertThat(observed, matcher, message)
failUnlessEqual = assertEquals = assertEqual
diff --git a/testtools/tests/matchers/test_basic.py b/testtools/tests/matchers/test_basic.py
index c53bc9e..519cdd8 100644
--- a/testtools/tests/matchers/test_basic.py
+++ b/testtools/tests/matchers/test_basic.py
@@ -55,41 +55,61 @@ class Test_BinaryMismatch(TestCase):
def test_long_bytes(self):
one_line_b = self._long_b.replace(_b("\n"), _b(" "))
mismatch = _BinaryMismatch(one_line_b, "!~", self._long_b)
- self.assertEqual(mismatch.describe(),
- "%s:\nreference = %s\nactual = %s\n" % ("!~",
+ self.assertEqual(
+ mismatch.describe(),
+ "%s:\nreference = %s\nactual = %s\n" % (
+ "!~",
+ text_repr(self._long_b, multiline=True),
text_repr(one_line_b),
- text_repr(self._long_b, multiline=True)))
+ )
+ )
def test_long_unicode(self):
one_line_u = self._long_u.replace("\n", " ")
mismatch = _BinaryMismatch(one_line_u, "!~", self._long_u)
- self.assertEqual(mismatch.describe(),
- "%s:\nreference = %s\nactual = %s\n" % ("!~",
+ self.assertEqual(
+ mismatch.describe(),
+ "%s:\nreference = %s\nactual = %s\n" % (
+ "!~",
+ text_repr(self._long_u, multiline=True),
text_repr(one_line_u),
- text_repr(self._long_u, multiline=True)))
+ )
+ )
def test_long_mixed_strings(self):
mismatch = _BinaryMismatch(self._long_b, "!~", self._long_u)
- self.assertEqual(mismatch.describe(),
- "%s:\nreference = %s\nactual = %s\n" % ("!~",
+ self.assertEqual(
+ mismatch.describe(),
+ "%s:\nreference = %s\nactual = %s\n" % (
+ "!~",
+ text_repr(self._long_u, multiline=True),
text_repr(self._long_b, multiline=True),
- text_repr(self._long_u, multiline=True)))
+ )
+ )
def test_long_bytes_and_object(self):
obj = object()
mismatch = _BinaryMismatch(self._long_b, "!~", obj)
- self.assertEqual(mismatch.describe(),
- "%s:\nreference = %s\nactual = %s\n" % ("!~",
+ self.assertEqual(
+ mismatch.describe(),
+ "%s:\nreference = %s\nactual = %s\n" % (
+ "!~",
+ repr(obj),
text_repr(self._long_b, multiline=True),
- repr(obj)))
+ )
+ )
def test_long_unicode_and_object(self):
obj = object()
mismatch = _BinaryMismatch(self._long_u, "!~", obj)
- self.assertEqual(mismatch.describe(),
- "%s:\nreference = %s\nactual = %s\n" % ("!~",
+ self.assertEqual(
+ mismatch.describe(),
+ "%s:\nreference = %s\nactual = %s\n" % (
+ "!~",
+ repr(obj),
text_repr(self._long_u, multiline=True),
- repr(obj)))
+ )
+ )
class TestEqualsInterface(TestCase, TestMatchersInterface):
@@ -100,7 +120,14 @@ class TestEqualsInterface(TestCase, TestMatchersInterface):
str_examples = [("Equals(1)", Equals(1)), ("Equals('1')", Equals('1'))]
- describe_examples = [("1 != 2", 2, Equals(1))]
+ describe_examples = [
+ ("2 != 1", 2, Equals(1)),
+ (("!=:\n"
+ "reference = 'abcdefghijklmnopqrstuvwxyz0123456789'\n"
+ "actual = 'ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789'\n"),
+ 'ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789',
+ Equals('abcdefghijklmnopqrstuvwxyz0123456789')),
+ ]
class TestNotEqualsInterface(TestCase, TestMatchersInterface):
@@ -126,7 +153,7 @@ class TestIsInterface(TestCase, TestMatchersInterface):
str_examples = [("Is(2)", Is(2))]
- describe_examples = [("1 is not 2", 2, Is(1))]
+ describe_examples = [("2 is not 1", 2, Is(1))]
class TestIsInstanceInterface(TestCase, TestMatchersInterface):
@@ -160,8 +187,8 @@ class TestLessThanInterface(TestCase, TestMatchersInterface):
]
describe_examples = [
- ('4 is not > 5', 5, LessThan(4)),
- ('4 is not > 4', 4, LessThan(4)),
+ ('5 >= 4', 5, LessThan(4)),
+ ('4 >= 4', 4, LessThan(4)),
]
@@ -176,8 +203,8 @@ class TestGreaterThanInterface(TestCase, TestMatchersInterface):
]
describe_examples = [
- ('5 is not < 4', 4, GreaterThan(5)),
- ('4 is not < 4', 4, GreaterThan(4)),
+ ('4 <= 5', 4, GreaterThan(5)),
+ ('4 <= 4', 4, GreaterThan(4)),
]
diff --git a/testtools/tests/matchers/test_datastructures.py b/testtools/tests/matchers/test_datastructures.py
index f6d9d86..6a40399 100644
--- a/testtools/tests/matchers/test_datastructures.py
+++ b/testtools/tests/matchers/test_datastructures.py
@@ -37,6 +37,8 @@ class TestMatchesListwise(TestCase):
run_tests_with = FullStackRunTest
+ # XXX: Add interface tests.
+
def test_docstring(self):
failure_count, output = run_doctest(
MatchesListwise, "MatchesListwise")
@@ -69,16 +71,16 @@ class TestMatchesStructure(TestCase, TestMatchersInterface):
describe_examples = [
("""\
Differences: [
-3 != 1: x
+1 != 3: x
]""", SimpleClass(1, 2), MatchesStructure(x=Equals(3), y=Equals(2))),
("""\
Differences: [
-3 != 2: y
+2 != 3: y
]""", SimpleClass(1, 2), MatchesStructure(x=Equals(1), y=Equals(3))),
("""\
Differences: [
-0 != 1: x
-0 != 2: y
+1 != 0: x
+2 != 0: y
]""", SimpleClass(1, 2), MatchesStructure(x=Equals(0), y=Equals(0))),
]
diff --git a/testtools/tests/matchers/test_dict.py b/testtools/tests/matchers/test_dict.py
index 00368dd..a9d6429 100644
--- a/testtools/tests/matchers/test_dict.py
+++ b/testtools/tests/matchers/test_dict.py
@@ -102,7 +102,7 @@ class TestMatchesDict(TestCase, TestMatchersInterface):
str_examples = [
("MatchesDict({'baz': %s, 'foo': %s})" % (
- Not(Equals('qux')), Equals('bar')),
+ Not(Equals('qux')), Equals('bar')),
matches_matcher),
]
@@ -118,7 +118,7 @@ class TestMatchesDict(TestCase, TestMatchersInterface):
{'foo': 'bar', 'baz': 'qux'}, matches_matcher),
("Differences: {\n"
" 'baz': 'qux' matches Equals('qux'),\n"
- " 'foo': 'bar' != 'bop',\n"
+ " 'foo': 'bop' != 'bar',\n"
"}",
{'foo': 'bop', 'baz': 'qux'}, matches_matcher),
("Extra: {\n"
@@ -155,7 +155,7 @@ class TestContainsDict(TestCase, TestMatchersInterface):
str_examples = [
("ContainsDict({'baz': %s, 'foo': %s})" % (
- Not(Equals('qux')), Equals('bar')),
+ Not(Equals('qux')), Equals('bar')),
matches_matcher),
]
@@ -171,7 +171,7 @@ class TestContainsDict(TestCase, TestMatchersInterface):
{'foo': 'bar', 'baz': 'qux'}, matches_matcher),
("Differences: {\n"
" 'baz': 'qux' matches Equals('qux'),\n"
- " 'foo': 'bar' != 'bop',\n"
+ " 'foo': 'bop' != 'bar',\n"
"}",
{'foo': 'bop', 'baz': 'qux'}, matches_matcher),
("Missing: {\n"
@@ -201,7 +201,7 @@ class TestContainedByDict(TestCase, TestMatchersInterface):
str_examples = [
("ContainedByDict({'baz': %s, 'foo': %s})" % (
- Not(Equals('qux')), Equals('bar')),
+ Not(Equals('qux')), Equals('bar')),
matches_matcher),
]
@@ -212,7 +212,7 @@ class TestContainedByDict(TestCase, TestMatchersInterface):
{'foo': 'bar', 'baz': 'qux'}, matches_matcher),
("Differences: {\n"
" 'baz': 'qux' matches Equals('qux'),\n"
- " 'foo': 'bar' != 'bop',\n"
+ " 'foo': 'bop' != 'bar',\n"
"}",
{'foo': 'bop', 'baz': 'qux'}, matches_matcher),
("Extra: {\n"
diff --git a/testtools/tests/matchers/test_exception.py b/testtools/tests/matchers/test_exception.py
index a74043a..9ef36b8 100644
--- a/testtools/tests/matchers/test_exception.py
+++ b/testtools/tests/matchers/test_exception.py
@@ -100,7 +100,7 @@ class TestMatchesExceptionTypeMatcherInterface(TestCase, TestMatchersInterface):
MatchesException(Exception, Equals('foo')))
]
describe_examples = [
- ("5 != %r" % (error_bar[1],),
+ ("%r != 5" % (error_bar[1],),
error_bar, MatchesException(ValueError, Equals(5))),
]
diff --git a/testtools/tests/matchers/test_higherorder.py b/testtools/tests/matchers/test_higherorder.py
index fb86b7f..274fd4d 100644
--- a/testtools/tests/matchers/test_higherorder.py
+++ b/testtools/tests/matchers/test_higherorder.py
@@ -44,8 +44,8 @@ class TestAllMatch(TestCase, TestMatchersInterface):
describe_examples = [
('Differences: [\n'
- '10 is not > 11\n'
- '10 is not > 10\n'
+ '11 >= 10\n'
+ '10 >= 10\n'
']',
[11, 9, 10],
AllMatch(LessThan(10))),
@@ -75,9 +75,9 @@ class TestAnyMatch(TestCase, TestMatchersInterface):
describe_examples = [
('Differences: [\n'
- '7 != 11\n'
- '7 != 9\n'
- '7 != 10\n'
+ '11 != 7\n'
+ '9 != 7\n'
+ '10 != 7\n'
']',
[11, 9, 10],
AnyMatch(Equals(7))),
@@ -99,12 +99,13 @@ class TestAfterPreprocessing(TestCase, TestMatchersInterface):
]
describe_examples = [
- ("1 != 0: after <function parity> on 2", 2,
+ ("0 != 1: after <function parity> on 2", 2,
AfterPreprocessing(parity, Equals(1))),
- ("1 != 0", 2,
+ ("0 != 1", 2,
AfterPreprocessing(parity, Equals(1), annotate=False)),
]
+
class TestMatchersAnyInterface(TestCase, TestMatchersInterface):
matches_matcher = MatchesAny(DocTestMatches("1"), DocTestMatches("2"))
@@ -160,7 +161,7 @@ class TestAnnotate(TestCase, TestMatchersInterface):
str_examples = [
("Annotate('foo', Equals(1))", Annotate("foo", Equals(1)))]
- describe_examples = [("1 != 2: foo", 2, Annotate('foo', Equals(1)))]
+ describe_examples = [("2 != 1: foo", 2, Annotate('foo', Equals(1)))]
def test_if_message_no_message(self):
# Annotate.if_message returns the given matcher if there is no
diff --git a/testtools/tests/test_testcase.py b/testtools/tests/test_testcase.py
index 1ee9c5d..e7f62b5 100644
--- a/testtools/tests/test_testcase.py
+++ b/testtools/tests/test_testcase.py
@@ -515,14 +515,14 @@ class TestAssertions(TestCase):
def test_assertIs_fails(self):
# assertIs raises assertion errors if one object is not identical to
# another.
- self.assertFails('None is not 42', self.assertIs, None, 42)
+ self.assertFails('42 is not None', 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')
+ '42 is not None: foo bar', self.assertIs, None, 42, 'foo bar')
def test_assertIsNot(self):
# assertIsNot asserts that an object is not identical to another
@@ -732,7 +732,7 @@ class TestAssertions(TestCase):
def test_assertIsNone(self):
self.assertIsNone(None)
- expected_error = 'None is not 0'
+ expected_error = '0 is not None'
self.assertFails(expected_error, self.assertIsNone, 0)
def test_assertIsNotNone(self):