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