| import unittest |
| from collections import OrderedDict, UserDict |
| from types import MappingProxyType |
| import _testcapi |
| |
| |
| NULL = None |
| INVALID_UTF8 = b'\xff' |
| |
| class DictSubclass(dict): |
| def __getitem__(self, key): |
| raise RuntimeError('do not get evil') |
| def __setitem__(self, key, value): |
| raise RuntimeError('do not set evil') |
| def __delitem__(self, key): |
| raise RuntimeError('do not del evil') |
| |
| def gen(): |
| yield 'a' |
| yield 'b' |
| yield 'c' |
| |
| |
| class CAPITest(unittest.TestCase): |
| |
| def test_dict_check(self): |
| check = _testcapi.dict_check |
| self.assertTrue(check({1: 2})) |
| self.assertTrue(check(OrderedDict({1: 2}))) |
| self.assertFalse(check(UserDict({1: 2}))) |
| self.assertFalse(check([1, 2])) |
| self.assertFalse(check(object())) |
| #self.assertFalse(check(NULL)) |
| |
| def test_dict_checkexact(self): |
| check = _testcapi.dict_checkexact |
| self.assertTrue(check({1: 2})) |
| self.assertFalse(check(OrderedDict({1: 2}))) |
| self.assertFalse(check(UserDict({1: 2}))) |
| self.assertFalse(check([1, 2])) |
| self.assertFalse(check(object())) |
| #self.assertFalse(check(NULL)) |
| |
| def test_dict_new(self): |
| dict_new = _testcapi.dict_new |
| dct = dict_new() |
| self.assertEqual(dct, {}) |
| self.assertIs(type(dct), dict) |
| dct2 = dict_new() |
| self.assertIsNot(dct2, dct) |
| |
| def test_dictproxy_new(self): |
| dictproxy_new = _testcapi.dictproxy_new |
| for dct in {1: 2}, OrderedDict({1: 2}), UserDict({1: 2}): |
| proxy = dictproxy_new(dct) |
| self.assertIs(type(proxy), MappingProxyType) |
| self.assertEqual(proxy, dct) |
| with self.assertRaises(TypeError): |
| proxy[1] = 3 |
| self.assertEqual(proxy[1], 2) |
| dct[1] = 4 |
| self.assertEqual(proxy[1], 4) |
| |
| self.assertRaises(TypeError, dictproxy_new, []) |
| self.assertRaises(TypeError, dictproxy_new, 42) |
| # CRASHES dictproxy_new(NULL) |
| |
| def test_dict_copy(self): |
| copy = _testcapi.dict_copy |
| for dct in {1: 2}, OrderedDict({1: 2}): |
| dct_copy = copy(dct) |
| self.assertIs(type(dct_copy), dict) |
| self.assertEqual(dct_copy, dct) |
| |
| self.assertRaises(SystemError, copy, UserDict()) |
| self.assertRaises(SystemError, copy, []) |
| self.assertRaises(SystemError, copy, 42) |
| self.assertRaises(SystemError, copy, NULL) |
| |
| def test_dict_clear(self): |
| clear = _testcapi.dict_clear |
| dct = {1: 2} |
| clear(dct) |
| self.assertEqual(dct, {}) |
| |
| # NOTE: It is not safe to call it with OrderedDict. |
| |
| # Has no effect for non-dicts. |
| dct = UserDict({1: 2}) |
| clear(dct) |
| self.assertEqual(dct, {1: 2}) |
| lst = [1, 2] |
| clear(lst) |
| self.assertEqual(lst, [1, 2]) |
| clear(object()) |
| |
| # CRASHES? clear(NULL) |
| |
| def test_dict_size(self): |
| size = _testcapi.dict_size |
| self.assertEqual(size({1: 2}), 1) |
| self.assertEqual(size(OrderedDict({1: 2})), 1) |
| |
| self.assertRaises(SystemError, size, UserDict()) |
| self.assertRaises(SystemError, size, []) |
| self.assertRaises(SystemError, size, 42) |
| self.assertRaises(SystemError, size, object()) |
| self.assertRaises(SystemError, size, NULL) |
| |
| def test_dict_getitem(self): |
| getitem = _testcapi.dict_getitem |
| dct = {'a': 1, '\U0001f40d': 2} |
| self.assertEqual(getitem(dct, 'a'), 1) |
| self.assertIs(getitem(dct, 'b'), KeyError) |
| self.assertEqual(getitem(dct, '\U0001f40d'), 2) |
| |
| dct2 = DictSubclass(dct) |
| self.assertEqual(getitem(dct2, 'a'), 1) |
| self.assertIs(getitem(dct2, 'b'), KeyError) |
| |
| self.assertIs(getitem({}, []), KeyError) # unhashable |
| self.assertIs(getitem(42, 'a'), KeyError) |
| self.assertIs(getitem([1], 0), KeyError) |
| # CRASHES getitem({}, NULL) |
| # CRASHES getitem(NULL, 'a') |
| |
| def test_dict_getitemstring(self): |
| getitemstring = _testcapi.dict_getitemstring |
| dct = {'a': 1, '\U0001f40d': 2} |
| self.assertEqual(getitemstring(dct, b'a'), 1) |
| self.assertIs(getitemstring(dct, b'b'), KeyError) |
| self.assertEqual(getitemstring(dct, '\U0001f40d'.encode()), 2) |
| |
| dct2 = DictSubclass(dct) |
| self.assertEqual(getitemstring(dct2, b'a'), 1) |
| self.assertIs(getitemstring(dct2, b'b'), KeyError) |
| |
| self.assertIs(getitemstring({}, INVALID_UTF8), KeyError) |
| self.assertIs(getitemstring(42, b'a'), KeyError) |
| self.assertIs(getitemstring([], b'a'), KeyError) |
| # CRASHES getitemstring({}, NULL) |
| # CRASHES getitemstring(NULL, b'a') |
| |
| def test_dict_getitemref(self): |
| getitem = _testcapi.dict_getitemref |
| dct = {'a': 1, '\U0001f40d': 2} |
| self.assertEqual(getitem(dct, 'a'), 1) |
| self.assertIs(getitem(dct, 'b'), KeyError) |
| self.assertEqual(getitem(dct, '\U0001f40d'), 2) |
| |
| dct2 = DictSubclass(dct) |
| self.assertEqual(getitem(dct2, 'a'), 1) |
| self.assertIs(getitem(dct2, 'b'), KeyError) |
| |
| self.assertRaises(SystemError, getitem, 42, 'a') |
| self.assertRaises(TypeError, getitem, {}, []) # unhashable |
| self.assertRaises(SystemError, getitem, [], 1) |
| self.assertRaises(SystemError, getitem, [], 'a') |
| # CRASHES getitem({}, NULL) |
| # CRASHES getitem(NULL, 'a') |
| |
| def test_dict_getitemstringref(self): |
| getitemstring = _testcapi.dict_getitemstringref |
| dct = {'a': 1, '\U0001f40d': 2} |
| self.assertEqual(getitemstring(dct, b'a'), 1) |
| self.assertIs(getitemstring(dct, b'b'), KeyError) |
| self.assertEqual(getitemstring(dct, '\U0001f40d'.encode()), 2) |
| |
| dct2 = DictSubclass(dct) |
| self.assertEqual(getitemstring(dct2, b'a'), 1) |
| self.assertIs(getitemstring(dct2, b'b'), KeyError) |
| |
| self.assertRaises(SystemError, getitemstring, 42, b'a') |
| self.assertRaises(UnicodeDecodeError, getitemstring, {}, INVALID_UTF8) |
| self.assertRaises(SystemError, getitemstring, [], b'a') |
| # CRASHES getitemstring({}, NULL) |
| # CRASHES getitemstring(NULL, b'a') |
| |
| def test_dict_getitemwitherror(self): |
| getitem = _testcapi.dict_getitemwitherror |
| dct = {'a': 1, '\U0001f40d': 2} |
| self.assertEqual(getitem(dct, 'a'), 1) |
| self.assertIs(getitem(dct, 'b'), KeyError) |
| self.assertEqual(getitem(dct, '\U0001f40d'), 2) |
| |
| dct2 = DictSubclass(dct) |
| self.assertEqual(getitem(dct2, 'a'), 1) |
| self.assertIs(getitem(dct2, 'b'), KeyError) |
| |
| self.assertRaises(SystemError, getitem, 42, 'a') |
| self.assertRaises(TypeError, getitem, {}, []) # unhashable |
| self.assertRaises(SystemError, getitem, [], 1) |
| self.assertRaises(SystemError, getitem, [], 'a') |
| # CRASHES getitem({}, NULL) |
| # CRASHES getitem(NULL, 'a') |
| |
| def test_dict_contains(self): |
| contains = _testcapi.dict_contains |
| dct = {'a': 1, '\U0001f40d': 2} |
| self.assertTrue(contains(dct, 'a')) |
| self.assertFalse(contains(dct, 'b')) |
| self.assertTrue(contains(dct, '\U0001f40d')) |
| |
| dct2 = DictSubclass(dct) |
| self.assertTrue(contains(dct2, 'a')) |
| self.assertFalse(contains(dct2, 'b')) |
| |
| self.assertRaises(TypeError, contains, {}, []) # unhashable |
| # CRASHES contains({}, NULL) |
| # CRASHES contains(UserDict(), 'a') |
| # CRASHES contains(42, 'a') |
| # CRASHES contains(NULL, 'a') |
| |
| def test_dict_contains_string(self): |
| contains_string = _testcapi.dict_containsstring |
| dct = {'a': 1, '\U0001f40d': 2} |
| self.assertTrue(contains_string(dct, b'a')) |
| self.assertFalse(contains_string(dct, b'b')) |
| self.assertTrue(contains_string(dct, '\U0001f40d'.encode())) |
| self.assertRaises(UnicodeDecodeError, contains_string, dct, INVALID_UTF8) |
| |
| dct2 = DictSubclass(dct) |
| self.assertTrue(contains_string(dct2, b'a')) |
| self.assertFalse(contains_string(dct2, b'b')) |
| |
| # CRASHES contains({}, NULL) |
| # CRASHES contains(NULL, b'a') |
| |
| def test_dict_setitem(self): |
| setitem = _testcapi.dict_setitem |
| dct = {} |
| setitem(dct, 'a', 5) |
| self.assertEqual(dct, {'a': 5}) |
| setitem(dct, '\U0001f40d', 8) |
| self.assertEqual(dct, {'a': 5, '\U0001f40d': 8}) |
| |
| dct2 = DictSubclass() |
| setitem(dct2, 'a', 5) |
| self.assertEqual(dct2, {'a': 5}) |
| |
| self.assertRaises(TypeError, setitem, {}, [], 5) # unhashable |
| self.assertRaises(SystemError, setitem, UserDict(), 'a', 5) |
| self.assertRaises(SystemError, setitem, [1], 0, 5) |
| self.assertRaises(SystemError, setitem, 42, 'a', 5) |
| # CRASHES setitem({}, NULL, 5) |
| # CRASHES setitem({}, 'a', NULL) |
| # CRASHES setitem(NULL, 'a', 5) |
| |
| def test_dict_setitemstring(self): |
| setitemstring = _testcapi.dict_setitemstring |
| dct = {} |
| setitemstring(dct, b'a', 5) |
| self.assertEqual(dct, {'a': 5}) |
| setitemstring(dct, '\U0001f40d'.encode(), 8) |
| self.assertEqual(dct, {'a': 5, '\U0001f40d': 8}) |
| |
| dct2 = DictSubclass() |
| setitemstring(dct2, b'a', 5) |
| self.assertEqual(dct2, {'a': 5}) |
| |
| self.assertRaises(UnicodeDecodeError, setitemstring, {}, INVALID_UTF8, 5) |
| self.assertRaises(SystemError, setitemstring, UserDict(), b'a', 5) |
| self.assertRaises(SystemError, setitemstring, 42, b'a', 5) |
| # CRASHES setitemstring({}, NULL, 5) |
| # CRASHES setitemstring({}, b'a', NULL) |
| # CRASHES setitemstring(NULL, b'a', 5) |
| |
| def test_dict_delitem(self): |
| delitem = _testcapi.dict_delitem |
| dct = {'a': 1, 'c': 2, '\U0001f40d': 3} |
| delitem(dct, 'a') |
| self.assertEqual(dct, {'c': 2, '\U0001f40d': 3}) |
| self.assertRaises(KeyError, delitem, dct, 'b') |
| delitem(dct, '\U0001f40d') |
| self.assertEqual(dct, {'c': 2}) |
| |
| dct2 = DictSubclass({'a': 1, 'c': 2}) |
| delitem(dct2, 'a') |
| self.assertEqual(dct2, {'c': 2}) |
| self.assertRaises(KeyError, delitem, dct2, 'b') |
| |
| self.assertRaises(TypeError, delitem, {}, []) # unhashable |
| self.assertRaises(SystemError, delitem, UserDict({'a': 1}), 'a') |
| self.assertRaises(SystemError, delitem, [1], 0) |
| self.assertRaises(SystemError, delitem, 42, 'a') |
| # CRASHES delitem({}, NULL) |
| # CRASHES delitem(NULL, 'a') |
| |
| def test_dict_delitemstring(self): |
| delitemstring = _testcapi.dict_delitemstring |
| dct = {'a': 1, 'c': 2, '\U0001f40d': 3} |
| delitemstring(dct, b'a') |
| self.assertEqual(dct, {'c': 2, '\U0001f40d': 3}) |
| self.assertRaises(KeyError, delitemstring, dct, b'b') |
| delitemstring(dct, '\U0001f40d'.encode()) |
| self.assertEqual(dct, {'c': 2}) |
| |
| dct2 = DictSubclass({'a': 1, 'c': 2}) |
| delitemstring(dct2, b'a') |
| self.assertEqual(dct2, {'c': 2}) |
| self.assertRaises(KeyError, delitemstring, dct2, b'b') |
| |
| self.assertRaises(UnicodeDecodeError, delitemstring, {}, INVALID_UTF8) |
| self.assertRaises(SystemError, delitemstring, UserDict({'a': 1}), b'a') |
| self.assertRaises(SystemError, delitemstring, 42, b'a') |
| # CRASHES delitemstring({}, NULL) |
| # CRASHES delitemstring(NULL, b'a') |
| |
| def test_dict_setdefault(self): |
| setdefault = _testcapi.dict_setdefault |
| dct = {} |
| self.assertEqual(setdefault(dct, 'a', 5), 5) |
| self.assertEqual(dct, {'a': 5}) |
| self.assertEqual(setdefault(dct, 'a', 8), 5) |
| self.assertEqual(dct, {'a': 5}) |
| |
| dct2 = DictSubclass() |
| self.assertEqual(setdefault(dct2, 'a', 5), 5) |
| self.assertEqual(dct2, {'a': 5}) |
| self.assertEqual(setdefault(dct2, 'a', 8), 5) |
| self.assertEqual(dct2, {'a': 5}) |
| |
| self.assertRaises(TypeError, setdefault, {}, [], 5) # unhashable |
| self.assertRaises(SystemError, setdefault, UserDict(), 'a', 5) |
| self.assertRaises(SystemError, setdefault, [1], 0, 5) |
| self.assertRaises(SystemError, setdefault, 42, 'a', 5) |
| # CRASHES setdefault({}, NULL, 5) |
| # CRASHES setdefault({}, 'a', NULL) |
| # CRASHES setdefault(NULL, 'a', 5) |
| |
| def test_mapping_keys_valuesitems(self): |
| class BadMapping(dict): |
| def keys(self): |
| return None |
| def values(self): |
| return None |
| def items(self): |
| return None |
| dict_obj = {'foo': 1, 'bar': 2, 'spam': 3} |
| for mapping in [dict_obj, DictSubclass(dict_obj), BadMapping(dict_obj)]: |
| self.assertListEqual(_testcapi.dict_keys(mapping), |
| list(dict_obj.keys())) |
| self.assertListEqual(_testcapi.dict_values(mapping), |
| list(dict_obj.values())) |
| self.assertListEqual(_testcapi.dict_items(mapping), |
| list(dict_obj.items())) |
| |
| def test_dict_keys_valuesitems_bad_arg(self): |
| for mapping in UserDict(), [], object(): |
| self.assertRaises(SystemError, _testcapi.dict_keys, mapping) |
| self.assertRaises(SystemError, _testcapi.dict_values, mapping) |
| self.assertRaises(SystemError, _testcapi.dict_items, mapping) |
| |
| def test_dict_next(self): |
| dict_next = _testcapi.dict_next |
| self.assertIsNone(dict_next({}, 0)) |
| dct = {'a': 1, 'b': 2, 'c': 3} |
| pos = 0 |
| pairs = [] |
| while True: |
| res = dict_next(dct, pos) |
| if res is None: |
| break |
| rc, pos, key, value = res |
| self.assertEqual(rc, 1) |
| pairs.append((key, value)) |
| self.assertEqual(pairs, list(dct.items())) |
| |
| # CRASHES dict_next(NULL, 0) |
| |
| def test_dict_update(self): |
| update = _testcapi.dict_update |
| for cls1 in dict, DictSubclass: |
| for cls2 in dict, DictSubclass, UserDict: |
| dct = cls1({'a': 1, 'b': 2}) |
| update(dct, cls2({'b': 3, 'c': 4})) |
| self.assertEqual(dct, {'a': 1, 'b': 3, 'c': 4}) |
| |
| self.assertRaises(AttributeError, update, {}, []) |
| self.assertRaises(AttributeError, update, {}, 42) |
| self.assertRaises(SystemError, update, UserDict(), {}) |
| self.assertRaises(SystemError, update, 42, {}) |
| self.assertRaises(SystemError, update, {}, NULL) |
| self.assertRaises(SystemError, update, NULL, {}) |
| |
| def test_dict_merge(self): |
| merge = _testcapi.dict_merge |
| for cls1 in dict, DictSubclass: |
| for cls2 in dict, DictSubclass, UserDict: |
| dct = cls1({'a': 1, 'b': 2}) |
| merge(dct, cls2({'b': 3, 'c': 4}), 0) |
| self.assertEqual(dct, {'a': 1, 'b': 2, 'c': 4}) |
| dct = cls1({'a': 1, 'b': 2}) |
| merge(dct, cls2({'b': 3, 'c': 4}), 1) |
| self.assertEqual(dct, {'a': 1, 'b': 3, 'c': 4}) |
| |
| self.assertRaises(AttributeError, merge, {}, [], 0) |
| self.assertRaises(AttributeError, merge, {}, 42, 0) |
| self.assertRaises(SystemError, merge, UserDict(), {}, 0) |
| self.assertRaises(SystemError, merge, 42, {}, 0) |
| self.assertRaises(SystemError, merge, {}, NULL, 0) |
| self.assertRaises(SystemError, merge, NULL, {}, 0) |
| |
| def test_dict_mergefromseq2(self): |
| mergefromseq2 = _testcapi.dict_mergefromseq2 |
| for cls1 in dict, DictSubclass: |
| for cls2 in list, iter: |
| dct = cls1({'a': 1, 'b': 2}) |
| mergefromseq2(dct, cls2([('b', 3), ('c', 4)]), 0) |
| self.assertEqual(dct, {'a': 1, 'b': 2, 'c': 4}) |
| dct = cls1({'a': 1, 'b': 2}) |
| mergefromseq2(dct, cls2([('b', 3), ('c', 4)]), 1) |
| self.assertEqual(dct, {'a': 1, 'b': 3, 'c': 4}) |
| |
| self.assertRaises(ValueError, mergefromseq2, {}, [(1,)], 0) |
| self.assertRaises(ValueError, mergefromseq2, {}, [(1, 2, 3)], 0) |
| self.assertRaises(TypeError, mergefromseq2, {}, [1], 0) |
| self.assertRaises(TypeError, mergefromseq2, {}, 42, 0) |
| # CRASHES mergefromseq2(UserDict(), [], 0) |
| # CRASHES mergefromseq2(42, [], 0) |
| # CRASHES mergefromseq2({}, NULL, 0) |
| # CRASHES mergefromseq2(NULL, {}, 0) |
| |
| |
| if __name__ == "__main__": |
| unittest.main() |