← Back to team overview

testtools-dev team mailing list archive

[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