Initialize the file descriptor in the files_struct before trying to close it. Otherwi...
[Samba/gebeck_regimport.git] / lib / testtools / testtools / matchers / _basic.py
blob44a47c566b00c27b4a57a68009d82e2cd496d84b
1 # Copyright (c) 2009-2012 testtools developers. See LICENSE for details.
3 __all__ = [
4 'Contains',
5 'EndsWith',
6 'Equals',
7 'GreaterThan',
8 'Is',
9 'IsInstance',
10 'LessThan',
11 'MatchesRegex',
12 'NotEquals',
13 'StartsWith',
16 import operator
17 from pprint import pformat
18 import re
20 from ..compat import (
21 _isbytes,
22 istext,
23 str_is_unicode,
24 text_repr,
26 from ..helpers import list_subtract
27 from ._higherorder import PostfixedMismatch
28 from ._impl import (
29 Matcher,
30 Mismatch,
34 def _format(thing):
35 """
36 Blocks of text with newlines are formatted as triple-quote
37 strings. Everything else is pretty-printed.
38 """
39 if istext(thing) or _isbytes(thing):
40 return text_repr(thing)
41 return pformat(thing)
44 class _BinaryComparison(object):
45 """Matcher that compares an object to another object."""
47 def __init__(self, expected):
48 self.expected = expected
50 def __str__(self):
51 return "%s(%r)" % (self.__class__.__name__, self.expected)
53 def match(self, other):
54 if self.comparator(other, self.expected):
55 return None
56 return _BinaryMismatch(self.expected, self.mismatch_string, other)
58 def comparator(self, expected, other):
59 raise NotImplementedError(self.comparator)
62 class _BinaryMismatch(Mismatch):
63 """Two things did not match."""
65 def __init__(self, expected, mismatch_string, other):
66 self.expected = expected
67 self._mismatch_string = mismatch_string
68 self.other = other
70 def describe(self):
71 left = repr(self.expected)
72 right = repr(self.other)
73 if len(left) + len(right) > 70:
74 return "%s:\nreference = %s\nactual = %s\n" % (
75 self._mismatch_string, _format(self.expected),
76 _format(self.other))
77 else:
78 return "%s %s %s" % (left, self._mismatch_string, right)
81 class Equals(_BinaryComparison):
82 """Matches if the items are equal."""
84 comparator = operator.eq
85 mismatch_string = '!='
88 class NotEquals(_BinaryComparison):
89 """Matches if the items are not equal.
91 In most cases, this is equivalent to ``Not(Equals(foo))``. The difference
92 only matters when testing ``__ne__`` implementations.
93 """
95 comparator = operator.ne
96 mismatch_string = '=='
99 class Is(_BinaryComparison):
100 """Matches if the items are identical."""
102 comparator = operator.is_
103 mismatch_string = 'is not'
106 class LessThan(_BinaryComparison):
107 """Matches if the item is less than the matchers reference object."""
109 comparator = operator.__lt__
110 mismatch_string = 'is not >'
113 class GreaterThan(_BinaryComparison):
114 """Matches if the item is greater than the matchers reference object."""
116 comparator = operator.__gt__
117 mismatch_string = 'is not <'
120 class SameMembers(Matcher):
121 """Matches if two iterators have the same members.
123 This is not the same as set equivalence. The two iterators must be of the
124 same length and have the same repetitions.
127 def __init__(self, expected):
128 super(SameMembers, self).__init__()
129 self.expected = expected
131 def __str__(self):
132 return '%s(%r)' % (self.__class__.__name__, self.expected)
134 def match(self, observed):
135 expected_only = list_subtract(self.expected, observed)
136 observed_only = list_subtract(observed, self.expected)
137 if expected_only == observed_only == []:
138 return
139 return PostfixedMismatch(
140 "\nmissing: %s\nextra: %s" % (
141 _format(expected_only), _format(observed_only)),
142 _BinaryMismatch(self.expected, 'elements differ', observed))
145 class DoesNotStartWith(Mismatch):
147 def __init__(self, matchee, expected):
148 """Create a DoesNotStartWith Mismatch.
150 :param matchee: the string that did not match.
151 :param expected: the string that 'matchee' was expected to start with.
153 self.matchee = matchee
154 self.expected = expected
156 def describe(self):
157 return "%s does not start with %s." % (
158 text_repr(self.matchee), text_repr(self.expected))
161 class StartsWith(Matcher):
162 """Checks whether one string starts with another."""
164 def __init__(self, expected):
165 """Create a StartsWith Matcher.
167 :param expected: the string that matchees should start with.
169 self.expected = expected
171 def __str__(self):
172 return "StartsWith(%r)" % (self.expected,)
174 def match(self, matchee):
175 if not matchee.startswith(self.expected):
176 return DoesNotStartWith(matchee, self.expected)
177 return None
180 class DoesNotEndWith(Mismatch):
182 def __init__(self, matchee, expected):
183 """Create a DoesNotEndWith Mismatch.
185 :param matchee: the string that did not match.
186 :param expected: the string that 'matchee' was expected to end with.
188 self.matchee = matchee
189 self.expected = expected
191 def describe(self):
192 return "%s does not end with %s." % (
193 text_repr(self.matchee), text_repr(self.expected))
196 class EndsWith(Matcher):
197 """Checks whether one string ends with another."""
199 def __init__(self, expected):
200 """Create a EndsWith Matcher.
202 :param expected: the string that matchees should end with.
204 self.expected = expected
206 def __str__(self):
207 return "EndsWith(%r)" % (self.expected,)
209 def match(self, matchee):
210 if not matchee.endswith(self.expected):
211 return DoesNotEndWith(matchee, self.expected)
212 return None
215 class IsInstance(object):
216 """Matcher that wraps isinstance."""
218 def __init__(self, *types):
219 self.types = tuple(types)
221 def __str__(self):
222 return "%s(%s)" % (self.__class__.__name__,
223 ', '.join(type.__name__ for type in self.types))
225 def match(self, other):
226 if isinstance(other, self.types):
227 return None
228 return NotAnInstance(other, self.types)
231 class NotAnInstance(Mismatch):
233 def __init__(self, matchee, types):
234 """Create a NotAnInstance Mismatch.
236 :param matchee: the thing which is not an instance of any of types.
237 :param types: A tuple of the types which were expected.
239 self.matchee = matchee
240 self.types = types
242 def describe(self):
243 if len(self.types) == 1:
244 typestr = self.types[0].__name__
245 else:
246 typestr = 'any of (%s)' % ', '.join(type.__name__ for type in
247 self.types)
248 return "'%s' is not an instance of %s" % (self.matchee, typestr)
251 class DoesNotContain(Mismatch):
253 def __init__(self, matchee, needle):
254 """Create a DoesNotContain Mismatch.
256 :param matchee: the object that did not contain needle.
257 :param needle: the needle that 'matchee' was expected to contain.
259 self.matchee = matchee
260 self.needle = needle
262 def describe(self):
263 return "%r not in %r" % (self.needle, self.matchee)
266 class Contains(Matcher):
267 """Checks whether something is contained in another thing."""
269 def __init__(self, needle):
270 """Create a Contains Matcher.
272 :param needle: the thing that needs to be contained by matchees.
274 self.needle = needle
276 def __str__(self):
277 return "Contains(%r)" % (self.needle,)
279 def match(self, matchee):
280 try:
281 if self.needle not in matchee:
282 return DoesNotContain(matchee, self.needle)
283 except TypeError:
284 # e.g. 1 in 2 will raise TypeError
285 return DoesNotContain(matchee, self.needle)
286 return None
289 class MatchesRegex(object):
290 """Matches if the matchee is matched by a regular expression."""
292 def __init__(self, pattern, flags=0):
293 self.pattern = pattern
294 self.flags = flags
296 def __str__(self):
297 args = ['%r' % self.pattern]
298 flag_arg = []
299 # dir() sorts the attributes for us, so we don't need to do it again.
300 for flag in dir(re):
301 if len(flag) == 1:
302 if self.flags & getattr(re, flag):
303 flag_arg.append('re.%s' % flag)
304 if flag_arg:
305 args.append('|'.join(flag_arg))
306 return '%s(%s)' % (self.__class__.__name__, ', '.join(args))
308 def match(self, value):
309 if not re.match(self.pattern, value, self.flags):
310 pattern = self.pattern
311 if not isinstance(pattern, str_is_unicode and str or unicode):
312 pattern = pattern.decode("latin1")
313 pattern = pattern.encode("unicode_escape").decode("ascii")
314 return Mismatch("%r does not match /%s/" % (
315 value, pattern.replace("\\\\", "\\")))