michael@0: # Copyright (C) 2007-2012 Michael Foord & the mock team michael@0: # E-mail: fuzzyman AT voidspace DOT org DOT uk michael@0: # http://www.voidspace.org.uk/python/mock/ michael@0: michael@0: from tests.support import unittest2, inPy3k michael@0: michael@0: try: michael@0: unicode michael@0: except NameError: michael@0: # Python 3 michael@0: unicode = str michael@0: long = int michael@0: michael@0: import inspect michael@0: import sys michael@0: from mock import Mock, MagicMock, _magics michael@0: michael@0: michael@0: michael@0: class TestMockingMagicMethods(unittest2.TestCase): michael@0: michael@0: def test_deleting_magic_methods(self): michael@0: mock = Mock() michael@0: self.assertFalse(hasattr(mock, '__getitem__')) michael@0: michael@0: mock.__getitem__ = Mock() michael@0: self.assertTrue(hasattr(mock, '__getitem__')) michael@0: michael@0: del mock.__getitem__ michael@0: self.assertFalse(hasattr(mock, '__getitem__')) michael@0: michael@0: michael@0: def test_magicmock_del(self): michael@0: mock = MagicMock() michael@0: # before using getitem michael@0: del mock.__getitem__ michael@0: self.assertRaises(TypeError, lambda: mock['foo']) michael@0: michael@0: mock = MagicMock() michael@0: # this time use it first michael@0: mock['foo'] michael@0: del mock.__getitem__ michael@0: self.assertRaises(TypeError, lambda: mock['foo']) michael@0: michael@0: michael@0: def test_magic_method_wrapping(self): michael@0: mock = Mock() michael@0: def f(self, name): michael@0: return self, 'fish' michael@0: michael@0: mock.__getitem__ = f michael@0: self.assertFalse(mock.__getitem__ is f) michael@0: self.assertEqual(mock['foo'], (mock, 'fish')) michael@0: self.assertEqual(mock.__getitem__('foo'), (mock, 'fish')) michael@0: michael@0: mock.__getitem__ = mock michael@0: self.assertTrue(mock.__getitem__ is mock) michael@0: michael@0: michael@0: def test_magic_methods_isolated_between_mocks(self): michael@0: mock1 = Mock() michael@0: mock2 = Mock() michael@0: michael@0: mock1.__iter__ = Mock(return_value=iter([])) michael@0: self.assertEqual(list(mock1), []) michael@0: self.assertRaises(TypeError, lambda: list(mock2)) michael@0: michael@0: michael@0: def test_repr(self): michael@0: mock = Mock() michael@0: self.assertEqual(repr(mock), "" % id(mock)) michael@0: mock.__repr__ = lambda s: 'foo' michael@0: self.assertEqual(repr(mock), 'foo') michael@0: michael@0: michael@0: def test_str(self): michael@0: mock = Mock() michael@0: self.assertEqual(str(mock), object.__str__(mock)) michael@0: mock.__str__ = lambda s: 'foo' michael@0: self.assertEqual(str(mock), 'foo') michael@0: michael@0: michael@0: @unittest2.skipIf(inPy3k, "no unicode in Python 3") michael@0: def test_unicode(self): michael@0: mock = Mock() michael@0: self.assertEqual(unicode(mock), unicode(str(mock))) michael@0: michael@0: mock.__unicode__ = lambda s: unicode('foo') michael@0: self.assertEqual(unicode(mock), unicode('foo')) michael@0: michael@0: michael@0: def test_dict_methods(self): michael@0: mock = Mock() michael@0: michael@0: self.assertRaises(TypeError, lambda: mock['foo']) michael@0: def _del(): michael@0: del mock['foo'] michael@0: def _set(): michael@0: mock['foo'] = 3 michael@0: self.assertRaises(TypeError, _del) michael@0: self.assertRaises(TypeError, _set) michael@0: michael@0: _dict = {} michael@0: def getitem(s, name): michael@0: return _dict[name] michael@0: def setitem(s, name, value): michael@0: _dict[name] = value michael@0: def delitem(s, name): michael@0: del _dict[name] michael@0: michael@0: mock.__setitem__ = setitem michael@0: mock.__getitem__ = getitem michael@0: mock.__delitem__ = delitem michael@0: michael@0: self.assertRaises(KeyError, lambda: mock['foo']) michael@0: mock['foo'] = 'bar' michael@0: self.assertEqual(_dict, {'foo': 'bar'}) michael@0: self.assertEqual(mock['foo'], 'bar') michael@0: del mock['foo'] michael@0: self.assertEqual(_dict, {}) michael@0: michael@0: michael@0: def test_numeric(self): michael@0: original = mock = Mock() michael@0: mock.value = 0 michael@0: michael@0: self.assertRaises(TypeError, lambda: mock + 3) michael@0: michael@0: def add(self, other): michael@0: mock.value += other michael@0: return self michael@0: mock.__add__ = add michael@0: self.assertEqual(mock + 3, mock) michael@0: self.assertEqual(mock.value, 3) michael@0: michael@0: del mock.__add__ michael@0: def iadd(mock): michael@0: mock += 3 michael@0: self.assertRaises(TypeError, iadd, mock) michael@0: mock.__iadd__ = add michael@0: mock += 6 michael@0: self.assertEqual(mock, original) michael@0: self.assertEqual(mock.value, 9) michael@0: michael@0: self.assertRaises(TypeError, lambda: 3 + mock) michael@0: mock.__radd__ = add michael@0: self.assertEqual(7 + mock, mock) michael@0: self.assertEqual(mock.value, 16) michael@0: michael@0: michael@0: @unittest2.skipIf(inPy3k, 'no truediv in Python 3') michael@0: def test_truediv(self): michael@0: mock = MagicMock() michael@0: mock.__truediv__.return_value = 6 michael@0: michael@0: context = {'mock': mock} michael@0: code = 'from __future__ import division\nresult = mock / 7\n' michael@0: exec(code, context) michael@0: self.assertEqual(context['result'], 6) michael@0: michael@0: mock.__rtruediv__.return_value = 3 michael@0: code = 'from __future__ import division\nresult = 2 / mock\n' michael@0: exec(code, context) michael@0: self.assertEqual(context['result'], 3) michael@0: michael@0: michael@0: @unittest2.skipIf(not inPy3k, 'truediv is available in Python 2') michael@0: def test_no_truediv(self): michael@0: self.assertRaises( michael@0: AttributeError, getattr, MagicMock(), '__truediv__' michael@0: ) michael@0: self.assertRaises( michael@0: AttributeError, getattr, MagicMock(), '__rtruediv__' michael@0: ) michael@0: michael@0: michael@0: def test_hash(self): michael@0: mock = Mock() michael@0: # test delegation michael@0: self.assertEqual(hash(mock), Mock.__hash__(mock)) michael@0: michael@0: def _hash(s): michael@0: return 3 michael@0: mock.__hash__ = _hash michael@0: self.assertEqual(hash(mock), 3) michael@0: michael@0: michael@0: def test_nonzero(self): michael@0: m = Mock() michael@0: self.assertTrue(bool(m)) michael@0: michael@0: nonzero = lambda s: False michael@0: if not inPy3k: michael@0: m.__nonzero__ = nonzero michael@0: else: michael@0: m.__bool__ = nonzero michael@0: michael@0: self.assertFalse(bool(m)) michael@0: michael@0: michael@0: def test_comparison(self): michael@0: # note: this test fails with Jython 2.5.1 due to a Jython bug michael@0: # it is fixed in jython 2.5.2 michael@0: if not inPy3k: michael@0: # incomparable in Python 3 michael@0: self. assertEqual(Mock() < 3, object() < 3) michael@0: self. assertEqual(Mock() > 3, object() > 3) michael@0: self. assertEqual(Mock() <= 3, object() <= 3) michael@0: self. assertEqual(Mock() >= 3, object() >= 3) michael@0: else: michael@0: self.assertRaises(TypeError, lambda: MagicMock() < object()) michael@0: self.assertRaises(TypeError, lambda: object() < MagicMock()) michael@0: self.assertRaises(TypeError, lambda: MagicMock() < MagicMock()) michael@0: self.assertRaises(TypeError, lambda: MagicMock() > object()) michael@0: self.assertRaises(TypeError, lambda: object() > MagicMock()) michael@0: self.assertRaises(TypeError, lambda: MagicMock() > MagicMock()) michael@0: self.assertRaises(TypeError, lambda: MagicMock() <= object()) michael@0: self.assertRaises(TypeError, lambda: object() <= MagicMock()) michael@0: self.assertRaises(TypeError, lambda: MagicMock() <= MagicMock()) michael@0: self.assertRaises(TypeError, lambda: MagicMock() >= object()) michael@0: self.assertRaises(TypeError, lambda: object() >= MagicMock()) michael@0: self.assertRaises(TypeError, lambda: MagicMock() >= MagicMock()) michael@0: michael@0: mock = Mock() michael@0: def comp(s, o): michael@0: return True michael@0: mock.__lt__ = mock.__gt__ = mock.__le__ = mock.__ge__ = comp michael@0: self. assertTrue(mock < 3) michael@0: self. assertTrue(mock > 3) michael@0: self. assertTrue(mock <= 3) michael@0: self. assertTrue(mock >= 3) michael@0: michael@0: michael@0: def test_equality(self): michael@0: for mock in Mock(), MagicMock(): michael@0: self.assertEqual(mock == mock, True) michael@0: self.assertIsInstance(mock == mock, bool) michael@0: self.assertEqual(mock != mock, False) michael@0: self.assertIsInstance(mock != mock, bool) michael@0: self.assertEqual(mock == object(), False) michael@0: self.assertEqual(mock != object(), True) michael@0: michael@0: def eq(self, other): michael@0: return other == 3 michael@0: mock.__eq__ = eq michael@0: self.assertTrue(mock == 3) michael@0: self.assertFalse(mock == 4) michael@0: michael@0: def ne(self, other): michael@0: return other == 3 michael@0: mock.__ne__ = ne michael@0: self.assertTrue(mock != 3) michael@0: self.assertFalse(mock != 4) michael@0: michael@0: mock = MagicMock() michael@0: mock.__eq__.return_value = True michael@0: self.assertIsInstance(mock == 3, bool) michael@0: self.assertEqual(mock == 3, True) michael@0: michael@0: mock.__ne__.return_value = False michael@0: self.assertIsInstance(mock != 3, bool) michael@0: self.assertEqual(mock != 3, False) michael@0: michael@0: michael@0: def test_len_contains_iter(self): michael@0: mock = Mock() michael@0: michael@0: self.assertRaises(TypeError, len, mock) michael@0: self.assertRaises(TypeError, iter, mock) michael@0: self.assertRaises(TypeError, lambda: 'foo' in mock) michael@0: michael@0: mock.__len__ = lambda s: 6 michael@0: self.assertEqual(len(mock), 6) michael@0: michael@0: mock.__contains__ = lambda s, o: o == 3 michael@0: self.assertTrue(3 in mock) michael@0: self.assertFalse(6 in mock) michael@0: michael@0: mock.__iter__ = lambda s: iter('foobarbaz') michael@0: self.assertEqual(list(mock), list('foobarbaz')) michael@0: michael@0: michael@0: def test_magicmock(self): michael@0: mock = MagicMock() michael@0: michael@0: mock.__iter__.return_value = iter([1, 2, 3]) michael@0: self.assertEqual(list(mock), [1, 2, 3]) michael@0: michael@0: name = '__nonzero__' michael@0: other = '__bool__' michael@0: if inPy3k: michael@0: name, other = other, name michael@0: getattr(mock, name).return_value = False michael@0: self.assertFalse(hasattr(mock, other)) michael@0: self.assertFalse(bool(mock)) michael@0: michael@0: for entry in _magics: michael@0: self.assertTrue(hasattr(mock, entry)) michael@0: self.assertFalse(hasattr(mock, '__imaginery__')) michael@0: michael@0: michael@0: def test_magic_mock_equality(self): michael@0: mock = MagicMock() michael@0: self.assertIsInstance(mock == object(), bool) michael@0: self.assertIsInstance(mock != object(), bool) michael@0: michael@0: self.assertEqual(mock == object(), False) michael@0: self.assertEqual(mock != object(), True) michael@0: self.assertEqual(mock == mock, True) michael@0: self.assertEqual(mock != mock, False) michael@0: michael@0: michael@0: def test_magicmock_defaults(self): michael@0: mock = MagicMock() michael@0: self.assertEqual(int(mock), 1) michael@0: self.assertEqual(complex(mock), 1j) michael@0: self.assertEqual(float(mock), 1.0) michael@0: self.assertEqual(long(mock), long(1)) michael@0: self.assertNotIn(object(), mock) michael@0: self.assertEqual(len(mock), 0) michael@0: self.assertEqual(list(mock), []) michael@0: self.assertEqual(hash(mock), object.__hash__(mock)) michael@0: self.assertEqual(str(mock), object.__str__(mock)) michael@0: self.assertEqual(unicode(mock), object.__str__(mock)) michael@0: self.assertIsInstance(unicode(mock), unicode) michael@0: self.assertTrue(bool(mock)) michael@0: if not inPy3k: michael@0: self.assertEqual(oct(mock), '1') michael@0: else: michael@0: # in Python 3 oct and hex use __index__ michael@0: # so these tests are for __index__ in py3k michael@0: self.assertEqual(oct(mock), '0o1') michael@0: self.assertEqual(hex(mock), '0x1') michael@0: # how to test __sizeof__ ? michael@0: michael@0: michael@0: @unittest2.skipIf(inPy3k, "no __cmp__ in Python 3") michael@0: def test_non_default_magic_methods(self): michael@0: mock = MagicMock() michael@0: self.assertRaises(AttributeError, lambda: mock.__cmp__) michael@0: michael@0: mock = Mock() michael@0: mock.__cmp__ = lambda s, o: 0 michael@0: michael@0: self.assertEqual(mock, object()) michael@0: michael@0: michael@0: def test_magic_methods_and_spec(self): michael@0: class Iterable(object): michael@0: def __iter__(self): michael@0: pass michael@0: michael@0: mock = Mock(spec=Iterable) michael@0: self.assertRaises(AttributeError, lambda: mock.__iter__) michael@0: michael@0: mock.__iter__ = Mock(return_value=iter([])) michael@0: self.assertEqual(list(mock), []) michael@0: michael@0: class NonIterable(object): michael@0: pass michael@0: mock = Mock(spec=NonIterable) michael@0: self.assertRaises(AttributeError, lambda: mock.__iter__) michael@0: michael@0: def set_int(): michael@0: mock.__int__ = Mock(return_value=iter([])) michael@0: self.assertRaises(AttributeError, set_int) michael@0: michael@0: mock = MagicMock(spec=Iterable) michael@0: self.assertEqual(list(mock), []) michael@0: self.assertRaises(AttributeError, set_int) michael@0: michael@0: michael@0: def test_magic_methods_and_spec_set(self): michael@0: class Iterable(object): michael@0: def __iter__(self): michael@0: pass michael@0: michael@0: mock = Mock(spec_set=Iterable) michael@0: self.assertRaises(AttributeError, lambda: mock.__iter__) michael@0: michael@0: mock.__iter__ = Mock(return_value=iter([])) michael@0: self.assertEqual(list(mock), []) michael@0: michael@0: class NonIterable(object): michael@0: pass michael@0: mock = Mock(spec_set=NonIterable) michael@0: self.assertRaises(AttributeError, lambda: mock.__iter__) michael@0: michael@0: def set_int(): michael@0: mock.__int__ = Mock(return_value=iter([])) michael@0: self.assertRaises(AttributeError, set_int) michael@0: michael@0: mock = MagicMock(spec_set=Iterable) michael@0: self.assertEqual(list(mock), []) michael@0: self.assertRaises(AttributeError, set_int) michael@0: michael@0: michael@0: def test_setting_unsupported_magic_method(self): michael@0: mock = MagicMock() michael@0: def set_setattr(): michael@0: mock.__setattr__ = lambda self, name: None michael@0: self.assertRaisesRegexp(AttributeError, michael@0: "Attempting to set unsupported magic method '__setattr__'.", michael@0: set_setattr michael@0: ) michael@0: michael@0: michael@0: def test_attributes_and_return_value(self): michael@0: mock = MagicMock() michael@0: attr = mock.foo michael@0: def _get_type(obj): michael@0: # the type of every mock (or magicmock) is a custom subclass michael@0: # so the real type is the second in the mro michael@0: return type(obj).__mro__[1] michael@0: self.assertEqual(_get_type(attr), MagicMock) michael@0: michael@0: returned = mock() michael@0: self.assertEqual(_get_type(returned), MagicMock) michael@0: michael@0: michael@0: def test_magic_methods_are_magic_mocks(self): michael@0: mock = MagicMock() michael@0: self.assertIsInstance(mock.__getitem__, MagicMock) michael@0: michael@0: mock[1][2].__getitem__.return_value = 3 michael@0: self.assertEqual(mock[1][2][3], 3) michael@0: michael@0: michael@0: def test_magic_method_reset_mock(self): michael@0: mock = MagicMock() michael@0: str(mock) michael@0: self.assertTrue(mock.__str__.called) michael@0: mock.reset_mock() michael@0: self.assertFalse(mock.__str__.called) michael@0: michael@0: michael@0: @unittest2.skipUnless(sys.version_info[:2] >= (2, 6), michael@0: "__dir__ not available until Python 2.6 or later") michael@0: def test_dir(self): michael@0: # overriding the default implementation michael@0: for mock in Mock(), MagicMock(): michael@0: def _dir(self): michael@0: return ['foo'] michael@0: mock.__dir__ = _dir michael@0: self.assertEqual(dir(mock), ['foo']) michael@0: michael@0: michael@0: @unittest2.skipIf('PyPy' in sys.version, "This fails differently on pypy") michael@0: def test_bound_methods(self): michael@0: m = Mock() michael@0: michael@0: # XXXX should this be an expected failure instead? michael@0: michael@0: # this seems like it should work, but is hard to do without introducing michael@0: # other api inconsistencies. Failure message could be better though. michael@0: m.__iter__ = [3].__iter__ michael@0: self.assertRaises(TypeError, iter, m) michael@0: michael@0: michael@0: def test_magic_method_type(self): michael@0: class Foo(MagicMock): michael@0: pass michael@0: michael@0: foo = Foo() michael@0: self.assertIsInstance(foo.__int__, Foo) michael@0: michael@0: michael@0: def test_descriptor_from_class(self): michael@0: m = MagicMock() michael@0: type(m).__str__.return_value = 'foo' michael@0: self.assertEqual(str(m), 'foo') michael@0: michael@0: michael@0: def test_iterable_as_iter_return_value(self): michael@0: m = MagicMock() michael@0: m.__iter__.return_value = [1, 2, 3] michael@0: self.assertEqual(list(m), [1, 2, 3]) michael@0: self.assertEqual(list(m), [1, 2, 3]) michael@0: michael@0: m.__iter__.return_value = iter([4, 5, 6]) michael@0: self.assertEqual(list(m), [4, 5, 6]) michael@0: self.assertEqual(list(m), []) michael@0: michael@0: michael@0: if __name__ == '__main__': michael@0: unittest2.main()