diff --git a/Lib/test/test_ordered_dict.py b/Lib/test/test_ordered_dict.py index 1d09387fb9..4b9f5a766d 100644 --- a/Lib/test/test_ordered_dict.py +++ b/Lib/test/test_ordered_dict.py @@ -239,6 +239,8 @@ def test_popitem_last(self): obj.popitem(last=True) self.assertEqual(len(obj), 20) + # TODO: RUSTPYTHON + @unittest.expectedFailure def test_pop(self): OrderedDict = self.OrderedDict pairs = [('c', 1), ('b', 2), ('a', 3), ('d', 4), ('e', 5), ('f', 6)] @@ -281,12 +283,16 @@ def test_equality(self): # different length implied inequality self.assertNotEqual(od1, OrderedDict(pairs[:-1])) + # TODO: RUSTPYTHON + @unittest.expectedFailure def test_copying(self): OrderedDict = self.OrderedDict # Check that ordered dicts are copyable, deepcopyable, picklable, # and have a repr/eval round-trip pairs = [('c', 1), ('b', 2), ('a', 3), ('d', 4), ('e', 5), ('f', 6)] od = OrderedDict(pairs) + od.x = ['x'] + od.z = ['z'] def check(dup): msg = "\ncopy: %s\nod: %s" % (dup, od) self.assertIsNot(dup, od, msg) @@ -295,13 +301,27 @@ def check(dup): self.assertEqual(len(dup), len(od)) self.assertEqual(type(dup), type(od)) check(od.copy()) - check(copy.copy(od)) - check(copy.deepcopy(od)) + dup = copy.copy(od) + check(dup) + self.assertIs(dup.x, od.x) + self.assertIs(dup.z, od.z) + self.assertFalse(hasattr(dup, 'y')) + dup = copy.deepcopy(od) + check(dup) + self.assertEqual(dup.x, od.x) + self.assertIsNot(dup.x, od.x) + self.assertEqual(dup.z, od.z) + self.assertIsNot(dup.z, od.z) + self.assertFalse(hasattr(dup, 'y')) # pickle directly pulls the module, so we have to fake it with replaced_module('collections', self.module): for proto in range(pickle.HIGHEST_PROTOCOL + 1): with self.subTest(proto=proto): - check(pickle.loads(pickle.dumps(od, proto))) + dup = pickle.loads(pickle.dumps(od, proto)) + check(dup) + self.assertEqual(dup.x, od.x) + self.assertEqual(dup.z, od.z) + self.assertFalse(hasattr(dup, 'y')) check(eval(repr(od))) update_test = OrderedDict() update_test.update(od) @@ -756,7 +776,7 @@ def test_sizeof_exact(self): check = self.check_sizeof basicsize = size('nQ2P' + '3PnPn2P') - keysize = calcsize('2nP2n') + keysize = calcsize('n2BI2n') entrysize = calcsize('n2P') p = calcsize('P') @@ -854,6 +874,23 @@ class OrderedDict(c_coll.OrderedDict): pass +class PurePythonOrderedDictWithSlotsCopyingTests(unittest.TestCase): + + module = py_coll + class OrderedDict(py_coll.OrderedDict): + __slots__ = ('x', 'y') + test_copying = OrderedDictTests.test_copying + + +@unittest.skipUnless(c_coll, 'requires the C version of the collections module') +class CPythonOrderedDictWithSlotsCopyingTests(unittest.TestCase): + + module = c_coll + class OrderedDict(c_coll.OrderedDict): + __slots__ = ('x', 'y') + test_copying = OrderedDictTests.test_copying + + class PurePythonGeneralMappingTests(mapping_tests.BasicTestMappingProtocol): @classmethod @@ -904,5 +941,88 @@ def test_popitem(self): self.assertRaises(KeyError, d.popitem) +class SimpleLRUCache: + + def __init__(self, size): + super().__init__() + self.size = size + self.counts = dict.fromkeys(('get', 'set', 'del'), 0) + + def __getitem__(self, item): + self.counts['get'] += 1 + value = super().__getitem__(item) + self.move_to_end(item) + return value + + def __setitem__(self, key, value): + self.counts['set'] += 1 + while key not in self and len(self) >= self.size: + self.popitem(last=False) + super().__setitem__(key, value) + self.move_to_end(key) + + def __delitem__(self, key): + self.counts['del'] += 1 + super().__delitem__(key) + + +class SimpleLRUCacheTests: + + def test_add_after_full(self): + c = self.type2test(2) + c['t1'] = 1 + c['t2'] = 2 + c['t3'] = 3 + self.assertEqual(c.counts, {'get': 0, 'set': 3, 'del': 0}) + self.assertEqual(list(c), ['t2', 't3']) + self.assertEqual(c.counts, {'get': 0, 'set': 3, 'del': 0}) + + def test_popitem(self): + c = self.type2test(3) + for i in range(1, 4): + c[i] = i + self.assertEqual(c.popitem(last=False), (1, 1)) + self.assertEqual(c.popitem(last=True), (3, 3)) + self.assertEqual(c.counts, {'get': 0, 'set': 3, 'del': 0}) + + def test_pop(self): + c = self.type2test(3) + for i in range(1, 4): + c[i] = i + self.assertEqual(c.counts, {'get': 0, 'set': 3, 'del': 0}) + self.assertEqual(c.pop(2), 2) + self.assertEqual(c.counts, {'get': 0, 'set': 3, 'del': 0}) + self.assertEqual(c.pop(4, 0), 0) + self.assertEqual(c.counts, {'get': 0, 'set': 3, 'del': 0}) + self.assertRaises(KeyError, c.pop, 4) + self.assertEqual(c.counts, {'get': 0, 'set': 3, 'del': 0}) + + def test_change_order_on_get(self): + c = self.type2test(3) + for i in range(1, 4): + c[i] = i + self.assertEqual(list(c), list(range(1, 4))) + self.assertEqual(c.counts, {'get': 0, 'set': 3, 'del': 0}) + self.assertEqual(c[2], 2) + self.assertEqual(c.counts, {'get': 1, 'set': 3, 'del': 0}) + self.assertEqual(list(c), [1, 3, 2]) + + +class PySimpleLRUCacheTests(SimpleLRUCacheTests, unittest.TestCase): + + class type2test(SimpleLRUCache, py_coll.OrderedDict): + pass + + +@unittest.skipUnless(c_coll, 'requires the C version of the collections module') +class CSimpleLRUCacheTests(SimpleLRUCacheTests, unittest.TestCase): + + @classmethod + def setUpClass(cls): + class type2test(SimpleLRUCache, c_coll.OrderedDict): + pass + cls.type2test = type2test + + if __name__ == "__main__": unittest.main()