diff --git a/Lib/test/test_dict.py b/Lib/test/test_dict.py index b761f68d1b3e70..1c5a1d20daf5b2 100644 --- a/Lib/test/test_dict.py +++ b/Lib/test/test_dict.py @@ -12,6 +12,15 @@ from test.support import import_helper +class CustomHash: + def __init__(self, hash): + self.hash = hash + def __hash__(self): + return self.hash + def __repr__(self): + return f'' + + class DictTest(unittest.TestCase): def test_invalid_keyword_arguments(self): @@ -1648,6 +1657,29 @@ class MyClass: pass d[MyStr("attr1")] = 2 self.assertIsInstance(list(d)[0], MyStr) + def test_hash_collision_remove_add(self): + self.maxDiff = None + # There should be enough space, so all elements with unique hash + # will be placed in corresponding cells without collision. + n = 64 + items = [(CustomHash(h), h) for h in range(n)] + # Keys with hash collision. + a = CustomHash(n) + b = CustomHash(n) + items += [(a, 'a'), (b, 'b')] + d = dict(items) + self.assertEqual(len(d), len(items), d) + del d[a] + # "a" has been replaced with a dummy. + del items[n] + self.assertEqual(len(d), len(items), d) + self.assertEqual(d, dict(items)) + d[b] = 'c' + # "b" should not replace the dummy. + items[n] = (b, 'c') + self.assertEqual(len(d), len(items), d) + self.assertEqual(d, dict(items)) + class CAPITest(unittest.TestCase): diff --git a/Lib/test/test_set.py b/Lib/test/test_set.py index 5f38f8e319efc3..34da01c3415128 100644 --- a/Lib/test/test_set.py +++ b/Lib/test/test_set.py @@ -20,6 +20,14 @@ def check_pass_thru(): raise PassThru yield 1 +class CustomHash: + def __init__(self, hash): + self.hash = hash + def __hash__(self): + return self.hash + def __repr__(self): + return f'' + class BadCmp: def __hash__(self): return 1 @@ -675,6 +683,28 @@ def __hash__(self): with self.assertRaises(KeyError): myset.discard(elem2) + def test_hash_collision_remove_add(self): + self.maxDiff = None + # There should be enough space, so all elements with unique hash + # will be placed in corresponding cells without collision. + n = 64 + elems = [CustomHash(h) for h in range(n)] + # Elements with hash collision. + a = CustomHash(n) + b = CustomHash(n) + elems += [a, b] + s = self.thetype(elems) + self.assertEqual(len(s), len(elems), s) + s.remove(a) + # "a" has been replaced with a dummy. + del elems[n] + self.assertEqual(len(s), len(elems), s) + self.assertEqual(s, set(elems)) + s.add(b) + # "b" should not replace the dummy. + self.assertEqual(len(s), len(elems), s) + self.assertEqual(s, set(elems)) + class SetSubclass(set): pass