~testtools-dev/testtools/trunk

« back to all changes in this revision

Viewing changes to testtools/tests/test_matchers.py

Merge heroic branch that makes unicode actually work!

Show diffs side-by-side

added added

removed removed

Lines of Context:
12
12
    )
13
13
from testtools.compat import (
14
14
    StringIO,
 
15
    str_is_unicode,
 
16
    text_repr,
 
17
    _b,
15
18
    _u,
16
19
    )
17
20
from testtools.matchers import (
19
22
    AllMatch,
20
23
    Annotate,
21
24
    AnnotatedMismatch,
 
25
    _BinaryMismatch,
22
26
    Contains,
23
27
    Equals,
24
28
    DocTestMatches,
39
43
    MatchesStructure,
40
44
    Mismatch,
41
45
    MismatchDecorator,
 
46
    MismatchError,
42
47
    Not,
43
48
    NotEquals,
44
49
    Raises,
67
72
        self.assertEqual({}, mismatch.get_details())
68
73
 
69
74
 
 
75
class TestMismatchError(TestCase):
 
76
 
 
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)
 
83
 
 
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))
 
88
 
 
89
    def test_default_description_unicode(self):
 
90
        matchee = _u('\xa7')
 
91
        matcher = Equals(_u('a'))
 
92
        mismatch = matcher.match(matchee)
 
93
        e = MismatchError(matchee, matcher, mismatch)
 
94
        self.assertEqual(mismatch.describe(), str(e))
 
95
 
 
96
    def test_verbose_description(self):
 
97
        matchee = 2
 
98
        matcher = Equals(3)
 
99
        mismatch = matcher.match(2)
 
100
        e = MismatchError(matchee, matcher, mismatch, True)
 
101
        expected = (
 
102
            'Match failed. Matchee: %r\n'
 
103
            'Matcher: %s\n'
 
104
            'Difference: %s\n' % (
 
105
                matchee,
 
106
                matcher,
 
107
                matcher.match(matchee).describe(),
 
108
                ))
 
109
        self.assertEqual(expected, str(e))
 
110
 
 
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.
 
114
        matchee = _u('\xa7')
 
115
        matcher = Equals(_u('a'))
 
116
        mismatch = matcher.match(matchee)
 
117
        expected = (
 
118
            'Match failed. Matchee: %s\n'
 
119
            'Matcher: %s\n'
 
120
            'Difference: %s\n' % (
 
121
                text_repr(matchee),
 
122
                matcher,
 
123
                mismatch.describe(),
 
124
                ))
 
125
        e = MismatchError(matchee, matcher, mismatch, True)
 
126
        if str_is_unicode:
 
127
            actual = str(e)
 
128
        else:
 
129
            actual = unicode(e)
 
130
            # Using str() should still work, and return ascii only
 
131
            self.assertEqual(
 
132
                expected.replace(matchee, matchee.encode("unicode-escape")),
 
133
                str(e).decode("ascii"))
 
134
        self.assertEqual(expected, actual)
 
135
 
 
136
 
 
137
class Test_BinaryMismatch(TestCase):
 
138
    """Mismatches from binary comparisons need useful describe output"""
 
139
 
 
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)
 
143
 
 
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))
 
148
 
 
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))
 
153
 
 
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)))
 
161
 
 
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)))
 
169
 
 
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)))
 
176
 
 
177
    def test_long_bytes_and_object(self):
 
178
        obj = object()
 
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),
 
183
                repr(obj)))
 
184
 
 
185
    def test_long_unicode_and_object(self):
 
186
        obj = object()
 
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),
 
191
                repr(obj)))
 
192
 
 
193
 
70
194
class TestMatchersInterface(object):
71
195
 
72
196
    run_tests_with = FullStackRunTest
150
274
        self.assertEqual("bar\n", matcher.want)
151
275
        self.assertEqual(doctest.ELLIPSIS, matcher.flags)
152
276
 
 
277
    def test_describe_non_ascii_bytes(self):
 
278
        """Even with bytestrings, the mismatch should be coercible to unicode
 
279
 
 
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.
 
283
        """
 
284
        header = _b("\x89PNG\r\n\x1a\n...")
 
285
        if str_is_unicode:
 
286
            self.assertRaises(TypeError,
 
287
                DocTestMatches, header, doctest.ELLIPSIS)
 
