1 # Copyright (c) 2008-2011 testtools developers. See LICENSE for details.
3 """Tests for matchers."""
9 from testtools import (
10 Matcher, # check that Matcher is exposed at the top level for docs.
13 from testtools.compat import (
20 from testtools.matchers import (
53 from testtools.tests.helpers import FullStackRunTest
59 class TestMismatch(TestCase):
61 run_tests_with = FullStackRunTest
63 def test_constructor_arguments(self):
64 mismatch = Mismatch("some description", {'detail': "things"})
65 self.assertEqual("some description", mismatch.describe())
66 self.assertEqual({'detail': "things"}, mismatch.get_details())
68 def test_constructor_no_arguments(self):
70 self.assertThat(mismatch.describe,
71 Raises(MatchesException(NotImplementedError)))
72 self.assertEqual({}, mismatch.get_details())
75 class TestMismatchError(TestCase):
77 def test_is_assertion_error(self):
78 # MismatchError is an AssertionError, so that most of the time, it
79 # looks like a test failure, rather than an error.
80 def raise_mismatch_error():
81 raise MismatchError(2, Equals(3), Equals(3).match(2))
82 self.assertRaises(AssertionError, raise_mismatch_error)
84 def test_default_description_is_mismatch(self):
85 mismatch = Equals(3).match(2)
86 e = MismatchError(2, Equals(3), mismatch)
87 self.assertEqual(mismatch.describe(), str(e))
89 def test_default_description_unicode(self):
91 matcher = Equals(_u('a'))
92 mismatch = matcher.match(matchee)
93 e = MismatchError(matchee, matcher, mismatch)
94 self.assertEqual(mismatch.describe(), str(e))
96 def test_verbose_description(self):
99 mismatch = matcher.match(2)
100 e = MismatchError(matchee, matcher, mismatch, True)
102 'Match failed. Matchee: %r\n'
104 'Difference: %s\n' % (
107 matcher.match(matchee).describe(),
109 self.assertEqual(expected, str(e))
111 def test_verbose_unicode(self):
112 # When assertThat is given matchees or matchers that contain non-ASCII
113 # unicode strings, we can still provide a meaningful error.
115 matcher = Equals(_u('a'))
116 mismatch = matcher.match(matchee)
118 'Match failed. Matchee: %s\n'
120 'Difference: %s\n' % (
125 e = MismatchError(matchee, matcher, mismatch, True)
130 # Using str() should still work, and return ascii only
132 expected.replace(matchee, matchee.encode("unicode-escape")),
133 str(e).decode("ascii"))
134 self.assertEqual(expected, actual)
137 class Test_BinaryMismatch(TestCase):
138 """Mismatches from binary comparisons need useful describe output"""
140 _long_string = "This is a longish multiline non-ascii string\n\xa7"
141 _long_b = _b(_long_string)
142 _long_u = _u(_long_string)
144 def test_short_objects(self):
145 o1, o2 = object(), object()
146 mismatch = _BinaryMismatch(o1, "!~", o2)
147 self.assertEqual(mismatch.describe(), "%r !~ %r" % (o1, o2))
149 def test_short_mixed_strings(self):
150 b, u = _b("\xa7"), _u("\xa7")
151 mismatch = _BinaryMismatch(b, "!~", u)
152 self.assertEqual(mismatch.describe(), "%r !~ %r" % (b, u))
154 def test_long_bytes(self):
155 one_line_b = self._long_b.replace(_b("\n"), _b(" "))
156 mismatch = _BinaryMismatch(one_line_b, "!~", self._long_b)
157 self.assertEqual(mismatch.describe(),
158 "%s:\nreference = %s\nactual = %s\n" % ("!~",
159 text_repr(one_line_b),
160 text_repr(self._long_b, multiline=True)))
162 def test_long_unicode(self):
163 one_line_u = self._long_u.replace("\n", " ")
164 mismatch = _BinaryMismatch(one_line_u, "!~", self._long_u)
165 self.assertEqual(mismatch.describe(),
166 "%s:\nreference = %s\nactual = %s\n" % ("!~",
167 text_repr(one_line_u),
168 text_repr(self._long_u, multiline=True)))
170 def test_long_mixed_strings(self):
171 mismatch = _BinaryMismatch(self._long_b, "!~", self._long_u)
172 self.assertEqual(mismatch.describe(),
173 "%s:\nreference = %s\nactual = %s\n" % ("!~",
174 text_repr(self._long_b, multiline=True),
175 text_repr(self._long_u, multiline=True)))
177 def test_long_bytes_and_object(self):
179 mismatch = _BinaryMismatch(self._long_b, "!~", obj)
180 self.assertEqual(mismatch.describe(),
181 "%s:\nreference = %s\nactual = %s\n" % ("!~",
182 text_repr(self._long_b, multiline=True),
185 def test_long_unicode_and_object(self):
187 mismatch = _BinaryMismatch(self._long_u, "!~", obj)
188 self.assertEqual(mismatch.describe(),
189 "%s:\nreference = %s\nactual = %s\n" % ("!~",
190 text_repr(self._long_u, multiline=True),
194 class TestMatchersInterface(object):
196 run_tests_with = FullStackRunTest
198 def test_matches_match(self):
199 matcher = self.matches_matcher
200 matches = self.matches_matches
201 mismatches = self.matches_mismatches
202 for candidate in matches:
203 self.assertEqual(None, matcher.match(candidate))
204 for candidate in mismatches:
205 mismatch = matcher.match(candidate)
206 self.assertNotEqual(None, mismatch)
207 self.assertNotEqual(None, getattr(mismatch, 'describe', None))
209 def test__str__(self):
210 # [(expected, object to __str__)].
211 examples = self.str_examples
212 for expected, matcher in examples:
213 self.assertThat(matcher, DocTestMatches(expected))
215 def test_describe_difference(self):
216 # [(expected, matchee, matcher), ...]
217 examples = self.describe_examples
218 for difference, matchee, matcher in examples:
219 mismatch = matcher.match(matchee)
220 self.assertEqual(difference, mismatch.describe())
222 def test_mismatch_details(self):
223 # The mismatch object must provide get_details, which must return a
224 # dictionary mapping names to Content objects.
225 examples = self.describe_examples
226 for difference, matchee, matcher in examples:
227 mismatch = matcher.match(matchee)
228 details = mismatch.get_details()
229 self.assertEqual(dict(details), details)
232 class TestDocTestMatchesInterface(TestCase, TestMatchersInterface):
234 matches_matcher = DocTestMatches("Ran 1 test in ...s", doctest.ELLIPSIS)
235 matches_matches = ["Ran 1 test in 0.000s", "Ran 1 test in 1.234s"]
236 matches_mismatches = ["Ran 1 tests in 0.000s", "Ran 2 test in 0.000s"]
238 str_examples = [("DocTestMatches('Ran 1 test in ...s\\n')",
239 DocTestMatches("Ran 1 test in ...s")),
240 ("DocTestMatches('foo\\n', flags=8)", DocTestMatches("foo", flags=8)),
243 describe_examples = [('Expected:\n Ran 1 tests in ...s\nGot:\n'
244 ' Ran 1 test in 0.123s\n', "Ran 1 test in 0.123s",
245 DocTestMatches("Ran 1 tests in ...s", doctest.ELLIPSIS))]
248 class TestDocTestMatchesInterfaceUnicode(TestCase, TestMatchersInterface):
250 matches_matcher = DocTestMatches(_u("\xa7..."), doctest.ELLIPSIS)
251 matches_matches = [_u("\xa7"), _u("\xa7 more\n")]
252 matches_mismatches = ["\\xa7", _u("more \xa7"), _u("\n\xa7")]
254 str_examples = [("DocTestMatches(%r)" % (_u("\xa7\n"),),
255 DocTestMatches(_u("\xa7"))),
258 describe_examples = [(
259 _u("Expected:\n \xa7\nGot:\n a\n"),
261 DocTestMatches(_u("\xa7"), doctest.ELLIPSIS))]
264 class TestDocTestMatchesSpecific(TestCase):
266 run_tests_with = FullStackRunTest
268 def test___init__simple(self):
269 matcher = DocTestMatches("foo")
270 self.assertEqual("foo\n", matcher.want)
272 def test___init__flags(self):
273 matcher = DocTestMatches("bar\n", doctest.ELLIPSIS)
274 self.assertEqual("bar\n", matcher.want)
275 self.assertEqual(doctest.ELLIPSIS, matcher.flags)
277 def test_describe_non_ascii_bytes(self):
278 """Even with bytestrings, the mismatch should be coercible to unicode
280 DocTestMatches is intended for text, but the Python 2 str type also
281 permits arbitrary binary inputs. This is a slightly bogus thing to do,
282 and under Python 3 using bytes objects will reasonably raise an error.
284 header = _b("\x89PNG\r\n\x1a\n...")
286 self.assertRaises(TypeError,
287 DocTestMatches, header, doctest.ELLIPSIS)
289 matcher = DocTestMatches(header, doctest.ELLIPSIS)
290 mismatch = matcher.match(_b("GIF89a\1\0\1\0\0\0\0;"))
291 # Must be treatable as unicode text, the exact output matters less
292 self.assertTrue(unicode(mismatch.describe()))
295 class TestEqualsInterface(TestCase, TestMatchersInterface):
297 matches_matcher = Equals(1)
298 matches_matches = [1]
299 matches_mismatches = [2]
301 str_examples = [("Equals(1)", Equals(1)), ("Equals('1')", Equals('1'))]
303 describe_examples = [("1 != 2", 2, Equals(1))]
306 class TestNotEqualsInterface(TestCase, TestMatchersInterface):
308 matches_matcher = NotEquals(1)
309 matches_matches = [2]
310 matches_mismatches = [1]
313 ("NotEquals(1)", NotEquals(1)), ("NotEquals('1')", NotEquals('1'))]
315 describe_examples = [("1 == 1", 1, NotEquals(1))]
318 class TestIsInterface(TestCase, TestMatchersInterface):
323 matches_matcher = Is(foo)
324 matches_matches = [foo]
325 matches_mismatches = [bar, 1]
327 str_examples = [("Is(2)", Is(2))]
329 describe_examples = [("1 is not 2", 2, Is(1))]
332 class TestIsInstanceInterface(TestCase, TestMatchersInterface):
336 matches_matcher = IsInstance(Foo)
337 matches_matches = [Foo()]
338 matches_mismatches = [object(), 1, Foo]
341 ("IsInstance(str)", IsInstance(str)),
342 ("IsInstance(str, int)", IsInstance(str, int)),
345 describe_examples = [
346 ("'foo' is not an instance of int", 'foo', IsInstance(int)),
347 ("'foo' is not an instance of any of (int, type)", 'foo',
348 IsInstance(int, type)),
352 class TestLessThanInterface(TestCase, TestMatchersInterface):
354 matches_matcher = LessThan(4)
355 matches_matches = [-5, 3]
356 matches_mismatches = [4, 5, 5000]
359 ("LessThan(12)", LessThan(12)),
362 describe_examples = [
363 ('4 is not > 5', 5, LessThan(4)),
364 ('4 is not > 4', 4, LessThan(4)),
368 class TestGreaterThanInterface(TestCase, TestMatchersInterface):
370 matches_matcher = GreaterThan(4)
371 matches_matches = [5, 8]
372 matches_mismatches = [-2, 0, 4]
375 ("GreaterThan(12)", GreaterThan(12)),
378 describe_examples = [
379 ('5 is not < 4', 4, GreaterThan(5)),
380 ('4 is not < 4', 4, GreaterThan(4)),
384 class TestContainsInterface(TestCase, TestMatchersInterface):
386 matches_matcher = Contains('foo')
387 matches_matches = ['foo', 'afoo', 'fooa']
388 matches_mismatches = ['f', 'fo', 'oo', 'faoo', 'foao']
391 ("Contains(1)", Contains(1)),
392 ("Contains('foo')", Contains('foo')),
395 describe_examples = [("1 not in 2", 2, Contains(1))]
398 def make_error(type, *args, **kwargs):
400 raise type(*args, **kwargs)
402 return sys.exc_info()
405 class TestMatchesExceptionInstanceInterface(TestCase, TestMatchersInterface):
407 matches_matcher = MatchesException(ValueError("foo"))
408 error_foo = make_error(ValueError, 'foo')
409 error_bar = make_error(ValueError, 'bar')
410 error_base_foo = make_error(Exception, 'foo')
411 matches_matches = [error_foo]
412 matches_mismatches = [error_bar, error_base_foo]
415 ("MatchesException(Exception('foo',))",
416 MatchesException(Exception('foo')))
418 describe_examples = [
419 ("%r is not a %r" % (Exception, ValueError),
421 MatchesException(ValueError("foo"))),
422 ("ValueError('bar',) has different arguments to ValueError('foo',).",
424 MatchesException(ValueError("foo"))),
428 class TestMatchesExceptionTypeInterface(TestCase, TestMatchersInterface):
430 matches_matcher = MatchesException(ValueError)
431 error_foo = make_error(ValueError, 'foo')
432 error_sub = make_error(UnicodeError, 'bar')
433 error_base_foo = make_error(Exception, 'foo')
434 matches_matches = [error_foo, error_sub]
435 matches_mismatches = [error_base_foo]
438 ("MatchesException(%r)" % Exception,
439 MatchesException(Exception))
441 describe_examples = [
442 ("%r is not a %r" % (Exception, ValueError),
444 MatchesException(ValueError)),
448 class TestMatchesExceptionTypeReInterface(TestCase, TestMatchersInterface):
450 matches_matcher = MatchesException(ValueError, 'fo.')
451 error_foo = make_error(ValueError, 'foo')
452 error_sub = make_error(UnicodeError, 'foo')
453 error_bar = make_error(ValueError, 'bar')
454 matches_matches = [error_foo, error_sub]
455 matches_mismatches = [error_bar]
458 ("MatchesException(%r)" % Exception,
459 MatchesException(Exception, 'fo.'))
461 describe_examples = [
462 ("'bar' does not match /fo./",
463 error_bar, MatchesException(ValueError, "fo.")),
467 class TestMatchesExceptionTypeMatcherInterface(TestCase, TestMatchersInterface):
469 matches_matcher = MatchesException(
470 ValueError, AfterPreprocessing(str, Equals('foo')))
471 error_foo = make_error(ValueError, 'foo')
472 error_sub = make_error(UnicodeError, 'foo')
473 error_bar = make_error(ValueError, 'bar')
474 matches_matches = [error_foo, error_sub]
475 matches_mismatches = [error_bar]
478 ("MatchesException(%r)" % Exception,
479 MatchesException(Exception, Equals('foo')))
481 describe_examples = [
482 ("5 != %r" % (error_bar[1],),
483 error_bar, MatchesException(ValueError, Equals(5))),
487 class TestNotInterface(TestCase, TestMatchersInterface):
489 matches_matcher = Not(Equals(1))
490 matches_matches = [2]
491 matches_mismatches = [1]
494 ("Not(Equals(1))", Not(Equals(1))),
495 ("Not(Equals('1'))", Not(Equals('1')))]
497 describe_examples = [('1 matches Equals(1)', 1, Not(Equals(1)))]
500 class TestMatchersAnyInterface(TestCase, TestMatchersInterface):
502 matches_matcher = MatchesAny(DocTestMatches("1"), DocTestMatches("2"))
503 matches_matches = ["1", "2"]
504 matches_mismatches = ["3"]
507 "MatchesAny(DocTestMatches('1\\n'), DocTestMatches('2\\n'))",
508 MatchesAny(DocTestMatches("1"), DocTestMatches("2"))),
511 describe_examples = [("""Differences: [
523 "3", MatchesAny(DocTestMatches("1"), DocTestMatches("2")))]
526 class TestMatchesAllInterface(TestCase, TestMatchersInterface):
528 matches_matcher = MatchesAll(NotEquals(1), NotEquals(2))
529 matches_matches = [3, 4]
530 matches_mismatches = [1, 2]
533 ("MatchesAll(NotEquals(1), NotEquals(2))",
534 MatchesAll(NotEquals(1), NotEquals(2)))]
536 describe_examples = [("""Differences: [
539 1, MatchesAll(NotEquals(1), NotEquals(2)))]
542 class TestKeysEqual(TestCase, TestMatchersInterface):
544 matches_matcher = KeysEqual('foo', 'bar')
546 {'foo': 0, 'bar': 1},
548 matches_mismatches = [
552 {'foo': 0, 'bar': 1, 'baz': 2},
553 {'a': None, 'b': None, 'c': None},
557 ("KeysEqual('foo', 'bar')", KeysEqual('foo', 'bar')),
560 describe_examples = [
561 ("['bar', 'foo'] does not match {'baz': 2, 'foo': 0, 'bar': 1}: "
563 {'foo': 0, 'bar': 1, 'baz': 2}, KeysEqual('foo', 'bar')),
567 class TestAnnotate(TestCase, TestMatchersInterface):
569 matches_matcher = Annotate("foo", Equals(1))
570 matches_matches = [1]
571 matches_mismatches = [2]
574 ("Annotate('foo', Equals(1))", Annotate("foo", Equals(1)))]
576 describe_examples = [("1 != 2: foo", 2, Annotate('foo', Equals(1)))]
578 def test_if_message_no_message(self):
579 # Annotate.if_message returns the given matcher if there is no
582 not_annotated = Annotate.if_message('', matcher)
583 self.assertIs(matcher, not_annotated)
585 def test_if_message_given_message(self):
586 # Annotate.if_message returns an annotated version of the matcher if a
587 # message is provided.
589 expected = Annotate('foo', matcher)
590 annotated = Annotate.if_message('foo', matcher)
593 MatchesStructure.fromExample(expected, 'annotation', 'matcher'))
596 class TestAnnotatedMismatch(TestCase):
598 run_tests_with = FullStackRunTest
600 def test_forwards_details(self):
601 x = Mismatch('description', {'foo': 'bar'})
602 annotated = AnnotatedMismatch("annotation", x)
603 self.assertEqual(x.get_details(), annotated.get_details())
606 class TestRaisesInterface(TestCase, TestMatchersInterface):
608 matches_matcher = Raises()
610 raise Exception('foo')
611 matches_matches = [boom]
612 matches_mismatches = [lambda:None]
614 # Tricky to get function objects to render constantly, and the interfaces
615 # helper uses assertEqual rather than (for instance) DocTestMatches.
618 describe_examples = []
621 class TestRaisesExceptionMatcherInterface(TestCase, TestMatchersInterface):
623 matches_matcher = Raises(
624 exception_matcher=MatchesException(Exception('foo')))
626 raise Exception('bar')
628 raise Exception('foo')
629 matches_matches = [boom_foo]
630 matches_mismatches = [lambda:None, boom_bar]
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 TestRaisesBaseTypes(TestCase):
641 run_tests_with = FullStackRunTest
644 raise KeyboardInterrupt('foo')
646 def test_KeyboardInterrupt_matched(self):
647 # When KeyboardInterrupt is matched, it is swallowed.
648 matcher = Raises(MatchesException(KeyboardInterrupt))
649 self.assertThat(self.raiser, matcher)
651 def test_KeyboardInterrupt_propogates(self):
652 # The default 'it raised' propogates KeyboardInterrupt.
653 match_keyb = Raises(MatchesException(KeyboardInterrupt))
654 def raise_keyb_from_match():
656 matcher.match(self.raiser)
657 self.assertThat(raise_keyb_from_match, match_keyb)
659 def test_KeyboardInterrupt_match_Exception_propogates(self):
660 # If the raised exception isn't matched, and it is not a subclass of
661 # Exception, it is propogated.
662 match_keyb = Raises(MatchesException(KeyboardInterrupt))
663 def raise_keyb_from_match():
664 if sys.version_info > (2, 5):
665 matcher = Raises(MatchesException(Exception))
667 # On Python 2.4 KeyboardInterrupt is a StandardError subclass
668 # but should propogate from less generic exception matchers
669 matcher = Raises(MatchesException(EnvironmentError))
670 matcher.match(self.raiser)
671 self.assertThat(raise_keyb_from_match, match_keyb)
674 class TestRaisesConvenience(TestCase):
676 run_tests_with = FullStackRunTest
678 def test_exc_type(self):
679 self.assertThat(lambda: 1/0, raises(ZeroDivisionError))
681 def test_exc_value(self):
682 e = RuntimeError("You lose!")
685 self.assertThat(raiser, raises(e))
688 class DoesNotStartWithTests(TestCase):
690 run_tests_with = FullStackRunTest
692 def test_describe(self):
693 mismatch = DoesNotStartWith("fo", "bo")
694 self.assertEqual("'fo' does not start with 'bo'.", mismatch.describe())
696 def test_describe_non_ascii_unicode(self):
699 mismatch = DoesNotStartWith(string, suffix)
700 self.assertEqual("%s does not start with %s." % (
701 text_repr(string), text_repr(suffix)),
704 def test_describe_non_ascii_bytes(self):
707 mismatch = DoesNotStartWith(string, suffix)
708 self.assertEqual("%r does not start with %r." % (string, suffix),
712 class StartsWithTests(TestCase):
714 run_tests_with = FullStackRunTest
717 matcher = StartsWith("bar")
718 self.assertEqual("StartsWith('bar')", str(matcher))
720 def test_str_with_bytes(self):
722 matcher = StartsWith(b)
723 self.assertEqual("StartsWith(%r)" % (b,), str(matcher))
725 def test_str_with_unicode(self):
727 matcher = StartsWith(u)
728 self.assertEqual("StartsWith(%r)" % (u,), str(matcher))
730 def test_match(self):
731 matcher = StartsWith("bar")
732 self.assertIs(None, matcher.match("barf"))
734 def test_mismatch_returns_does_not_start_with(self):
735 matcher = StartsWith("bar")
736 self.assertIsInstance(matcher.match("foo"), DoesNotStartWith)
738 def test_mismatch_sets_matchee(self):
739 matcher = StartsWith("bar")
740 mismatch = matcher.match("foo")
741 self.assertEqual("foo", mismatch.matchee)
743 def test_mismatch_sets_expected(self):
744 matcher = StartsWith("bar")
745 mismatch = matcher.match("foo")
746 self.assertEqual("bar", mismatch.expected)
749 class DoesNotEndWithTests(TestCase):
751 run_tests_with = FullStackRunTest
753 def test_describe(self):
754 mismatch = DoesNotEndWith("fo", "bo")
755 self.assertEqual("'fo' does not end with 'bo'.", mismatch.describe())
757 def test_describe_non_ascii_unicode(self):
760 mismatch = DoesNotEndWith(string, suffix)
761 self.assertEqual("%s does not end with %s." % (
762 text_repr(string), text_repr(suffix)),
765 def test_describe_non_ascii_bytes(self):
768 mismatch = DoesNotEndWith(string, suffix)
769 self.assertEqual("%r does not end with %r." % (string, suffix),
773 class EndsWithTests(TestCase):
775 run_tests_with = FullStackRunTest
778 matcher = EndsWith("bar")
779 self.assertEqual("EndsWith('bar')", str(matcher))
781 def test_str_with_bytes(self):
783 matcher = EndsWith(b)
784 self.assertEqual("EndsWith(%r)" % (b,), str(matcher))
786 def test_str_with_unicode(self):
788 matcher = EndsWith(u)
789 self.assertEqual("EndsWith(%r)" % (u,), str(matcher))
791 def test_match(self):
792 matcher = EndsWith("arf")
793 self.assertIs(None, matcher.match("barf"))
795 def test_mismatch_returns_does_not_end_with(self):
796 matcher = EndsWith("bar")
797 self.assertIsInstance(matcher.match("foo"), DoesNotEndWith)
799 def test_mismatch_sets_matchee(self):
800 matcher = EndsWith("bar")
801 mismatch = matcher.match("foo")
802 self.assertEqual("foo", mismatch.matchee)
804 def test_mismatch_sets_expected(self):
805 matcher = EndsWith("bar")
806 mismatch = matcher.match("foo")
807 self.assertEqual("bar", mismatch.expected)
810 def run_doctest(obj, name):
811 p = doctest.DocTestParser()
813 obj.__doc__, sys.modules[obj.__module__].__dict__, name, '', 0)
814 r = doctest.DocTestRunner()
816 r.run(t, out=output.write)
817 return r.failures, output.getvalue()
820 class TestMatchesListwise(TestCase):
822 run_tests_with = FullStackRunTest
824 def test_docstring(self):
825 failure_count, output = run_doctest(
826 MatchesListwise, "MatchesListwise")
828 self.fail("Doctest failed with %s" % output)
831 class TestMatchesStructure(TestCase, TestMatchersInterface):
834 def __init__(self, x, y):
838 matches_matcher = MatchesStructure(x=Equals(1), y=Equals(2))
839 matches_matches = [SimpleClass(1, 2)]
840 matches_mismatches = [
847 ("MatchesStructure(x=Equals(1))", MatchesStructure(x=Equals(1))),
848 ("MatchesStructure(y=Equals(2))", MatchesStructure(y=Equals(2))),
849 ("MatchesStructure(x=Equals(1), y=Equals(2))",
850 MatchesStructure(x=Equals(1), y=Equals(2))),
853 describe_examples = [
857 ]""", SimpleClass(1, 2), MatchesStructure(x=Equals(3), y=Equals(2))),
861 ]""", SimpleClass(1, 2), MatchesStructure(x=Equals(1), y=Equals(3))),
866 ]""", SimpleClass(1, 2), MatchesStructure(x=Equals(0), y=Equals(0))),
869 def test_fromExample(self):
871 self.SimpleClass(1, 2),
872 MatchesStructure.fromExample(self.SimpleClass(1, 3), 'x'))
874 def test_byEquality(self):
876 self.SimpleClass(1, 2),
877 MatchesStructure.byEquality(x=1))
879 def test_withStructure(self):
881 self.SimpleClass(1, 2),
882 MatchesStructure.byMatcher(LessThan, x=2))
884 def test_update(self):
886 self.SimpleClass(1, 2),
887 MatchesStructure(x=NotEquals(1)).update(x=Equals(1)))
889 def test_update_none(self):
891 self.SimpleClass(1, 2),
892 MatchesStructure(x=Equals(1), z=NotEquals(42)).update(
896 class TestMatchesRegex(TestCase, TestMatchersInterface):
898 matches_matcher = MatchesRegex('a|b')
899 matches_matches = ['a', 'b']
900 matches_mismatches = ['c']
903 ("MatchesRegex('a|b')", MatchesRegex('a|b')),
904 ("MatchesRegex('a|b', re.M)", MatchesRegex('a|b', re.M)),
905 ("MatchesRegex('a|b', re.I|re.M)", MatchesRegex('a|b', re.I|re.M)),
906 ("MatchesRegex(%r)" % (_b("\xA7"),), MatchesRegex(_b("\xA7"))),
907 ("MatchesRegex(%r)" % (_u("\xA7"),), MatchesRegex(_u("\xA7"))),
910 describe_examples = [
911 ("'c' does not match /a|b/", 'c', MatchesRegex('a|b')),
912 ("'c' does not match /a\d/", 'c', MatchesRegex(r'a\d')),
913 ("%r does not match /\\s+\\xa7/" % (_b('c'),),
914 _b('c'), MatchesRegex(_b("\\s+\xA7"))),
915 ("%r does not match /\\s+\\xa7/" % (_u('c'),),
916 _u('c'), MatchesRegex(_u("\\s+\xA7"))),
920 class TestMatchesSetwise(TestCase):
922 run_tests_with = FullStackRunTest
924 def assertMismatchWithDescriptionMatching(self, value, matcher,
925 description_matcher):
926 mismatch = matcher.match(value)
928 self.fail("%s matched %s" % (matcher, value))
929 actual_description = mismatch.describe()
933 "%s matching %s" % (matcher, value),
934 description_matcher))
936 def test_matches(self):
938 None, MatchesSetwise(Equals(1), Equals(2)).match([2, 1]))
940 def test_mismatches(self):
941 self.assertMismatchWithDescriptionMatching(
942 [2, 3], MatchesSetwise(Equals(1), Equals(2)),
943 MatchesRegex('.*There was 1 mismatch$', re.S))
945 def test_too_many_matchers(self):
946 self.assertMismatchWithDescriptionMatching(
947 [2, 3], MatchesSetwise(Equals(1), Equals(2), Equals(3)),
948 Equals('There was 1 matcher left over: Equals(1)'))
950 def test_too_many_values(self):
951 self.assertMismatchWithDescriptionMatching(
952 [1, 2, 3], MatchesSetwise(Equals(1), Equals(2)),
953 Equals('There was 1 value left over: [3]'))
955 def test_two_too_many_matchers(self):
956 self.assertMismatchWithDescriptionMatching(
957 [3], MatchesSetwise(Equals(1), Equals(2), Equals(3)),
959 'There were 2 matchers left over: Equals\([12]\), '
962 def test_two_too_many_values(self):
963 self.assertMismatchWithDescriptionMatching(
964 [1, 2, 3, 4], MatchesSetwise(Equals(1), Equals(2)),
966 'There were 2 values left over: \[[34], [34]\]'))
968 def test_mismatch_and_too_many_matchers(self):
969 self.assertMismatchWithDescriptionMatching(
970 [2, 3], MatchesSetwise(Equals(0), Equals(1), Equals(2)),
972 '.*There was 1 mismatch and 1 extra matcher: Equals\([01]\)',
975 def test_mismatch_and_too_many_values(self):
976 self.assertMismatchWithDescriptionMatching(
977 [2, 3, 4], MatchesSetwise(Equals(1), Equals(2)),
979 '.*There was 1 mismatch and 1 extra value: \[[34]\]',
982 def test_mismatch_and_two_too_many_matchers(self):
983 self.assertMismatchWithDescriptionMatching(
984 [3, 4], MatchesSetwise(
985 Equals(0), Equals(1), Equals(2), Equals(3)),
987 '.*There was 1 mismatch and 2 extra matchers: '
988 'Equals\([012]\), Equals\([012]\)', re.S))
990 def test_mismatch_and_two_too_many_values(self):
991 self.assertMismatchWithDescriptionMatching(
992 [2, 3, 4, 5], MatchesSetwise(Equals(1), Equals(2)),
994 '.*There was 1 mismatch and 2 extra values: \[[145], [145]\]',
998 class TestAfterPreprocessing(TestCase, TestMatchersInterface):
1003 matches_matcher = AfterPreprocessing(parity, Equals(1))
1004 matches_matches = [3, 5]
1005 matches_mismatches = [2]
1008 ("AfterPreprocessing(<function parity>, Equals(1))",
1009 AfterPreprocessing(parity, Equals(1))),
1012 describe_examples = [
1013 ("1 != 0: after <function parity> on 2", 2,
1014 AfterPreprocessing(parity, Equals(1))),
1016 AfterPreprocessing(parity, Equals(1), annotate=False)),
1020 class TestMismatchDecorator(TestCase):
1022 run_tests_with = FullStackRunTest
1024 def test_forwards_description(self):
1025 x = Mismatch("description", {'foo': 'bar'})
1026 decorated = MismatchDecorator(x)
1027 self.assertEqual(x.describe(), decorated.describe())
1029 def test_forwards_details(self):
1030 x = Mismatch("description", {'foo': 'bar'})
1031 decorated = MismatchDecorator(x)
1032 self.assertEqual(x.get_details(), decorated.get_details())
1034 def test_repr(self):
1035 x = Mismatch("description", {'foo': 'bar'})
1036 decorated = MismatchDecorator(x)
1038 '<testtools.matchers.MismatchDecorator(%r)>' % (x,),
1042 class TestAllMatch(TestCase, TestMatchersInterface):
1044 matches_matcher = AllMatch(LessThan(10))
1048 iter([9, 9, 9, 9, 9]),
1050 matches_mismatches = [
1052 iter([9, 12, 9, 11]),
1056 ("AllMatch(LessThan(12))", AllMatch(LessThan(12))),
1059 describe_examples = [
1065 AllMatch(LessThan(10))),
1070 from unittest import TestLoader
1071 return TestLoader().loadTestsFromName(__name__)