mirror of
https://github.com/python/cpython.git
synced 2025-07-23 19:25:40 +00:00

This was achieved by: * moving many pass statements in tests onto their own lines, so they pass line coverage and can match an easy ignore pattern if branch coverage is added later. * removing code that cannot be reached. * removing long-disabled tests. * removing unused code. * adding tests for uncovered code It turned out that removing `if __name__ == '__main__'` blocks that run unittest.main() at the bottom of test files was surprisingly contentious, so they remain and can be filtered out with an appropriate .coveragerc.
481 lines
14 KiB
Python
481 lines
14 KiB
Python
import math
|
|
import unittest
|
|
import os
|
|
import sys
|
|
from unittest.mock import Mock, MagicMock, _magics
|
|
|
|
|
|
|
|
class TestMockingMagicMethods(unittest.TestCase):
|
|
|
|
def test_deleting_magic_methods(self):
|
|
mock = Mock()
|
|
self.assertFalse(hasattr(mock, '__getitem__'))
|
|
|
|
mock.__getitem__ = Mock()
|
|
self.assertTrue(hasattr(mock, '__getitem__'))
|
|
|
|
del mock.__getitem__
|
|
self.assertFalse(hasattr(mock, '__getitem__'))
|
|
|
|
|
|
def test_magicmock_del(self):
|
|
mock = MagicMock()
|
|
# before using getitem
|
|
del mock.__getitem__
|
|
self.assertRaises(TypeError, lambda: mock['foo'])
|
|
|
|
mock = MagicMock()
|
|
# this time use it first
|
|
mock['foo']
|
|
del mock.__getitem__
|
|
self.assertRaises(TypeError, lambda: mock['foo'])
|
|
|
|
|
|
def test_magic_method_wrapping(self):
|
|
mock = Mock()
|
|
def f(self, name):
|
|
return self, 'fish'
|
|
|
|
mock.__getitem__ = f
|
|
self.assertIsNot(mock.__getitem__, f)
|
|
self.assertEqual(mock['foo'], (mock, 'fish'))
|
|
self.assertEqual(mock.__getitem__('foo'), (mock, 'fish'))
|
|
|
|
mock.__getitem__ = mock
|
|
self.assertIs(mock.__getitem__, mock)
|
|
|
|
|
|
def test_magic_methods_isolated_between_mocks(self):
|
|
mock1 = Mock()
|
|
mock2 = Mock()
|
|
|
|
mock1.__iter__ = Mock(return_value=iter([]))
|
|
self.assertEqual(list(mock1), [])
|
|
self.assertRaises(TypeError, lambda: list(mock2))
|
|
|
|
|
|
def test_repr(self):
|
|
mock = Mock()
|
|
self.assertEqual(repr(mock), "<Mock id='%s'>" % id(mock))
|
|
mock.__repr__ = lambda s: 'foo'
|
|
self.assertEqual(repr(mock), 'foo')
|
|
|
|
|
|
def test_str(self):
|
|
mock = Mock()
|
|
self.assertEqual(str(mock), object.__str__(mock))
|
|
mock.__str__ = lambda s: 'foo'
|
|
self.assertEqual(str(mock), 'foo')
|
|
|
|
|
|
def test_dict_methods(self):
|
|
mock = Mock()
|
|
|
|
self.assertRaises(TypeError, lambda: mock['foo'])
|
|
def _del():
|
|
del mock['foo']
|
|
def _set():
|
|
mock['foo'] = 3
|
|
self.assertRaises(TypeError, _del)
|
|
self.assertRaises(TypeError, _set)
|
|
|
|
_dict = {}
|
|
def getitem(s, name):
|
|
return _dict[name]
|
|
def setitem(s, name, value):
|
|
_dict[name] = value
|
|
def delitem(s, name):
|
|
del _dict[name]
|
|
|
|
mock.__setitem__ = setitem
|
|
mock.__getitem__ = getitem
|
|
mock.__delitem__ = delitem
|
|
|
|
self.assertRaises(KeyError, lambda: mock['foo'])
|
|
mock['foo'] = 'bar'
|
|
self.assertEqual(_dict, {'foo': 'bar'})
|
|
self.assertEqual(mock['foo'], 'bar')
|
|
del mock['foo']
|
|
self.assertEqual(_dict, {})
|
|
|
|
|
|
def test_numeric(self):
|
|
original = mock = Mock()
|
|
mock.value = 0
|
|
|
|
self.assertRaises(TypeError, lambda: mock + 3)
|
|
|
|
def add(self, other):
|
|
mock.value += other
|
|
return self
|
|
mock.__add__ = add
|
|
self.assertEqual(mock + 3, mock)
|
|
self.assertEqual(mock.value, 3)
|
|
|
|
del mock.__add__
|
|
def iadd(mock):
|
|
mock += 3
|
|
self.assertRaises(TypeError, iadd, mock)
|
|
mock.__iadd__ = add
|
|
mock += 6
|
|
self.assertEqual(mock, original)
|
|
self.assertEqual(mock.value, 9)
|
|
|
|
self.assertRaises(TypeError, lambda: 3 + mock)
|
|
mock.__radd__ = add
|
|
self.assertEqual(7 + mock, mock)
|
|
self.assertEqual(mock.value, 16)
|
|
|
|
def test_division(self):
|
|
original = mock = Mock()
|
|
mock.value = 32
|
|
self.assertRaises(TypeError, lambda: mock / 2)
|
|
|
|
def truediv(self, other):
|
|
mock.value /= other
|
|
return self
|
|
mock.__truediv__ = truediv
|
|
self.assertEqual(mock / 2, mock)
|
|
self.assertEqual(mock.value, 16)
|
|
|
|
del mock.__truediv__
|
|
def itruediv(mock):
|
|
mock /= 4
|
|
self.assertRaises(TypeError, itruediv, mock)
|
|
mock.__itruediv__ = truediv
|
|
mock /= 8
|
|
self.assertEqual(mock, original)
|
|
self.assertEqual(mock.value, 2)
|
|
|
|
self.assertRaises(TypeError, lambda: 8 / mock)
|
|
mock.__rtruediv__ = truediv
|
|
self.assertEqual(0.5 / mock, mock)
|
|
self.assertEqual(mock.value, 4)
|
|
|
|
def test_hash(self):
|
|
mock = Mock()
|
|
# test delegation
|
|
self.assertEqual(hash(mock), Mock.__hash__(mock))
|
|
|
|
def _hash(s):
|
|
return 3
|
|
mock.__hash__ = _hash
|
|
self.assertEqual(hash(mock), 3)
|
|
|
|
|
|
def test_nonzero(self):
|
|
m = Mock()
|
|
self.assertTrue(bool(m))
|
|
|
|
m.__bool__ = lambda s: False
|
|
self.assertFalse(bool(m))
|
|
|
|
|
|
def test_comparison(self):
|
|
mock = Mock()
|
|
def comp(s, o):
|
|
return True
|
|
mock.__lt__ = mock.__gt__ = mock.__le__ = mock.__ge__ = comp
|
|
self. assertTrue(mock < 3)
|
|
self. assertTrue(mock > 3)
|
|
self. assertTrue(mock <= 3)
|
|
self. assertTrue(mock >= 3)
|
|
|
|
self.assertRaises(TypeError, lambda: MagicMock() < object())
|
|
self.assertRaises(TypeError, lambda: object() < MagicMock())
|
|
self.assertRaises(TypeError, lambda: MagicMock() < MagicMock())
|
|
self.assertRaises(TypeError, lambda: MagicMock() > object())
|
|
self.assertRaises(TypeError, lambda: object() > MagicMock())
|
|
self.assertRaises(TypeError, lambda: MagicMock() > MagicMock())
|
|
self.assertRaises(TypeError, lambda: MagicMock() <= object())
|
|
self.assertRaises(TypeError, lambda: object() <= MagicMock())
|
|
self.assertRaises(TypeError, lambda: MagicMock() <= MagicMock())
|
|
self.assertRaises(TypeError, lambda: MagicMock() >= object())
|
|
self.assertRaises(TypeError, lambda: object() >= MagicMock())
|
|
self.assertRaises(TypeError, lambda: MagicMock() >= MagicMock())
|
|
|
|
|
|
def test_equality(self):
|
|
for mock in Mock(), MagicMock():
|
|
self.assertEqual(mock == mock, True)
|
|
self.assertIsInstance(mock == mock, bool)
|
|
self.assertEqual(mock != mock, False)
|
|
self.assertIsInstance(mock != mock, bool)
|
|
self.assertEqual(mock == object(), False)
|
|
self.assertEqual(mock != object(), True)
|
|
|
|
def eq(self, other):
|
|
return other == 3
|
|
mock.__eq__ = eq
|
|
self.assertTrue(mock == 3)
|
|
self.assertFalse(mock == 4)
|
|
|
|
def ne(self, other):
|
|
return other == 3
|
|
mock.__ne__ = ne
|
|
self.assertTrue(mock != 3)
|
|
self.assertFalse(mock != 4)
|
|
|
|
mock = MagicMock()
|
|
mock.__eq__.return_value = True
|
|
self.assertIsInstance(mock == 3, bool)
|
|
self.assertEqual(mock == 3, True)
|
|
|
|
mock.__ne__.return_value = False
|
|
self.assertIsInstance(mock != 3, bool)
|
|
self.assertEqual(mock != 3, False)
|
|
|
|
|
|
def test_len_contains_iter(self):
|
|
mock = Mock()
|
|
|
|
self.assertRaises(TypeError, len, mock)
|
|
self.assertRaises(TypeError, iter, mock)
|
|
self.assertRaises(TypeError, lambda: 'foo' in mock)
|
|
|
|
mock.__len__ = lambda s: 6
|
|
self.assertEqual(len(mock), 6)
|
|
|
|
mock.__contains__ = lambda s, o: o == 3
|
|
self.assertIn(3, mock)
|
|
self.assertNotIn(6, mock)
|
|
|
|
mock.__iter__ = lambda s: iter('foobarbaz')
|
|
self.assertEqual(list(mock), list('foobarbaz'))
|
|
|
|
|
|
def test_magicmock(self):
|
|
mock = MagicMock()
|
|
|
|
mock.__iter__.return_value = iter([1, 2, 3])
|
|
self.assertEqual(list(mock), [1, 2, 3])
|
|
|
|
getattr(mock, '__bool__').return_value = False
|
|
self.assertFalse(hasattr(mock, '__nonzero__'))
|
|
self.assertFalse(bool(mock))
|
|
|
|
for entry in _magics:
|
|
self.assertTrue(hasattr(mock, entry))
|
|
self.assertFalse(hasattr(mock, '__imaginary__'))
|
|
|
|
|
|
def test_magic_mock_equality(self):
|
|
mock = MagicMock()
|
|
self.assertIsInstance(mock == object(), bool)
|
|
self.assertIsInstance(mock != object(), bool)
|
|
|
|
self.assertEqual(mock == object(), False)
|
|
self.assertEqual(mock != object(), True)
|
|
self.assertEqual(mock == mock, True)
|
|
self.assertEqual(mock != mock, False)
|
|
|
|
|
|
def test_magicmock_defaults(self):
|
|
mock = MagicMock()
|
|
self.assertEqual(int(mock), 1)
|
|
self.assertEqual(complex(mock), 1j)
|
|
self.assertEqual(float(mock), 1.0)
|
|
self.assertNotIn(object(), mock)
|
|
self.assertEqual(len(mock), 0)
|
|
self.assertEqual(list(mock), [])
|
|
self.assertEqual(hash(mock), object.__hash__(mock))
|
|
self.assertEqual(str(mock), object.__str__(mock))
|
|
self.assertTrue(bool(mock))
|
|
self.assertEqual(round(mock), mock.__round__())
|
|
self.assertEqual(math.trunc(mock), mock.__trunc__())
|
|
self.assertEqual(math.floor(mock), mock.__floor__())
|
|
self.assertEqual(math.ceil(mock), mock.__ceil__())
|
|
|
|
# in Python 3 oct and hex use __index__
|
|
# so these tests are for __index__ in py3k
|
|
self.assertEqual(oct(mock), '0o1')
|
|
self.assertEqual(hex(mock), '0x1')
|
|
# how to test __sizeof__ ?
|
|
|
|
|
|
def test_magic_methods_fspath(self):
|
|
mock = MagicMock()
|
|
expected_path = mock.__fspath__()
|
|
mock.reset_mock()
|
|
|
|
self.assertEqual(os.fspath(mock), expected_path)
|
|
mock.__fspath__.assert_called_once()
|
|
|
|
|
|
def test_magic_methods_and_spec(self):
|
|
class Iterable(object):
|
|
def __iter__(self): pass
|
|
|
|
mock = Mock(spec=Iterable)
|
|
self.assertRaises(AttributeError, lambda: mock.__iter__)
|
|
|
|
mock.__iter__ = Mock(return_value=iter([]))
|
|
self.assertEqual(list(mock), [])
|
|
|
|
class NonIterable(object):
|
|
pass
|
|
mock = Mock(spec=NonIterable)
|
|
self.assertRaises(AttributeError, lambda: mock.__iter__)
|
|
|
|
def set_int():
|
|
mock.__int__ = Mock(return_value=iter([]))
|
|
self.assertRaises(AttributeError, set_int)
|
|
|
|
mock = MagicMock(spec=Iterable)
|
|
self.assertEqual(list(mock), [])
|
|
self.assertRaises(AttributeError, set_int)
|
|
|
|
|
|
def test_magic_methods_and_spec_set(self):
|
|
class Iterable(object):
|
|
def __iter__(self): pass
|
|
|
|
mock = Mock(spec_set=Iterable)
|
|
self.assertRaises(AttributeError, lambda: mock.__iter__)
|
|
|
|
mock.__iter__ = Mock(return_value=iter([]))
|
|
self.assertEqual(list(mock), [])
|
|
|
|
class NonIterable(object):
|
|
pass
|
|
mock = Mock(spec_set=NonIterable)
|
|
self.assertRaises(AttributeError, lambda: mock.__iter__)
|
|
|
|
def set_int():
|
|
mock.__int__ = Mock(return_value=iter([]))
|
|
self.assertRaises(AttributeError, set_int)
|
|
|
|
mock = MagicMock(spec_set=Iterable)
|
|
self.assertEqual(list(mock), [])
|
|
self.assertRaises(AttributeError, set_int)
|
|
|
|
|
|
def test_setting_unsupported_magic_method(self):
|
|
mock = MagicMock()
|
|
def set_setattr():
|
|
mock.__setattr__ = lambda self, name: None
|
|
self.assertRaisesRegex(AttributeError,
|
|
"Attempting to set unsupported magic method '__setattr__'.",
|
|
set_setattr
|
|
)
|
|
|
|
|
|
def test_attributes_and_return_value(self):
|
|
mock = MagicMock()
|
|
attr = mock.foo
|
|
def _get_type(obj):
|
|
# the type of every mock (or magicmock) is a custom subclass
|
|
# so the real type is the second in the mro
|
|
return type(obj).__mro__[1]
|
|
self.assertEqual(_get_type(attr), MagicMock)
|
|
|
|
returned = mock()
|
|
self.assertEqual(_get_type(returned), MagicMock)
|
|
|
|
|
|
def test_magic_methods_are_magic_mocks(self):
|
|
mock = MagicMock()
|
|
self.assertIsInstance(mock.__getitem__, MagicMock)
|
|
|
|
mock[1][2].__getitem__.return_value = 3
|
|
self.assertEqual(mock[1][2][3], 3)
|
|
|
|
|
|
def test_magic_method_reset_mock(self):
|
|
mock = MagicMock()
|
|
str(mock)
|
|
self.assertTrue(mock.__str__.called)
|
|
mock.reset_mock()
|
|
self.assertFalse(mock.__str__.called)
|
|
|
|
|
|
def test_dir(self):
|
|
# overriding the default implementation
|
|
for mock in Mock(), MagicMock():
|
|
def _dir(self):
|
|
return ['foo']
|
|
mock.__dir__ = _dir
|
|
self.assertEqual(dir(mock), ['foo'])
|
|
|
|
|
|
@unittest.skipIf('PyPy' in sys.version, "This fails differently on pypy")
|
|
def test_bound_methods(self):
|
|
m = Mock()
|
|
|
|
# XXXX should this be an expected failure instead?
|
|
|
|
# this seems like it should work, but is hard to do without introducing
|
|
# other api inconsistencies. Failure message could be better though.
|
|
m.__iter__ = [3].__iter__
|
|
self.assertRaises(TypeError, iter, m)
|
|
|
|
|
|
def test_magic_method_type(self):
|
|
class Foo(MagicMock):
|
|
pass
|
|
|
|
foo = Foo()
|
|
self.assertIsInstance(foo.__int__, Foo)
|
|
|
|
|
|
def test_descriptor_from_class(self):
|
|
m = MagicMock()
|
|
type(m).__str__.return_value = 'foo'
|
|
self.assertEqual(str(m), 'foo')
|
|
|
|
|
|
def test_iterable_as_iter_return_value(self):
|
|
m = MagicMock()
|
|
m.__iter__.return_value = [1, 2, 3]
|
|
self.assertEqual(list(m), [1, 2, 3])
|
|
self.assertEqual(list(m), [1, 2, 3])
|
|
|
|
m.__iter__.return_value = iter([4, 5, 6])
|
|
self.assertEqual(list(m), [4, 5, 6])
|
|
self.assertEqual(list(m), [])
|
|
|
|
|
|
def test_matmul(self):
|
|
m = MagicMock()
|
|
self.assertIsInstance(m @ 1, MagicMock)
|
|
m.__matmul__.return_value = 42
|
|
m.__rmatmul__.return_value = 666
|
|
m.__imatmul__.return_value = 24
|
|
self.assertEqual(m @ 1, 42)
|
|
self.assertEqual(1 @ m, 666)
|
|
m @= 24
|
|
self.assertEqual(m, 24)
|
|
|
|
def test_divmod_and_rdivmod(self):
|
|
m = MagicMock()
|
|
self.assertIsInstance(divmod(5, m), MagicMock)
|
|
m.__divmod__.return_value = (2, 1)
|
|
self.assertEqual(divmod(m, 2), (2, 1))
|
|
m = MagicMock()
|
|
foo = divmod(2, m)
|
|
self.assertIsInstance(foo, MagicMock)
|
|
foo_direct = m.__divmod__(2)
|
|
self.assertIsInstance(foo_direct, MagicMock)
|
|
bar = divmod(m, 2)
|
|
self.assertIsInstance(bar, MagicMock)
|
|
bar_direct = m.__rdivmod__(2)
|
|
self.assertIsInstance(bar_direct, MagicMock)
|
|
|
|
# http://bugs.python.org/issue23310
|
|
# Check if you can change behaviour of magic methods in MagicMock init
|
|
def test_magic_in_initialization(self):
|
|
m = MagicMock(**{'__str__.return_value': "12"})
|
|
self.assertEqual(str(m), "12")
|
|
|
|
def test_changing_magic_set_in_initialization(self):
|
|
m = MagicMock(**{'__str__.return_value': "12"})
|
|
m.__str__.return_value = "13"
|
|
self.assertEqual(str(m), "13")
|
|
m = MagicMock(**{'__str__.return_value': "12"})
|
|
m.configure_mock(**{'__str__.return_value': "14"})
|
|
self.assertEqual(str(m), "14")
|
|
|
|
|
|
if __name__ == '__main__':
|
|
unittest.main()
|