288
            return
 
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()))
 
293
 
153
294
 
154
295
class TestEqualsInterface(TestCase, TestMatchersInterface):
155
296
 
552
693
        mismatch = DoesNotStartWith("fo", "bo")
553
694
        self.assertEqual("'fo' does not start with 'bo'.", mismatch.describe())
554
695
 
 
696
    def test_describe_non_ascii_unicode(self):
 
697
        string = _u("A\xA7")
 
698
        suffix = _u("B\xA7")
 
699
        mismatch = DoesNotStartWith(string, suffix)
 
700
        self.assertEqual("%s does not start with %s." % (
 
701
            text_repr(string), text_repr(suffix)),
 
702
            mismatch.describe())
 
703
 
 
704
    def test_describe_non_ascii_bytes(self):
 
705
        string = _b("A\xA7")
 
706
        suffix = _b("B\xA7")
 
707
        mismatch = DoesNotStartWith(string, suffix)
 
708
        self.assertEqual("%r does not start with %r." % (string, suffix),
 
709
            mismatch.describe())
 
710
 
555
711
 
556
712
class StartsWithTests(TestCase):
557
713
 
559
715
 
560
716
    def test_str(self):
561
717
        matcher = StartsWith("bar")
562
 
        self.assertEqual("Starts with 'bar'.", str(matcher))
 
718
        self.assertEqual("StartsWith('bar')", str(matcher))
 
719
 
 
720
    def test_str_with_bytes(self):
 
721
        b = _b("\xA7")
 
722
        matcher = StartsWith(b)
 
723
        self.assertEqual("StartsWith(%r)" % (b,), str(matcher))
 
724
 
 
725
    def test_str_with_unicode(self):
 
726
        u = _u("\xA7")
 
727
        matcher = StartsWith(u)
 
728
        self.assertEqual("StartsWith(%r)" % (u,), str(matcher))
563
729
 
564
730
    def test_match(self):
565
731
        matcher = StartsWith("bar")
588
754
        mismatch = DoesNotEndWith("fo", "bo")
589
755
        self.assertEqual("'fo' does not end with 'bo'.", mismatch.describe())
590
756
 
 
757
    def test_describe_non_ascii_unicode(self):
 
758
        string = _u("A\xA7")
 
759
        suffix = _u("B\xA7")
 
760
        mismatch = DoesNotEndWith(string, suffix)
 
761
        self.assertEqual("%s does not end with %s." % (
 
762
            text_repr(string), text_repr(suffix)),
 
763
            mismatch.describe())
 
764
 
 
765
    def test_describe_non_ascii_bytes(self):
 
766
        string = _b("A\xA7")
 
767
        suffix = _b("B\xA7")
 
768
        mismatch = DoesNotEndWith(string, suffix)
 
769
        self.assertEqual("%r does not end with %r." % (string, suffix),
 
770
            mismatch.describe())
 
771
 
591
772
 
592
773
class EndsWithTests(TestCase):
593
774
 
595
776
 
596
777
    def test_str(self):
597
778
        matcher = EndsWith("bar")
598
 
        self.assertEqual("Ends with 'bar'.", str(matcher))
 
779
        self.assertEqual("EndsWith('bar')", str(matcher))
 
780
 
 
781
    def test_str_with_bytes(self):
 
782
        b = _b("\xA7")
 
783
        matcher = EndsWith(b)
 
784
        self.assertEqual("EndsWith(%r)" % (b,), str(matcher))
 
785
 
 
786
    def test_str_with_unicode(self):
 
787
        u = _u("\xA7")
 
788
        matcher = EndsWith(u)
 
789
        self.assertEqual("EndsWith(%r)" % (u,), str(matcher))
599
790
 
600
791
    def test_match(self):
601
792
        matcher = EndsWith("arf")
712
903
        ("MatchesRegex('a|b')", MatchesRegex('a|b')),
713
904
        ("MatchesRegex('a|b', re.M)", MatchesRegex('a|b', re.M)),
714
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"))),
715
908
        ]
716
909
 
717
910
    describe_examples = [
718
911
        ("'c' does not match /a|b/", 'c', MatchesRegex('a|b')),
719
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"))),
720
917
        ]
721
918
 
722
919