1 # Copyright (c) 2008-2011 testtools developers. See LICENSE for details.
3 """Tests for matchers."""
13 from testtools import (
14 Matcher, # check that Matcher is exposed at the top level for docs.
18 from testtools.compat import (
25 from testtools.matchers import (
67 from testtools.tests.helpers import FullStackRunTest
73 class TestMismatch(TestCase):
75 run_tests_with = FullStackRunTest
77 def test_constructor_arguments(self):
78 mismatch = Mismatch("some description", {'detail': "things"})
79 self.assertEqual("some description", mismatch.describe())
80 self.assertEqual({'detail': "things"}, mismatch.get_details())
82 def test_constructor_no_arguments(self):
84 self.assertThat(mismatch.describe,
85 Raises(MatchesException(NotImplementedError)))
86 self.assertEqual({}, mismatch.get_details())
89 class TestMismatchError(TestCase):
91 def test_is_assertion_error(self):
92 # MismatchError is an AssertionError, so that most of the time, it
93 # looks like a test failure, rather than an error.
94 def raise_mismatch_error():
95 raise MismatchError(2, Equals(3), Equals(3).match(2))
96 self.assertRaises(AssertionError, raise_mismatch_error)
98 def test_default_description_is_mismatch(self):
99 mismatch = Equals(3).match(2)
100 e = MismatchError(2, Equals(3), mismatch)
101 self.assertEqual(mismatch.describe(), str(e))
103 def test_default_description_unicode(self):
105 matcher = Equals(_u('a'))
106 mismatch = matcher.match(matchee)
107 e = MismatchError(matchee, matcher, mismatch)
108 self.assertEqual(mismatch.describe(), str(e))
110 def test_verbose_description(self):
113 mismatch = matcher.match(2)
114 e = MismatchError(matchee, matcher, mismatch, True)
116 'Match failed. Matchee: %r\n'
118 'Difference: %s\n' % (
121 matcher.match(matchee).describe(),
123 self.assertEqual(expected, str(e))
125 def test_verbose_unicode(self):
126 # When assertThat is given matchees or matchers that contain non-ASCII
127 # unicode strings, we can still provide a meaningful error.
129 matcher = Equals(_u('a'))
130 mismatch = matcher.match(matchee)
132 'Match failed. Matchee: %s\n'
134 'Difference: %s\n' % (
139 e = MismatchError(matchee, matcher, mismatch, True)
144 # Using str() should still work, and return ascii only
146 expected.replace(matchee, matchee.encode("unicode-escape")),
147 str(e).decode("ascii"))
148 self.assertEqual(expected, actual)
151 class Test_BinaryMismatch(TestCase):
152 """Mismatches from binary comparisons need useful describe output"""
154 _long_string = "This is a longish multiline non-ascii string\n\xa7"
155 _long_b = _b(_long_string)
156 _long_u = _u(_long_string)
158 def test_short_objects(self):
159 o1, o2 = object(), object()
160 mismatch = _BinaryMismatch(o1, "!~", o2)
161 self.assertEqual(mismatch.describe(), "%r !~ %r" % (o1, o2))
163 def test_short_mixed_strings(self):
164 b, u = _b("\xa7"), _u("\xa7")
165 mismatch = _BinaryMismatch(b, "!~", u)
166 self.assertEqual(mismatch.describe(), "%r !~ %r" % (b, u))
168 def test_long_bytes(self):
169 one_line_b = self._long_b.replace(_b("\n"), _b(" "))
170 mismatch = _BinaryMismatch(one_line_b, "!~", self._long_b)
171 self.assertEqual(mismatch.describe(),
172 "%s:\nreference = %s\nactual = %s\n" % ("!~",
173 text_repr(one_line_b),
174 text_repr(self._long_b, multiline=True)))
176 def test_long_unicode(self):
177 one_line_u = self._long_u.replace("\n", " ")
178 mismatch = _BinaryMismatch(one_line_u, "!~", self._long_u)
179 self.assertEqual(mismatch.describe(),
180 "%s:\nreference = %s\nactual = %s\n" % ("!~",
181 text_repr(one_line_u),
182 text_repr(self._long_u, multiline=True)))
184 def test_long_mixed_strings(self):
185 mismatch = _BinaryMismatch(self._long_b, "!~", self._long_u)
186 self.assertEqual(mismatch.describe(),
187 "%s:\nreference = %s\nactual = %s\n" % ("!~",
188 text_repr(self._long_b, multiline=True),
189 text_repr(self._long_u, multiline=True)))
191 def test_long_bytes_and_object(self):
193 mismatch = _BinaryMismatch(self._long_b, "!~", obj)
194 self.assertEqual(mismatch.describe(),
195 "%s:\nreference = %s\nactual = %s\n" % ("!~",
196 text_repr(self._long_b, multiline=True),
199 def test_long_unicode_and_object(self):
201 mismatch = _BinaryMismatch(self._long_u, "!~", obj)
202 self.assertEqual(mismatch.describe(),
203 "%s:\nreference = %s\nactual = %s\n" % ("!~",
204 text_repr(self._long_u, multiline=True),
208 class TestMatchersInterface(object):
210 run_tests_with = FullStackRunTest
212 def test_matches_match(self):
213 matcher = self.matches_matcher
214 matches = self.matches_matches
215 mismatches = self.matches_mismatches
216 for candidate in matches:
217 self.assertEqual(None, matcher.match(candidate))
218 for candidate in mismatches:
219 mismatch = matcher.match(candidate)
220 self.assertNotEqual(None, mismatch)
221 self.assertNotEqual(None, getattr(mismatch, 'describe', None))
223 def test__str__(self):
224 # [(expected, object to __str__)].
225 examples = self.str_examples
226 for expected, matcher in examples:
227 self.assertThat(matcher, DocTestMatches(expected))
229 def test_describe_difference(self):
230 # [(expected, matchee, matcher), ...]
231 examples = self.describe_examples
232 for difference, matchee, matcher in examples:
233 mismatch = matcher.match(matchee)
234 self.assertEqual(difference, mismatch.describe())
236 def test_mismatch_details(self):
237 # The mismatch object must provide get_details, which must return a
238 # dictionary mapping names to Content objects.
239 examples = self.describe_examples
240 for difference, matchee, matcher in examples:
241 mismatch = matcher.match(matchee)
242 details = mismatch.get_details()
243 self.assertEqual(dict(details), details)
246 class TestDocTestMatchesInterface(TestCase, TestMatchersInterface):
248 matches_matcher = DocTestMatches("Ran 1 test in ...s", doctest.ELLIPSIS)
249 matches_matches = ["Ran 1 test in 0.000s", "Ran 1 test in 1.234s"]
250 matches_mismatches = ["Ran 1 tests in 0.000s", "Ran 2 test in 0.000s"]
252 str_examples = [("DocTestMatches('Ran 1 test in ...s\\n')",
253 DocTestMatches("Ran 1 test in ...s")),
254 ("DocTestMatches('foo\\n', flags=8)", DocTestMatches("foo", flags=8)),
257 describe_examples = [('Expected:\n Ran 1 tests in ...s\nGot:\n'
258 ' Ran 1 test in 0.123s\n', "Ran 1 test in 0.123s",
259 DocTestMatches("Ran 1 tests in ...s", doctest.ELLIPSIS))]
262 class TestDocTestMatchesInterfaceUnicode(TestCase, TestMatchersInterface):
264 matches_matcher = DocTestMatches(_u("\xa7..."), doctest.ELLIPSIS)
265 matches_matches = [_u("\xa7"), _u("\xa7 more\n")]
266 matches_mismatches = ["\\xa7", _u("more \xa7"), _u("\n\xa7")]
268 str_examples = [("DocTestMatches(%r)" % (_u("\xa7\n"),),
269 DocTestMatches(_u("\xa7"))),
272 describe_examples = [(
273 _u("Expected:\n \xa7\nGot:\n a\n"),
275 DocTestMatches(_u("\xa7"), doctest.ELLIPSIS))]
278 class TestDocTestMatchesSpecific(TestCase):
280 run_tests_with = FullStackRunTest
282 def test___init__simple(self):
283 matcher = DocTestMatches("foo")
284 self.assertEqual("foo\n", matcher.want)
286 def test___init__flags(self):
287 matcher = DocTestMatches("bar\n", doctest.ELLIPSIS)
288 self.assertEqual("bar\n", matcher.want)
289 self.assertEqual(doctest.ELLIPSIS, matcher.flags)
291 def test_describe_non_ascii_bytes(self):
292 """Even with bytestrings, the mismatch should be coercible to unicode
294 DocTestMatches is intended for text, but the Python 2 str type also
295 permits arbitrary binary inputs. This is a slightly bogus thing to do,
296 and under Python 3 using bytes objects will reasonably raise an error.
298 header = _b("\x89PNG\r\n\x1a\n...")
300 self.assertRaises(TypeError,
301 DocTestMatches, header, doctest.ELLIPSIS)
303 matcher = DocTestMatches(header, doctest.ELLIPSIS)
304 mismatch = matcher.match(_b("GIF89a\1\0\1\0\0\0\0;"))
305 # Must be treatable as unicode text, the exact output matters less
306 self.assertTrue(unicode(mismatch.describe()))
309 class TestEqualsInterface(TestCase, TestMatchersInterface):
311 matches_matcher = Equals(1)
312 matches_matches = [1]
313 matches_mismatches = [2]
315 str_examples = [("Equals(1)", Equals(1)), ("Equals('1')", Equals('1'))]
317 describe_examples = [("1 != 2", 2, Equals(1))]
320 class TestNotEqualsInterface(TestCase, TestMatchersInterface):
322 matches_matcher = NotEquals(1)
323 matches_matches = [2]
324 matches_mismatches = [1]
327 ("NotEquals(1)", NotEquals(1)), ("NotEquals('1')", NotEquals('1'))]
329 describe_examples = [("1 == 1", 1, NotEquals(1))]
332 class TestIsInterface(TestCase, TestMatchersInterface):
337 matches_matcher = Is(foo)
338 matches_matches = [foo]
339 matches_mismatches = [bar, 1]
341 str_examples = [("Is(2)", Is(2))]
343 describe_examples = [("1 is not 2", 2, Is(1))]
346 class TestIsInstanceInterface(TestCase, TestMatchersInterface):
350 matches_matcher = IsInstance(Foo)
351 matches_matches = [Foo()]
352 matches_mismatches = [object(), 1, Foo]
355 ("IsInstance(str)", IsInstance(str)),
356 ("IsInstance(str, int)", IsInstance(str, int)),
359 describe_examples = [
360 ("'foo' is not an instance of int", 'foo', IsInstance(int)),
361 ("'foo' is not an instance of any of (int, type)", 'foo',
362 IsInstance(int, type)),
366 class TestLessThanInterface(TestCase, TestMatchersInterface):
368 matches_matcher = LessThan(4)
369 matches_matches = [-5, 3]
370 matches_mismatches = [4, 5, 5000]
373 ("LessThan(12)", LessThan(12)),
376 describe_examples = [
377 ('4 is not > 5', 5, LessThan(4)),
378 ('4 is not > 4', 4, LessThan(4)),
382 class TestGreaterThanInterface(TestCase, TestMatchersInterface):
384 matches_matcher = GreaterThan(4)
385 matches_matches = [5, 8]
386 matches_mismatches = [-2, 0, 4]
389 ("GreaterThan(12)", GreaterThan(12)),
392 describe_examples = [
393 ('5 is not < 4', 4, GreaterThan(5)),
394 ('4 is not < 4', 4, GreaterThan(4)),
398 class TestContainsInterface(TestCase, TestMatchersInterface):
400 matches_matcher = Contains('foo')
401 matches_matches = ['foo', 'afoo', 'fooa']
402 matches_mismatches = ['f', 'fo', 'oo', 'faoo', 'foao']
405 ("Contains(1)", Contains(1)),
406 ("Contains('foo')", Contains('foo')),
409 describe_examples = [("1 not in 2", 2, Contains(1))]
412 def make_error(type, *args, **kwargs):
414 raise type(*args, **kwargs)
416 return sys.exc_info()
419 class TestMatchesExceptionInstanceInterface(TestCase, TestMatchersInterface):
421 matches_matcher = MatchesException(ValueError("foo"))
422 error_foo = make_error(ValueError, 'foo')
423 error_bar = make_error(ValueError, 'bar')
424 error_base_foo = make_error(Exception, 'foo')
425 matches_matches = [error_foo]
426 matches_mismatches = [error_bar, error_base_foo]
429 ("MatchesException(Exception('foo',))",
430 MatchesException(Exception('foo')))
432 describe_examples = [
433 ("%r is not a %r" % (Exception, ValueError),
435 MatchesException(ValueError("foo"))),
436 ("ValueError('bar',) has different arguments to ValueError('foo',).",
438 MatchesException(ValueError("foo"))),
442 class TestMatchesExceptionTypeInterface(TestCase, TestMatchersInterface):
444 matches_matcher = MatchesException(ValueError)
445 error_foo = make_error(ValueError, 'foo')
446 error_sub = make_error(UnicodeError, 'bar')
447 error_base_foo = make_error(Exception, 'foo')
448 matches_matches = [error_foo, error_sub]
449 matches_mismatches = [error_base_foo]
452 ("MatchesException(%r)" % Exception,
453 MatchesException(Exception))
455 describe_examples = [
456 ("%r is not a %r" % (Exception, ValueError),
458 MatchesException(ValueError)),
462 class TestMatchesExceptionTypeReInterface(TestCase, TestMatchersInterface):
464 matches_matcher = MatchesException(ValueError, 'fo.')
465 error_foo = make_error(ValueError, 'foo')
466 error_sub = make_error(UnicodeError, 'foo')
467 error_bar = make_error(ValueError, 'bar')
468 matches_matches = [error_foo, error_sub]
469 matches_mismatches = [error_bar]
472 ("MatchesException(%r)" % Exception,
473 MatchesException(Exception, 'fo.'))
475 describe_examples = [
476 ("'bar' does not match /fo./",
477 error_bar, MatchesException(ValueError, "fo.")),
481 class TestMatchesExceptionTypeMatcherInterface(TestCase, TestMatchersInterface):
483 matches_matcher = MatchesException(
484 ValueError, AfterPreprocessing(str, Equals('foo')))
485 error_foo = make_error(ValueError, 'foo')
486 error_sub = make_error(UnicodeError, 'foo')
487 error_bar = make_error(ValueError, 'bar')
488 matches_matches = [error_foo, error_sub]
489 matches_mismatches = [error_bar]
492 ("MatchesException(%r)" % Exception,
493 MatchesException(Exception, Equals('foo')))
495 describe_examples = [
496 ("5 != %r" % (error_bar[1],),
497 error_bar, MatchesException(ValueError, Equals(5))),
501 class TestNotInterface(TestCase, TestMatchersInterface):
503 matches_matcher = Not(Equals(1))
504 matches_matches = [2]
505 matches_mismatches = [1]
508 ("Not(Equals(1))", Not(Equals(1))),
509 ("Not(Equals('1'))", Not(Equals('1')))]
511 describe_examples = [('1 matches Equals(1)', 1, Not(Equals(1)))]
514 class TestMatchersAnyInterface(TestCase, TestMatchersInterface):
516 matches_matcher = MatchesAny(DocTestMatches("1"), DocTestMatches("2"))
517 matches_matches = ["1", "2"]
518 matches_mismatches = ["3"]
521 "MatchesAny(DocTestMatches('1\\n'), DocTestMatches('2\\n'))",
522 MatchesAny(DocTestMatches("1"), DocTestMatches("2"))),
525 describe_examples = [("""Differences: [
537 "3", MatchesAny(DocTestMatches("1"), DocTestMatches("2")))]
540 class TestMatchesAllInterface(TestCase, TestMatchersInterface):
542 matches_matcher = MatchesAll(NotEquals(1), NotEquals(2))
543 matches_matches = [3, 4]
544 matches_mismatches = [1, 2]
547 ("MatchesAll(NotEquals(1), NotEquals(2))",
548 MatchesAll(NotEquals(1), NotEquals(2)))]
550 describe_examples = [
554 1, MatchesAll(NotEquals(1), NotEquals(2))),
556 MatchesAll(NotEquals(2), NotEquals(1), Equals(3), first_only=True)),
560 class TestKeysEqual(TestCase, TestMatchersInterface):
562 matches_matcher = KeysEqual('foo', 'bar')
564 {'foo': 0, 'bar': 1},
566 matches_mismatches = [
570 {'foo': 0, 'bar': 1, 'baz': 2},
571 {'a': None, 'b': None, 'c': None},
575 ("KeysEqual('foo', 'bar')", KeysEqual('foo', 'bar')),
578 describe_examples = [
579 ("['bar', 'foo'] does not match {'baz': 2, 'foo': 0, 'bar': 1}: "
581 {'foo': 0, 'bar': 1, 'baz': 2}, KeysEqual('foo', 'bar')),
585 class TestAnnotate(TestCase, TestMatchersInterface):
587 matches_matcher = Annotate("foo", Equals(1))
588 matches_matches = [1]
589 matches_mismatches = [2]
592 ("Annotate('foo', Equals(1))", Annotate("foo", Equals(1)))]
594 describe_examples = [("1 != 2: foo", 2, Annotate('foo', Equals(1)))]
596 def test_if_message_no_message(self):
597 # Annotate.if_message returns the given matcher if there is no
600 not_annotated = Annotate.if_message('', matcher)
601 self.assertIs(matcher, not_annotated)
603 def test_if_message_given_message(self):
604 # Annotate.if_message returns an annotated version of the matcher if a
605 # message is provided.
607 expected = Annotate('foo', matcher)
608 annotated = Annotate.if_message('foo', matcher)
611 MatchesStructure.fromExample(expected, 'annotation', 'matcher'))
614 class TestAnnotatedMismatch(TestCase):
616 run_tests_with = FullStackRunTest
618 def test_forwards_details(self):
619 x = Mismatch('description', {'foo': 'bar'})
620 annotated = AnnotatedMismatch("annotation", x)
621 self.assertEqual(x.get_details(), annotated.get_details())
624 class TestRaisesInterface(TestCase, TestMatchersInterface):
626 matches_matcher = Raises()
628 raise Exception('foo')
629 matches_matches = [boom]
630 matches_mismatches = [lambda:None]
632 # Tricky to get function objects to render constantly, and the interfaces
633 # helper uses assertEqual rather than (for instance) DocTestMatches.
636 describe_examples = []
639 class TestRaisesExceptionMatcherInterface(TestCase, TestMatchersInterface):
641 matches_matcher = Raises(
642 exception_matcher=MatchesException(Exception('foo')))
644 raise Exception('bar')
646 raise Exception('foo')
647 matches_matches = [boom_foo]
648 matches_mismatches = [lambda:None, boom_bar]
650 # Tricky to get function objects to render constantly, and the interfaces
651 # helper uses assertEqual rather than (for instance) DocTestMatches.
654 describe_examples = []
657 class TestRaisesBaseTypes(TestCase):
659 run_tests_with = FullStackRunTest
662 raise KeyboardInterrupt('foo')
664 def test_KeyboardInterrupt_matched(self):
665 # When KeyboardInterrupt is matched, it is swallowed.
666 matcher = Raises(MatchesException(KeyboardInterrupt))
667 self.assertThat(self.raiser, matcher)
669 def test_KeyboardInterrupt_propogates(self):
670 # The default 'it raised' propogates KeyboardInterrupt.
671 match_keyb = Raises(MatchesException(KeyboardInterrupt))
672 def raise_keyb_from_match():
674 matcher.match(self.raiser)
675 self.assertThat(raise_keyb_from_match, match_keyb)
677 def test_KeyboardInterrupt_match_Exception_propogates(self):
678 # If the raised exception isn't matched, and it is not a subclass of
679 # Exception, it is propogated.
680 match_keyb = Raises(MatchesException(KeyboardInterrupt))
681 def raise_keyb_from_match():
682 if sys.version_info > (2, 5):
683 matcher = Raises(MatchesException(Exception))
685 # On Python 2.4 KeyboardInterrupt is a StandardError subclass
686 # but should propogate from less generic exception matchers
687 matcher = Raises(MatchesException(EnvironmentError))
688 matcher.match(self.raiser)
689 self.assertThat(raise_keyb_from_match, match_keyb)
692 class TestRaisesConvenience(TestCase):
694 run_tests_with = FullStackRunTest
696 def test_exc_type(self):
697 self.assertThat(lambda: 1/0, raises(ZeroDivisionError))
699 def test_exc_value(self):
700 e = RuntimeError("You lose!")
703 self.assertThat(raiser, raises(e))
706 class DoesNotStartWithTests(TestCase):
708 run_tests_with = FullStackRunTest
710 def test_describe(self):
711 mismatch = DoesNotStartWith("fo", "bo")
712 self.assertEqual("'fo' does not start with 'bo'.", mismatch.describe())
714 def test_describe_non_ascii_unicode(self):
717 mismatch = DoesNotStartWith(string, suffix)
718 self.assertEqual("%s does not start with %s." % (
719 text_repr(string), text_repr(suffix)),
722 def test_describe_non_ascii_bytes(self):
725 mismatch = DoesNotStartWith(string, suffix)
726 self.assertEqual("%r does not start with %r." % (string, suffix),
730 class StartsWithTests(TestCase):
732 run_tests_with = FullStackRunTest
735 matcher = StartsWith("bar")
736 self.assertEqual("StartsWith('bar')", str(matcher))
738 def test_str_with_bytes(self):
740 matcher = StartsWith(b)
741 self.assertEqual("StartsWith(%r)" % (b,), str(matcher))
743 def test_str_with_unicode(self):
745 matcher = StartsWith(u)
746 self.assertEqual("StartsWith(%r)" % (u,), str(matcher))
748 def test_match(self):
749 matcher = StartsWith("bar")
750 self.assertIs(None, matcher.match("barf"))
752 def test_mismatch_returns_does_not_start_with(self):
753 matcher = StartsWith("bar")
754 self.assertIsInstance(matcher.match("foo"), DoesNotStartWith)
756 def test_mismatch_sets_matchee(self):
757 matcher = StartsWith("bar")
758 mismatch = matcher.match("foo")
759 self.assertEqual("foo", mismatch.matchee)
761 def test_mismatch_sets_expected(self):
762 matcher = StartsWith("bar")
763 mismatch = matcher.match("foo")
764 self.assertEqual("bar", mismatch.expected)
767 class DoesNotEndWithTests(TestCase):
769 run_tests_with = FullStackRunTest
771 def test_describe(self):
772 mismatch = DoesNotEndWith("fo", "bo")
773 self.assertEqual("'fo' does not end with 'bo'.", mismatch.describe())
775 def test_describe_non_ascii_unicode(self):
778 mismatch = DoesNotEndWith(string, suffix)
779 self.assertEqual("%s does not end with %s." % (
780 text_repr(string), text_repr(suffix)),
783 def test_describe_non_ascii_bytes(self):
786 mismatch = DoesNotEndWith(string, suffix)
787 self.assertEqual("%r does not end with %r." % (string, suffix),
791 class EndsWithTests(TestCase):
793 run_tests_with = FullStackRunTest
796 matcher = EndsWith("bar")
797 self.assertEqual("EndsWith('bar')", str(matcher))
799 def test_str_with_bytes(self):
801 matcher = EndsWith(b)
802 self.assertEqual("EndsWith(%r)" % (b,), str(matcher))
804 def test_str_with_unicode(self):
806 matcher = EndsWith(u)
807 self.assertEqual("EndsWith(%r)" % (u,), str(matcher))
809 def test_match(self):
810 matcher = EndsWith("arf")
811 self.assertIs(None, matcher.match("barf"))
813 def test_mismatch_returns_does_not_end_with(self):
814 matcher = EndsWith("bar")
815 self.assertIsInstance(matcher.match("foo"), DoesNotEndWith)
817 def test_mismatch_sets_matchee(self):
818 matcher = EndsWith("bar")
819 mismatch = matcher.match("foo")
820 self.assertEqual("foo", mismatch.matchee)
822 def test_mismatch_sets_expected(self):
823 matcher = EndsWith("bar")
824 mismatch = matcher.match("foo")
825 self.assertEqual("bar", mismatch.expected)
828 def run_doctest(obj, name):
829 p = doctest.DocTestParser()
831 obj.__doc__, sys.modules[obj.__module__].__dict__, name, '', 0)
832 r = doctest.DocTestRunner()
834 r.run(t, out=output.write)
835 return r.failures, output.getvalue()
838 class TestMatchesListwise(TestCase):
840 run_tests_with = FullStackRunTest
842 def test_docstring(self):
843 failure_count, output = run_doctest(
844 MatchesListwise, "MatchesListwise")
846 self.fail("Doctest failed with %s" % output)
849 class TestMatchesStructure(TestCase, TestMatchersInterface):
852 def __init__(self, x, y):
856 matches_matcher = MatchesStructure(x=Equals(1), y=Equals(2))
857 matches_matches = [SimpleClass(1, 2)]
858 matches_mismatches = [
865 ("MatchesStructure(x=Equals(1))", MatchesStructure(x=Equals(1))),
866 ("MatchesStructure(y=Equals(2))", MatchesStructure(y=Equals(2))),
867 ("MatchesStructure(x=Equals(1), y=Equals(2))",
868 MatchesStructure(x=Equals(1), y=Equals(2))),
871 describe_examples = [
875 ]""", SimpleClass(1, 2), MatchesStructure(x=Equals(3), y=Equals(2))),
879 ]""", SimpleClass(1, 2), MatchesStructure(x=Equals(1), y=Equals(3))),
884 ]""", SimpleClass(1, 2), MatchesStructure(x=Equals(0), y=Equals(0))),
887 def test_fromExample(self):
889 self.SimpleClass(1, 2),
890 MatchesStructure.fromExample(self.SimpleClass(1, 3), 'x'))
892 def test_byEquality(self):
894 self.SimpleClass(1, 2),
895 MatchesStructure.byEquality(x=1))
897 def test_withStructure(self):
899 self.SimpleClass(1, 2),
900 MatchesStructure.byMatcher(LessThan, x=2))
902 def test_update(self):
904 self.SimpleClass(1, 2),
905 MatchesStructure(x=NotEquals(1)).update(x=Equals(1)))
907 def test_update_none(self):
909 self.SimpleClass(1, 2),
910 MatchesStructure(x=Equals(1), z=NotEquals(42)).update(
914 class TestMatchesRegex(TestCase, TestMatchersInterface):
916 matches_matcher = MatchesRegex('a|b')
917 matches_matches = ['a', 'b']
918 matches_mismatches = ['c']
921 ("MatchesRegex('a|b')", MatchesRegex('a|b')),
922 ("MatchesRegex('a|b', re.M)", MatchesRegex('a|b', re.M)),
923 ("MatchesRegex('a|b', re.I|re.M)", MatchesRegex('a|b', re.I|re.M)),
924 ("MatchesRegex(%r)" % (_b("\xA7"),), MatchesRegex(_b("\xA7"))),
925 ("MatchesRegex(%r)" % (_u("\xA7"),), MatchesRegex(_u("\xA7"))),
928 describe_examples = [
929 ("'c' does not match /a|b/", 'c', MatchesRegex('a|b')),
930 ("'c' does not match /a\d/", 'c', MatchesRegex(r'a\d')),
931 ("%r does not match /\\s+\\xa7/" % (_b('c'),),
932 _b('c'), MatchesRegex(_b("\\s+\xA7"))),
933 ("%r does not match /\\s+\\xa7/" % (_u('c'),),
934 _u('c'), MatchesRegex(_u("\\s+\xA7"))),
938 class TestMatchesSetwise(TestCase):
940 run_tests_with = FullStackRunTest
942 def assertMismatchWithDescriptionMatching(self, value, matcher,
943 description_matcher):
944 mismatch = matcher.match(value)
946 self.fail("%s matched %s" % (matcher, value))
947 actual_description = mismatch.describe()
951 "%s matching %s" % (matcher, value),
952 description_matcher))
954 def test_matches(self):
956 None, MatchesSetwise(Equals(1), Equals(2)).match([2, 1]))
958 def test_mismatches(self):
959 self.assertMismatchWithDescriptionMatching(
960 [2, 3], MatchesSetwise(Equals(1), Equals(2)),
961 MatchesRegex('.*There was 1 mismatch$', re.S))
963 def test_too_many_matchers(self):
964 self.assertMismatchWithDescriptionMatching(
965 [2, 3], MatchesSetwise(Equals(1), Equals(2), Equals(3)),
966 Equals('There was 1 matcher left over: Equals(1)'))
968 def test_too_many_values(self):
969 self.assertMismatchWithDescriptionMatching(
970 [1, 2, 3], MatchesSetwise(Equals(1), Equals(2)),
971 Equals('There was 1 value left over: [3]'))
973 def test_two_too_many_matchers(self):
974 self.assertMismatchWithDescriptionMatching(
975 [3], MatchesSetwise(Equals(1), Equals(2), Equals(3)),
977 'There were 2 matchers left over: Equals\([12]\), '
980 def test_two_too_many_values(self):
981 self.assertMismatchWithDescriptionMatching(
982 [1, 2, 3, 4], MatchesSetwise(Equals(1), Equals(2)),
984 'There were 2 values left over: \[[34], [34]\]'))
986 def test_mismatch_and_too_many_matchers(self):
987 self.assertMismatchWithDescriptionMatching(
988 [2, 3], MatchesSetwise(Equals(0), Equals(1), Equals(2)),
990 '.*There was 1 mismatch and 1 extra matcher: Equals\([01]\)',
993 def test_mismatch_and_too_many_values(self):
994 self.assertMismatchWithDescriptionMatching(
995 [2, 3, 4], MatchesSetwise(Equals(1), Equals(2)),
997 '.*There was 1 mismatch and 1 extra value: \[[34]\]',
1000 def test_mismatch_and_two_too_many_matchers(self):
1001 self.assertMismatchWithDescriptionMatching(
1002 [3, 4], MatchesSetwise(
1003 Equals(0), Equals(1), Equals(2), Equals(3)),
1005 '.*There was 1 mismatch and 2 extra matchers: '
1006 'Equals\([012]\), Equals\([012]\)', re.S))
1008 def test_mismatch_and_two_too_many_values(self):
1009 self.assertMismatchWithDescriptionMatching(
1010 [2, 3, 4, 5], MatchesSetwise(Equals(1), Equals(2)),
1012 '.*There was 1 mismatch and 2 extra values: \[[145], [145]\]',
1016 class TestAfterPreprocessing(TestCase, TestMatchersInterface):
1021 matches_matcher = AfterPreprocessing(parity, Equals(1))
1022 matches_matches = [3, 5]
1023 matches_mismatches = [2]
1026 ("AfterPreprocessing(<function parity>, Equals(1))",
1027 AfterPreprocessing(parity, Equals(1))),
1030 describe_examples = [
1031 ("1 != 0: after <function parity> on 2", 2,
1032 AfterPreprocessing(parity, Equals(1))),
1034 AfterPreprocessing(parity, Equals(1), annotate=False)),
1038 class TestMismatchDecorator(TestCase):
1040 run_tests_with = FullStackRunTest
1042 def test_forwards_description(self):
1043 x = Mismatch("description", {'foo': 'bar'})
1044 decorated = MismatchDecorator(x)
1045 self.assertEqual(x.describe(), decorated.describe())
1047 def test_forwards_details(self):
1048 x = Mismatch("description", {'foo': 'bar'})
1049 decorated = MismatchDecorator(x)
1050 self.assertEqual(x.get_details(), decorated.get_details())
1052 def test_repr(self):
1053 x = Mismatch("description", {'foo': 'bar'})
1054 decorated = MismatchDecorator(x)
1056 '<testtools.matchers.MismatchDecorator(%r)>' % (x,),
1060 class TestAllMatch(TestCase, TestMatchersInterface):
1062 matches_matcher = AllMatch(LessThan(10))
1066 iter([9, 9, 9, 9, 9]),
1068 matches_mismatches = [
1070 iter([9, 12, 9, 11]),
1074 ("AllMatch(LessThan(12))", AllMatch(LessThan(12))),
1077 describe_examples = [
1083 AllMatch(LessThan(10))),
1087 class PathHelpers(object):
1090 directory = tempfile.mkdtemp()
1091 self.addCleanup(shutil.rmtree, directory)
1094 def create_file(self, filename, contents=''):
1095 fp = open(filename, 'w')
1101 def touch(self, filename):
1102 return self.create_file(filename)
1105 class TestPathExists(TestCase, PathHelpers):
1107 def test_exists(self):
1108 tempdir = self.mkdtemp()
1109 self.assertThat(tempdir, PathExists())
1111 def test_not_exists(self):
1112 doesntexist = os.path.join(self.mkdtemp(), 'doesntexist')
1113 mismatch = PathExists().match(doesntexist)
1115 "%s does not exist." % doesntexist, Equals(mismatch.describe()))
1118 class TestDirExists(TestCase, PathHelpers):
1120 def test_exists(self):
1121 tempdir = self.mkdtemp()
1122 self.assertThat(tempdir, DirExists())
1124 def test_not_exists(self):
1125 doesntexist = os.path.join(self.mkdtemp(), 'doesntexist')
1126 mismatch = DirExists().match(doesntexist)
1128 PathExists().match(doesntexist).describe(),
1129 Equals(mismatch.describe()))
1131 def test_not_a_directory(self):
1132 filename = os.path.join(self.mkdtemp(), 'foo')
1133 self.touch(filename)
1134 mismatch = DirExists().match(filename)
1136 "%s is not a directory." % filename, Equals(mismatch.describe()))
1139 class TestFileExists(TestCase, PathHelpers):
1141 def test_exists(self):
1142 tempdir = self.mkdtemp()
1143 filename = os.path.join(tempdir, 'filename')
1144 self.touch(filename)
1145 self.assertThat(filename, FileExists())
1147 def test_not_exists(self):
1148 doesntexist = os.path.join(self.mkdtemp(), 'doesntexist')
1149 mismatch = FileExists().match(doesntexist)
1151 PathExists().match(doesntexist).describe(),
1152 Equals(mismatch.describe()))
1154 def test_not_a_file(self):
1155 tempdir = self.mkdtemp()
1156 mismatch = FileExists().match(tempdir)
1158 "%s is not a file." % tempdir, Equals(mismatch.describe()))
1161 class TestDirContains(TestCase, PathHelpers):
1163 def test_empty(self):
1164 tempdir = self.mkdtemp()
1165 self.assertThat(tempdir, DirContains([]))
1167 def test_not_exists(self):
1168 doesntexist = os.path.join(self.mkdtemp(), 'doesntexist')
1169 mismatch = DirContains([]).match(doesntexist)
1171 PathExists().match(doesntexist).describe(),
1172 Equals(mismatch.describe()))
1174 def test_contains_files(self):
1175 tempdir = self.mkdtemp()
1176 self.touch(os.path.join(tempdir, 'foo'))
1177 self.touch(os.path.join(tempdir, 'bar'))
1178 self.assertThat(tempdir, DirContains(['bar', 'foo']))
1180 def test_matcher(self):
1181 tempdir = self.mkdtemp()
1182 self.touch(os.path.join(tempdir, 'foo'))
1183 self.touch(os.path.join(tempdir, 'bar'))
1184 self.assertThat(tempdir, DirContains(matcher=Contains('bar')))
1186 def test_neither_specified(self):
1187 self.assertRaises(AssertionError, DirContains)
1189 def test_both_specified(self):
1191 AssertionError, DirContains, filenames=[], matcher=Contains('a'))
1193 def test_does_not_contain_files(self):
1194 tempdir = self.mkdtemp()
1195 self.touch(os.path.join(tempdir, 'foo'))
1196 mismatch = DirContains(['bar', 'foo']).match(tempdir)
1198 Equals(['bar', 'foo']).match(['foo']).describe(),
1199 Equals(mismatch.describe()))
1202 class TestFileContains(TestCase, PathHelpers):
1204 def test_not_exists(self):
1205 doesntexist = os.path.join(self.mkdtemp(), 'doesntexist')
1206 mismatch = FileContains('').match(doesntexist)
1208 PathExists().match(doesntexist).describe(),
1209 Equals(mismatch.describe()))
1211 def test_contains(self):
1212 tempdir = self.mkdtemp()
1213 filename = os.path.join(tempdir, 'foo')
1214 self.create_file(filename, 'Hello World!')
1215 self.assertThat(filename, FileContains('Hello World!'))
1217 def test_matcher(self):
1218 tempdir = self.mkdtemp()
1219 filename = os.path.join(tempdir, 'foo')
1220 self.create_file(filename, 'Hello World!')
1222 filename, FileContains(matcher=DocTestMatches('Hello World!')))
1224 def test_neither_specified(self):
1225 self.assertRaises(AssertionError, FileContains)
1227 def test_both_specified(self):
1229 AssertionError, FileContains, contents=[], matcher=Contains('a'))
1231 def test_does_not_contain(self):
1232 tempdir = self.mkdtemp()
1233 filename = os.path.join(tempdir, 'foo')
1234 self.create_file(filename, 'Goodbye Cruel World!')
1235 mismatch = FileContains('Hello World!').match(filename)
1237 Equals('Hello World!').match('Goodbye Cruel World!').describe(),
1238 Equals(mismatch.describe()))
1245 class TestMatchesPredicate(TestCase, TestMatchersInterface):
1247 matches_matcher = MatchesPredicate(is_even, "%s is not even")
1248 matches_matches = [2, 4, 6, 8]
1249 matches_mismatches = [3, 5, 7, 9]
1252 ("MatchesPredicate(%r, %r)" % (is_even, "%s is not even"),
1253 MatchesPredicate(is_even, "%s is not even")),
1256 describe_examples = [
1257 ('7 is not even', 7, MatchesPredicate(is_even, "%s is not even")),
1261 class TestTarballContains(TestCase, PathHelpers):
1263 def test_match(self):
1264 tempdir = self.mkdtemp()
1265 in_temp_dir = lambda x: os.path.join(tempdir, x)
1266 self.touch(in_temp_dir('a'))
1267 self.touch(in_temp_dir('b'))
1268 tarball = tarfile.open(in_temp_dir('foo.tar.gz'), 'w')
1269 tarball.add(in_temp_dir('a'), 'a')
1270 tarball.add(in_temp_dir('b'), 'b')
1273 in_temp_dir('foo.tar.gz'), TarballContains(['b', 'a']))
1275 def test_mismatch(self):
1276 tempdir = self.mkdtemp()
1277 in_temp_dir = lambda x: os.path.join(tempdir, x)
1278 self.touch(in_temp_dir('a'))
1279 self.touch(in_temp_dir('b'))
1280 tarball = tarfile.open(in_temp_dir('foo.tar.gz'), 'w')
1281 tarball.add(in_temp_dir('a'), 'a')
1282 tarball.add(in_temp_dir('b'), 'b')
1284 mismatch = TarballContains(['d', 'c']).match(in_temp_dir('foo.tar.gz'))
1286 mismatch.describe(),
1287 Equals(['c', 'd']).match(['a', 'b']).describe())
1290 class TestSamePath(TestCase, PathHelpers):
1292 def test_same_string(self):
1293 self.assertThat('foo', SamePath('foo'))
1295 def test_relative_and_absolute(self):
1297 abspath = os.path.abspath(path)
1298 self.assertThat(path, SamePath(abspath))
1299 self.assertThat(abspath, SamePath(path))
1301 def test_real_path(self):
1302 symlink = getattr(os, 'symlink', None)
1303 skipIf(symlink is None, "No symlink support")
1304 tempdir = self.mkdtemp()
1305 source = os.path.join(tempdir, 'source')
1307 target = os.path.join(tempdir, 'target')
1308 symlink(source, target)
1309 self.assertThat(source, SamePath(target))
1310 self.assertThat(target, SamePath(source))
1313 class TestHasPermissions(TestCase, PathHelpers):
1315 def test_match(self):
1316 tempdir = self.mkdtemp()
1317 filename = os.path.join(tempdir, 'filename')
1318 self.touch(filename)
1319 permissions = oct(os.stat(filename).st_mode)[-4:]
1320 self.assertThat(filename, HasPermissions(permissions))
1324 from unittest import TestLoader
1325 return TestLoader().loadTestsFromName(__name__)