blob: ef0f16d82685bbfc99899d5da23e10a2509d5eff [file] [log] [blame]
Michael Foord1e68bec2012-03-03 22:24:30 +00001# Copyright (C) 2007-2012 Michael Foord & the mock team
2# E-mail: fuzzyman AT voidspace DOT org DOT uk
3# http://www.voidspace.org.uk/python/mock/
4
5from tests.support import unittest2, inPy3k
6
7try:
8 unicode
9except NameError:
10 # Python 3
11 unicode = str
12 long = int
13
14import inspect
15import sys
16from mock import Mock, MagicMock, _magics
17
18
19
20class TestMockingMagicMethods(unittest2.TestCase):
21
22 def test_deleting_magic_methods(self):
23 mock = Mock()
24 self.assertFalse(hasattr(mock, '__getitem__'))
25
26 mock.__getitem__ = Mock()
27 self.assertTrue(hasattr(mock, '__getitem__'))
28
29 del mock.__getitem__
30 self.assertFalse(hasattr(mock, '__getitem__'))
31
32
33 def test_magicmock_del(self):
34 mock = MagicMock()
35 # before using getitem
36 del mock.__getitem__
37 self.assertRaises(TypeError, lambda: mock['foo'])
38
39 mock = MagicMock()
40 # this time use it first
41 mock['foo']
42 del mock.__getitem__
43 self.assertRaises(TypeError, lambda: mock['foo'])
44
45
46 def test_magic_method_wrapping(self):
47 mock = Mock()
48 def f(self, name):
49 return self, 'fish'
50
51 mock.__getitem__ = f
52 self.assertFalse(mock.__getitem__ is f)
53 self.assertEqual(mock['foo'], (mock, 'fish'))
Michael Foorda9a8bb92012-03-13 14:39:59 -070054 self.assertEqual(mock.__getitem__('foo'), (mock, 'fish'))
Michael Foord1e68bec2012-03-03 22:24:30 +000055
56 mock.__getitem__ = mock
57 self.assertTrue(mock.__getitem__ is mock)
58
59
60 def test_magic_methods_isolated_between_mocks(self):
61 mock1 = Mock()
62 mock2 = Mock()
63
64 mock1.__iter__ = Mock(return_value=iter([]))
65 self.assertEqual(list(mock1), [])
66 self.assertRaises(TypeError, lambda: list(mock2))
67
68
69 def test_repr(self):
70 mock = Mock()
71 self.assertEqual(repr(mock), "<Mock id='%s'>" % id(mock))
72 mock.__repr__ = lambda s: 'foo'
73 self.assertEqual(repr(mock), 'foo')
74
75
76 def test_str(self):
77 mock = Mock()
78 self.assertEqual(str(mock), object.__str__(mock))
79 mock.__str__ = lambda s: 'foo'
80 self.assertEqual(str(mock), 'foo')
81
82
83 @unittest2.skipIf(inPy3k, "no unicode in Python 3")
84 def test_unicode(self):
85 mock = Mock()
86 self.assertEqual(unicode(mock), unicode(str(mock)))
87
88 mock.__unicode__ = lambda s: unicode('foo')
89 self.assertEqual(unicode(mock), unicode('foo'))
90
91
92 def test_dict_methods(self):
93 mock = Mock()
94
95 self.assertRaises(TypeError, lambda: mock['foo'])
96 def _del():
97 del mock['foo']
98 def _set():
99 mock['foo'] = 3
100 self.assertRaises(TypeError, _del)
101 self.assertRaises(TypeError, _set)
102
103 _dict = {}
104 def getitem(s, name):
105 return _dict[name]
106 def setitem(s, name, value):
107 _dict[name] = value
108 def delitem(s, name):
109 del _dict[name]
110
111 mock.__setitem__ = setitem
112 mock.__getitem__ = getitem
113 mock.__delitem__ = delitem
114
115 self.assertRaises(KeyError, lambda: mock['foo'])
116 mock['foo'] = 'bar'
117 self.assertEqual(_dict, {'foo': 'bar'})
118 self.assertEqual(mock['foo'], 'bar')
119 del mock['foo']
120 self.assertEqual(_dict, {})
121
122
123 def test_numeric(self):
124 original = mock = Mock()
125 mock.value = 0
126
127 self.assertRaises(TypeError, lambda: mock + 3)
128
129 def add(self, other):
130 mock.value += other
131 return self
132 mock.__add__ = add
133 self.assertEqual(mock + 3, mock)
134 self.assertEqual(mock.value, 3)
135
136 del mock.__add__
137 def iadd(mock):
138 mock += 3
139 self.assertRaises(TypeError, iadd, mock)
140 mock.__iadd__ = add
141 mock += 6
142 self.assertEqual(mock, original)
143 self.assertEqual(mock.value, 9)
144
145 self.assertRaises(TypeError, lambda: 3 + mock)
146 mock.__radd__ = add
147 self.assertEqual(7 + mock, mock)
148 self.assertEqual(mock.value, 16)
149
150
151 @unittest2.skipIf(inPy3k, 'no truediv in Python 3')
152 def test_truediv(self):
153 mock = MagicMock()
154 mock.__truediv__.return_value = 6
155
156 context = {'mock': mock}
157 code = 'from __future__ import division\nresult = mock / 7\n'
158 exec(code, context)
159 self.assertEqual(context['result'], 6)
160
161 mock.__rtruediv__.return_value = 3
162 code = 'from __future__ import division\nresult = 2 / mock\n'
163 exec(code, context)
164 self.assertEqual(context['result'], 3)
165
166
167 @unittest2.skipIf(not inPy3k, 'truediv is available in Python 2')
168 def test_no_truediv(self):
169 self.assertRaises(
170 AttributeError, getattr, MagicMock(), '__truediv__'
171 )
172 self.assertRaises(
173 AttributeError, getattr, MagicMock(), '__rtruediv__'
174 )
175
176
177 def test_hash(self):
178 mock = Mock()
179 # test delegation
180 self.assertEqual(hash(mock), Mock.__hash__(mock))
181
182 def _hash(s):
183 return 3
184 mock.__hash__ = _hash
185 self.assertEqual(hash(mock), 3)
186
187
188 def test_nonzero(self):
189 m = Mock()
190 self.assertTrue(bool(m))
191
192 nonzero = lambda s: False
193 if not inPy3k:
194 m.__nonzero__ = nonzero
195 else:
196 m.__bool__ = nonzero
197
198 self.assertFalse(bool(m))
199
200
201 def test_comparison(self):
202 # note: this test fails with Jython 2.5.1 due to a Jython bug
203 # it is fixed in jython 2.5.2
204 if not inPy3k:
205 # incomparable in Python 3
206 self. assertEqual(Mock() < 3, object() < 3)
207 self. assertEqual(Mock() > 3, object() > 3)
208 self. assertEqual(Mock() <= 3, object() <= 3)
209 self. assertEqual(Mock() >= 3, object() >= 3)
Michael Foord62dd80f2012-03-17 17:37:22 -0700210 else:
211 self.assertRaises(TypeError, lambda: MagicMock() < object())
212 self.assertRaises(TypeError, lambda: object() < MagicMock())
213 self.assertRaises(TypeError, lambda: MagicMock() < MagicMock())
214 self.assertRaises(TypeError, lambda: MagicMock() > object())
215 self.assertRaises(TypeError, lambda: object() > MagicMock())
216 self.assertRaises(TypeError, lambda: MagicMock() > MagicMock())
217 self.assertRaises(TypeError, lambda: MagicMock() <= object())
218 self.assertRaises(TypeError, lambda: object() <= MagicMock())
219 self.assertRaises(TypeError, lambda: MagicMock() <= MagicMock())
220 self.assertRaises(TypeError, lambda: MagicMock() >= object())
221 self.assertRaises(TypeError, lambda: object() >= MagicMock())
222 self.assertRaises(TypeError, lambda: MagicMock() >= MagicMock())
Michael Foord1e68bec2012-03-03 22:24:30 +0000223
224 mock = Mock()
225 def comp(s, o):
226 return True
227 mock.__lt__ = mock.__gt__ = mock.__le__ = mock.__ge__ = comp
228 self. assertTrue(mock < 3)
229 self. assertTrue(mock > 3)
230 self. assertTrue(mock <= 3)
231 self. assertTrue(mock >= 3)
232
233
234 def test_equality(self):
235 for mock in Mock(), MagicMock():
236 self.assertEqual(mock == mock, True)
237 self.assertIsInstance(mock == mock, bool)
238 self.assertEqual(mock != mock, False)
239 self.assertIsInstance(mock != mock, bool)
240 self.assertEqual(mock == object(), False)
241 self.assertEqual(mock != object(), True)
242
243 def eq(self, other):
244 return other == 3
245 mock.__eq__ = eq
246 self.assertTrue(mock == 3)
247 self.assertFalse(mock == 4)
248
249 def ne(self, other):
250 return other == 3
251 mock.__ne__ = ne
252 self.assertTrue(mock != 3)
253 self.assertFalse(mock != 4)
254
255 mock = MagicMock()
256 mock.__eq__.return_value = True
257 self.assertIsInstance(mock == 3, bool)
258 self.assertEqual(mock == 3, True)
259
260 mock.__ne__.return_value = False
261 self.assertIsInstance(mock != 3, bool)
262 self.assertEqual(mock != 3, False)
263
264
265 def test_len_contains_iter(self):
266 mock = Mock()
267
268 self.assertRaises(TypeError, len, mock)
269 self.assertRaises(TypeError, iter, mock)
270 self.assertRaises(TypeError, lambda: 'foo' in mock)
271
272 mock.__len__ = lambda s: 6
273 self.assertEqual(len(mock), 6)
274
275 mock.__contains__ = lambda s, o: o == 3
276 self.assertTrue(3 in mock)
277 self.assertFalse(6 in mock)
278
279 mock.__iter__ = lambda s: iter('foobarbaz')
280 self.assertEqual(list(mock), list('foobarbaz'))
281
282
283 def test_magicmock(self):
284 mock = MagicMock()
285
286 mock.__iter__.return_value = iter([1, 2, 3])
287 self.assertEqual(list(mock), [1, 2, 3])
288
289 name = '__nonzero__'
290 other = '__bool__'
291 if inPy3k:
292 name, other = other, name
293 getattr(mock, name).return_value = False
294 self.assertFalse(hasattr(mock, other))
295 self.assertFalse(bool(mock))
296
297 for entry in _magics:
298 self.assertTrue(hasattr(mock, entry))
299 self.assertFalse(hasattr(mock, '__imaginery__'))
300
301
302 def test_magic_mock_equality(self):
303 mock = MagicMock()
304 self.assertIsInstance(mock == object(), bool)
305 self.assertIsInstance(mock != object(), bool)
306
307 self.assertEqual(mock == object(), False)
308 self.assertEqual(mock != object(), True)
309 self.assertEqual(mock == mock, True)
310 self.assertEqual(mock != mock, False)
311
312
313 def test_magicmock_defaults(self):
314 mock = MagicMock()
315 self.assertEqual(int(mock), 1)
316 self.assertEqual(complex(mock), 1j)
317 self.assertEqual(float(mock), 1.0)
318 self.assertEqual(long(mock), long(1))
319 self.assertNotIn(object(), mock)
320 self.assertEqual(len(mock), 0)
321 self.assertEqual(list(mock), [])
322 self.assertEqual(hash(mock), object.__hash__(mock))
323 self.assertEqual(str(mock), object.__str__(mock))
324 self.assertEqual(unicode(mock), object.__str__(mock))
325 self.assertIsInstance(unicode(mock), unicode)
326 self.assertTrue(bool(mock))
327 if not inPy3k:
328 self.assertEqual(oct(mock), '1')
329 else:
330 # in Python 3 oct and hex use __index__
331 # so these tests are for __index__ in py3k
332 self.assertEqual(oct(mock), '0o1')
333 self.assertEqual(hex(mock), '0x1')
334 # how to test __sizeof__ ?
335
336
337 @unittest2.skipIf(inPy3k, "no __cmp__ in Python 3")
338 def test_non_default_magic_methods(self):
339 mock = MagicMock()
340 self.assertRaises(AttributeError, lambda: mock.__cmp__)
341
342 mock = Mock()
343 mock.__cmp__ = lambda s, o: 0
344
345 self.assertEqual(mock, object())
346
347
348 def test_magic_methods_and_spec(self):
349 class Iterable(object):
350 def __iter__(self):
351 pass
352
353 mock = Mock(spec=Iterable)
354 self.assertRaises(AttributeError, lambda: mock.__iter__)
355
356 mock.__iter__ = Mock(return_value=iter([]))
357 self.assertEqual(list(mock), [])
358
359 class NonIterable(object):
360 pass
361 mock = Mock(spec=NonIterable)
362 self.assertRaises(AttributeError, lambda: mock.__iter__)
363
364 def set_int():
365 mock.__int__ = Mock(return_value=iter([]))
366 self.assertRaises(AttributeError, set_int)
367
368 mock = MagicMock(spec=Iterable)
369 self.assertEqual(list(mock), [])
370 self.assertRaises(AttributeError, set_int)
371
372
373 def test_magic_methods_and_spec_set(self):
374 class Iterable(object):
375 def __iter__(self):
376 pass
377
378 mock = Mock(spec_set=Iterable)
379 self.assertRaises(AttributeError, lambda: mock.__iter__)
380
381 mock.__iter__ = Mock(return_value=iter([]))
382 self.assertEqual(list(mock), [])
383
384 class NonIterable(object):
385 pass
386 mock = Mock(spec_set=NonIterable)
387 self.assertRaises(AttributeError, lambda: mock.__iter__)
388
389 def set_int():
390 mock.__int__ = Mock(return_value=iter([]))
391 self.assertRaises(AttributeError, set_int)
392
393 mock = MagicMock(spec_set=Iterable)
394 self.assertEqual(list(mock), [])
395 self.assertRaises(AttributeError, set_int)
396
397
398 def test_setting_unsupported_magic_method(self):
399 mock = MagicMock()
400 def set_setattr():
401 mock.__setattr__ = lambda self, name: None
402 self.assertRaisesRegexp(AttributeError,
403 "Attempting to set unsupported magic method '__setattr__'.",
404 set_setattr
405 )
406
407
408 def test_attributes_and_return_value(self):
409 mock = MagicMock()
410 attr = mock.foo
411 def _get_type(obj):
412 # the type of every mock (or magicmock) is a custom subclass
413 # so the real type is the second in the mro
414 return type(obj).__mro__[1]
415 self.assertEqual(_get_type(attr), MagicMock)
416
417 returned = mock()
418 self.assertEqual(_get_type(returned), MagicMock)
419
420
421 def test_magic_methods_are_magic_mocks(self):
422 mock = MagicMock()
423 self.assertIsInstance(mock.__getitem__, MagicMock)
424
425 mock[1][2].__getitem__.return_value = 3
426 self.assertEqual(mock[1][2][3], 3)
427
428
Michael Foordb74d84f2012-06-09 15:49:37 +0100429 def test_magic_method_reset_mock(self):
430 mock = MagicMock()
431 str(mock)
432 self.assertTrue(mock.__str__.called)
433 mock.reset_mock()
434 self.assertFalse(mock.__str__.called)
435
436
Michael Foord1e68bec2012-03-03 22:24:30 +0000437 @unittest2.skipUnless(sys.version_info[:2] >= (2, 6),
438 "__dir__ not available until Python 2.6 or later")
439 def test_dir(self):
440 # overriding the default implementation
441 for mock in Mock(), MagicMock():
442 def _dir(self):
443 return ['foo']
444 mock.__dir__ = _dir
445 self.assertEqual(dir(mock), ['foo'])
446
447
448 @unittest2.skipIf('PyPy' in sys.version, "This fails differently on pypy")
449 def test_bound_methods(self):
450 m = Mock()
451
452 # XXXX should this be an expected failure instead?
453
454 # this seems like it should work, but is hard to do without introducing
455 # other api inconsistencies. Failure message could be better though.
Michael Foorda9a8bb92012-03-13 14:39:59 -0700456 m.__iter__ = [3].__iter__
457 self.assertRaises(TypeError, iter, m)
Michael Foord1e68bec2012-03-03 22:24:30 +0000458
459
460 def test_magic_method_type(self):
461 class Foo(MagicMock):
462 pass
463
464 foo = Foo()
465 self.assertIsInstance(foo.__int__, Foo)
466
467
468 def test_descriptor_from_class(self):
469 m = MagicMock()
470 type(m).__str__.return_value = 'foo'
471 self.assertEqual(str(m), 'foo')
472
473
474 def test_iterable_as_iter_return_value(self):
475 m = MagicMock()
476 m.__iter__.return_value = [1, 2, 3]
477 self.assertEqual(list(m), [1, 2, 3])
478 self.assertEqual(list(m), [1, 2, 3])
479
480 m.__iter__.return_value = iter([4, 5, 6])
481 self.assertEqual(list(m), [4, 5, 6])
482 self.assertEqual(list(m), [])
483
484
485if __name__ == '__main__':
486 unittest2.main()