testtools-dev team mailing list archive
-
testtools-dev team
-
Mailing list archive
-
Message #00690
[Merge] lp:~jml/testtools/assert-is-none-tweaks into lp:testtools
Jonathan Lange has proposed merging lp:~jml/testtools/assert-is-none-tweaks into lp:testtools.
Requested reviews:
testtools developers (testtools-dev)
For more details, see:
https://code.launchpad.net/~jml/testtools/assert-is-none-tweaks/+merge/65186
Tweaks to ``Annotate`` and the implementation of the built-in assertions, along with some flakes cleanup.
--
https://code.launchpad.net/~jml/testtools/assert-is-none-tweaks/+merge/65186
Your team testtools developers is requested to review the proposed merge of lp:~jml/testtools/assert-is-none-tweaks into lp:testtools.
=== modified file 'NEWS'
--- NEWS 2011-06-12 00:58:39 +0000
+++ NEWS 2011-06-20 11:59:26 +0000
@@ -4,6 +4,13 @@
NEXT
~~~~
+Improvements
+------------
+
+* New convenience assertions, ``assertIsNone`` and ``assertIsNotNone``.
+ (Christian Kampka)
+
+
0.9.11
~~~~~~
@@ -12,7 +19,7 @@
outputs and a compat helper for testing libraries that deal with bytestrings.
Changes
-~~~~~~~
+-------
* ``TestCase`` now uses super to call base ``unittest.TestCase`` constructor,
``setUp`` and ``tearDown``. (Tim Cole, #771508)
@@ -22,7 +29,7 @@
Improvements
-~~~~~~~~~~~~
+------------
* Additional compat helper for ``BytesIO`` for libraries that build on
testtools and are working on Python 3 porting. (Robert Collins)
=== modified file 'testtools/matchers.py'
--- testtools/matchers.py 2011-04-20 23:45:52 +0000
+++ testtools/matchers.py 2011-06-20 11:59:26 +0000
@@ -496,6 +496,13 @@
self.annotation = annotation
self.matcher = matcher
+ @classmethod
+ def if_message(cls, annotation, matcher):
+ """Annotate ``matcher`` only if ``annotation`` is non-empty."""
+ if not annotation:
+ return matcher
+ return cls(annotation, matcher)
+
def __str__(self):
return 'Annotate(%r, %s)' % (self.annotation, self.matcher)
=== modified file 'testtools/testcase.py'
--- testtools/testcase.py 2011-05-27 17:00:32 +0000
+++ testtools/testcase.py 2011-06-20 11:59:26 +0000
@@ -29,6 +29,8 @@
from testtools.matchers import (
Annotate,
Equals,
+ Is,
+ Not,
)
from testtools.monkey import patch
from testtools.runtest import RunTest
@@ -304,18 +306,35 @@
:param observed: The observed value.
:param message: An optional message to include in the error.
"""
- matcher = Equals(expected)
- if message:
- matcher = Annotate(message, matcher)
+ matcher = Annotate.if_message(message, Equals(expected))
self.assertThat(observed, matcher)
failUnlessEqual = assertEquals = assertEqual
def assertIn(self, needle, haystack):
"""Assert that needle is in haystack."""
+ # XXX: Re-implement with matchers.
if needle not in haystack:
self.fail('%r not in %r' % (needle, haystack))
+ def assertIsNone(self, observed, message=''):
+ """Assert that 'observed' is equal to None.
+
+ :param observed: The observed value.
+ :param message: An optional message describing the error.
+ """
+ matcher = Annotate.if_message(message, Is(None))
+ self.assertThat(observed, matcher)
+
+ def assertIsNotNone(self, observed, message=''):
+ """Assert that 'observed' is not equal to None.
+
+ :param observed: The observed value.
+ :param message: An optional message describing the error.
+ """
+ matcher = Annotate.if_message(message, Not(Is(None)))
+ self.assertThat(observed, matcher)
+
def assertIs(self, expected, observed, message=''):
"""Assert that 'expected' is 'observed'.
@@ -323,6 +342,7 @@
:param observed: The observed value.
:param message: An optional message describing the error.
"""
+ # XXX: Re-implement with matchers.
if message:
message = ': ' + message
if expected is not observed:
@@ -330,6 +350,7 @@
def assertIsNot(self, expected, observed, message=''):
"""Assert that 'expected' is not 'observed'."""
+ # XXX: Re-implement with matchers.
if message:
message = ': ' + message
if expected is observed:
@@ -337,10 +358,12 @@
def assertNotIn(self, needle, haystack):
"""Assert that needle is not in haystack."""
+ # XXX: Re-implement with matchers.
if needle in haystack:
self.fail('%r in %r' % (needle, haystack))
def assertIsInstance(self, obj, klass, msg=None):
+ # XXX: Re-implement with matchers.
if msg is None:
msg = '%r is not an instance of %s' % (
obj, self._formatTypes(klass))
@@ -355,6 +378,7 @@
deemed to have suffered an error, exactly as for an
unexpected exception.
"""
+ # XXX: Re-implement with matchers.
try:
ret = callableObj(*args, **kwargs)
except excClass:
@@ -371,6 +395,8 @@
:param matcher: An object meeting the testtools.Matcher protocol.
:raises self.failureException: When matcher does not match thing.
"""
+ # XXX: Should this take an optional 'message' parameter? Would kind of
+ # make sense.
mismatch = matcher.match(matchee)
if not mismatch:
return
=== modified file 'testtools/tests/test_matchers.py'
--- testtools/tests/test_matchers.py 2011-04-20 23:45:52 +0000
+++ testtools/tests/test_matchers.py 2011-06-20 11:59:26 +0000
@@ -336,6 +336,23 @@
describe_examples = [("1 != 2: foo", 2, Annotate('foo', Equals(1)))]
+ def test_if_message_no_message(self):
+ # Annotate.if_message returns the given matcher if there is no
+ # message.
+ matcher = Equals(1)
+ not_annotated = Annotate.if_message('', matcher)
+ self.assertIs(matcher, not_annotated)
+
+ def test_if_message_given_message(self):
+ # Annotate.if_message returns an annotated version of the matcher if a
+ # message is provided.
+ matcher = Equals(1)
+ expected = Annotate('foo', matcher)
+ annotated = Annotate.if_message('foo', matcher)
+ self.assertThat(
+ annotated,
+ MatchesStructure.fromExample(expected, 'annotation', 'matcher'))
+
class TestAnnotatedMismatch(TestCase):
=== modified file 'testtools/tests/test_testtools.py'
--- testtools/tests/test_testtools.py 2011-05-12 23:01:56 +0000
+++ testtools/tests/test_testtools.py 2011-06-20 11:59:26 +0000
@@ -1,11 +1,9 @@
-# Copyright (c) 2008-2010 testtools developers. See LICENSE for details.
+# Copyright (c) 2008-2011 testtools developers. See LICENSE for details.
"""Tests for extensions to the base test library."""
from pprint import pformat
-import os
import sys
-import tempfile
import unittest
from testtools import (
@@ -501,6 +499,29 @@
self.assertFails(expected_error, self.assertEquals, a, b)
self.assertFails(expected_error, self.failUnlessEqual, a, b)
+ def test_assertIsNone(self):
+ self.assertIsNone(None)
+
+ expected_error = '\n'.join([
+ 'Match failed. Matchee: "0"',
+ 'Matcher: Is(None)',
+ 'Difference: None is not 0',
+ ''
+ ])
+ self.assertFails(expected_error, self.assertIsNone, 0)
+
+ def test_assertIsNotNone(self):
+ self.assertIsNotNone(0)
+ self.assertIsNotNone("0")
+
+ expected_error = '\n'.join([
+ 'Match failed. Matchee: "None"',
+ 'Matcher: Not(Is(None))',
+ 'Difference: None matches Is(None)',
+ ''
+ ])
+ self.assertFails(expected_error, self.assertIsNotNone, None)
+
class TestAddCleanup(TestCase):
"""Tests for TestCase.addCleanup."""
Follow ups