testtools: Update to latest version.
[metze/samba/wip.git] / lib / testtools / testtools / tests / matchers / test_datastructures.py
1 # Copyright (c) 2008-2012 testtools developers. See LICENSE for details.
2
3 import doctest
4 import re
5 import sys
6
7 from testtools import TestCase
8 from testtools.compat import StringIO
9 from testtools.matchers import (
10     Annotate,
11     Equals,
12     LessThan,
13     MatchesRegex,
14     NotEquals,
15     )
16 from testtools.matchers._datastructures import (
17     ContainsAll,
18     MatchesListwise,
19     MatchesStructure,
20     MatchesSetwise,
21     )
22 from testtools.tests.helpers import FullStackRunTest
23 from testtools.tests.matchers.helpers import TestMatchersInterface
24
25
26 def run_doctest(obj, name):
27     p = doctest.DocTestParser()
28     t = p.get_doctest(
29         obj.__doc__, sys.modules[obj.__module__].__dict__, name, '', 0)
30     r = doctest.DocTestRunner()
31     output = StringIO()
32     r.run(t, out=output.write)
33     return r.failures, output.getvalue()
34
35
36 class TestMatchesListwise(TestCase):
37
38     run_tests_with = FullStackRunTest
39
40     def test_docstring(self):
41         failure_count, output = run_doctest(
42             MatchesListwise, "MatchesListwise")
43         if failure_count:
44             self.fail("Doctest failed with %s" % output)
45
46
47 class TestMatchesStructure(TestCase, TestMatchersInterface):
48
49     class SimpleClass:
50         def __init__(self, x, y):
51             self.x = x
52             self.y = y
53
54     matches_matcher = MatchesStructure(x=Equals(1), y=Equals(2))
55     matches_matches = [SimpleClass(1, 2)]
56     matches_mismatches = [
57         SimpleClass(2, 2),
58         SimpleClass(1, 1),
59         SimpleClass(3, 3),
60         ]
61
62     str_examples = [
63         ("MatchesStructure(x=Equals(1))", MatchesStructure(x=Equals(1))),
64         ("MatchesStructure(y=Equals(2))", MatchesStructure(y=Equals(2))),
65         ("MatchesStructure(x=Equals(1), y=Equals(2))",
66          MatchesStructure(x=Equals(1), y=Equals(2))),
67         ]
68
69     describe_examples = [
70         ("""\
71 Differences: [
72 3 != 1: x
73 ]""", SimpleClass(1, 2), MatchesStructure(x=Equals(3), y=Equals(2))),
74         ("""\
75 Differences: [
76 3 != 2: y
77 ]""", SimpleClass(1, 2), MatchesStructure(x=Equals(1), y=Equals(3))),
78         ("""\
79 Differences: [
80 0 != 1: x
81 0 != 2: y
82 ]""", SimpleClass(1, 2), MatchesStructure(x=Equals(0), y=Equals(0))),
83         ]
84
85     def test_fromExample(self):
86         self.assertThat(
87             self.SimpleClass(1, 2),
88             MatchesStructure.fromExample(self.SimpleClass(1, 3), 'x'))
89
90     def test_byEquality(self):
91         self.assertThat(
92             self.SimpleClass(1, 2),
93             MatchesStructure.byEquality(x=1))
94
95     def test_withStructure(self):
96         self.assertThat(
97             self.SimpleClass(1, 2),
98             MatchesStructure.byMatcher(LessThan, x=2))
99
100     def test_update(self):
101         self.assertThat(
102             self.SimpleClass(1, 2),
103             MatchesStructure(x=NotEquals(1)).update(x=Equals(1)))
104
105     def test_update_none(self):
106         self.assertThat(
107             self.SimpleClass(1, 2),
108             MatchesStructure(x=Equals(1), z=NotEquals(42)).update(
109                 z=None))
110
111
112 class TestMatchesSetwise(TestCase):
113
114     run_tests_with = FullStackRunTest
115
116     def assertMismatchWithDescriptionMatching(self, value, matcher,
117                                               description_matcher):
118         mismatch = matcher.match(value)
119         if mismatch is None:
120             self.fail("%s matched %s" % (matcher, value))
121         actual_description = mismatch.describe()
122         self.assertThat(
123             actual_description,
124             Annotate(
125                 "%s matching %s" % (matcher, value),
126                 description_matcher))
127
128     def test_matches(self):
129         self.assertIs(
130             None, MatchesSetwise(Equals(1), Equals(2)).match([2, 1]))
131
132     def test_mismatches(self):
133         self.assertMismatchWithDescriptionMatching(
134             [2, 3], MatchesSetwise(Equals(1), Equals(2)),
135             MatchesRegex('.*There was 1 mismatch$', re.S))
136
137     def test_too_many_matchers(self):
138         self.assertMismatchWithDescriptionMatching(
139             [2, 3], MatchesSetwise(Equals(1), Equals(2), Equals(3)),
140             Equals('There was 1 matcher left over: Equals(1)'))
141
142     def test_too_many_values(self):
143         self.assertMismatchWithDescriptionMatching(
144             [1, 2, 3], MatchesSetwise(Equals(1), Equals(2)),
145             Equals('There was 1 value left over: [3]'))
146
147     def test_two_too_many_matchers(self):
148         self.assertMismatchWithDescriptionMatching(
149             [3], MatchesSetwise(Equals(1), Equals(2), Equals(3)),
150             MatchesRegex(
151                 'There were 2 matchers left over: Equals\([12]\), '
152                 'Equals\([12]\)'))
153
154     def test_two_too_many_values(self):
155         self.assertMismatchWithDescriptionMatching(
156             [1, 2, 3, 4], MatchesSetwise(Equals(1), Equals(2)),
157             MatchesRegex(
158                 'There were 2 values left over: \[[34], [34]\]'))
159
160     def test_mismatch_and_too_many_matchers(self):
161         self.assertMismatchWithDescriptionMatching(
162             [2, 3], MatchesSetwise(Equals(0), Equals(1), Equals(2)),
163             MatchesRegex(
164                 '.*There was 1 mismatch and 1 extra matcher: Equals\([01]\)',
165                 re.S))
166
167     def test_mismatch_and_too_many_values(self):
168         self.assertMismatchWithDescriptionMatching(
169             [2, 3, 4], MatchesSetwise(Equals(1), Equals(2)),
170             MatchesRegex(
171                 '.*There was 1 mismatch and 1 extra value: \[[34]\]',
172                 re.S))
173
174     def test_mismatch_and_two_too_many_matchers(self):
175         self.assertMismatchWithDescriptionMatching(
176             [3, 4], MatchesSetwise(
177                 Equals(0), Equals(1), Equals(2), Equals(3)),
178             MatchesRegex(
179                 '.*There was 1 mismatch and 2 extra matchers: '
180                 'Equals\([012]\), Equals\([012]\)', re.S))
181
182     def test_mismatch_and_two_too_many_values(self):
183         self.assertMismatchWithDescriptionMatching(
184             [2, 3, 4, 5], MatchesSetwise(Equals(1), Equals(2)),
185             MatchesRegex(
186                 '.*There was 1 mismatch and 2 extra values: \[[145], [145]\]',
187                 re.S))
188
189
190 class TestContainsAllInterface(TestCase, TestMatchersInterface):
191
192     matches_matcher = ContainsAll(['foo', 'bar'])
193     matches_matches = [['foo', 'bar'], ['foo', 'z', 'bar'], ['bar', 'foo']]
194     matches_mismatches = [['f', 'g'], ['foo', 'baz'], []]
195
196     str_examples = [(
197         "MatchesAll(Contains('foo'), Contains('bar'))",
198         ContainsAll(['foo', 'bar'])),
199         ]
200
201     describe_examples = [("""Differences: [
202 'baz' not in 'foo'
203 ]""",
204     'foo', ContainsAll(['foo', 'baz']))]
205
206
207 def test_suite():
208     from unittest import TestLoader
209     return TestLoader().loadTestsFromName(__name__)