17db96d56Sopenharmony_ci"""
27db96d56Sopenharmony_ciTest implementation of the PEP 509: dictionary versioning.
37db96d56Sopenharmony_ci"""
47db96d56Sopenharmony_ciimport unittest
57db96d56Sopenharmony_cifrom test.support import import_helper
67db96d56Sopenharmony_ci
77db96d56Sopenharmony_ci# PEP 509 is implemented in CPython but other Python implementations
87db96d56Sopenharmony_ci# don't require to implement it
97db96d56Sopenharmony_ci_testcapi = import_helper.import_module('_testcapi')
107db96d56Sopenharmony_ci
117db96d56Sopenharmony_ci
127db96d56Sopenharmony_ciclass DictVersionTests(unittest.TestCase):
137db96d56Sopenharmony_ci    type2test = dict
147db96d56Sopenharmony_ci
157db96d56Sopenharmony_ci    def setUp(self):
167db96d56Sopenharmony_ci        self.seen_versions = set()
177db96d56Sopenharmony_ci        self.dict = None
187db96d56Sopenharmony_ci
197db96d56Sopenharmony_ci    def check_version_unique(self, mydict):
207db96d56Sopenharmony_ci        version = _testcapi.dict_get_version(mydict)
217db96d56Sopenharmony_ci        self.assertNotIn(version, self.seen_versions)
227db96d56Sopenharmony_ci        self.seen_versions.add(version)
237db96d56Sopenharmony_ci
247db96d56Sopenharmony_ci    def check_version_changed(self, mydict, method, *args, **kw):
257db96d56Sopenharmony_ci        result = method(*args, **kw)
267db96d56Sopenharmony_ci        self.check_version_unique(mydict)
277db96d56Sopenharmony_ci        return result
287db96d56Sopenharmony_ci
297db96d56Sopenharmony_ci    def check_version_dont_change(self, mydict, method, *args, **kw):
307db96d56Sopenharmony_ci        version1 = _testcapi.dict_get_version(mydict)
317db96d56Sopenharmony_ci        self.seen_versions.add(version1)
327db96d56Sopenharmony_ci
337db96d56Sopenharmony_ci        result = method(*args, **kw)
347db96d56Sopenharmony_ci
357db96d56Sopenharmony_ci        version2 = _testcapi.dict_get_version(mydict)
367db96d56Sopenharmony_ci        self.assertEqual(version2, version1, "version changed")
377db96d56Sopenharmony_ci
387db96d56Sopenharmony_ci        return  result
397db96d56Sopenharmony_ci
407db96d56Sopenharmony_ci    def new_dict(self, *args, **kw):
417db96d56Sopenharmony_ci        d = self.type2test(*args, **kw)
427db96d56Sopenharmony_ci        self.check_version_unique(d)
437db96d56Sopenharmony_ci        return d
447db96d56Sopenharmony_ci
457db96d56Sopenharmony_ci    def test_constructor(self):
467db96d56Sopenharmony_ci        # new empty dictionaries must all have an unique version
477db96d56Sopenharmony_ci        empty1 = self.new_dict()
487db96d56Sopenharmony_ci        empty2 = self.new_dict()
497db96d56Sopenharmony_ci        empty3 = self.new_dict()
507db96d56Sopenharmony_ci
517db96d56Sopenharmony_ci        # non-empty dictionaries must also have an unique version
527db96d56Sopenharmony_ci        nonempty1 = self.new_dict(x='x')
537db96d56Sopenharmony_ci        nonempty2 = self.new_dict(x='x', y='y')
547db96d56Sopenharmony_ci
557db96d56Sopenharmony_ci    def test_copy(self):
567db96d56Sopenharmony_ci        d = self.new_dict(a=1, b=2)
577db96d56Sopenharmony_ci
587db96d56Sopenharmony_ci        d2 = self.check_version_dont_change(d, d.copy)
597db96d56Sopenharmony_ci
607db96d56Sopenharmony_ci        # dict.copy() must create a dictionary with a new unique version
617db96d56Sopenharmony_ci        self.check_version_unique(d2)
627db96d56Sopenharmony_ci
637db96d56Sopenharmony_ci    def test_setitem(self):
647db96d56Sopenharmony_ci        d = self.new_dict()
657db96d56Sopenharmony_ci
667db96d56Sopenharmony_ci        # creating new keys must change the version
677db96d56Sopenharmony_ci        self.check_version_changed(d, d.__setitem__, 'x', 'x')
687db96d56Sopenharmony_ci        self.check_version_changed(d, d.__setitem__, 'y', 'y')
697db96d56Sopenharmony_ci
707db96d56Sopenharmony_ci        # changing values must change the version
717db96d56Sopenharmony_ci        self.check_version_changed(d, d.__setitem__, 'x', 1)
727db96d56Sopenharmony_ci        self.check_version_changed(d, d.__setitem__, 'y', 2)
737db96d56Sopenharmony_ci
747db96d56Sopenharmony_ci    def test_setitem_same_value(self):
757db96d56Sopenharmony_ci        value = object()
767db96d56Sopenharmony_ci        d = self.new_dict()
777db96d56Sopenharmony_ci
787db96d56Sopenharmony_ci        # setting a key must change the version
797db96d56Sopenharmony_ci        self.check_version_changed(d, d.__setitem__, 'key', value)
807db96d56Sopenharmony_ci
817db96d56Sopenharmony_ci        # setting a key to the same value with dict.__setitem__
827db96d56Sopenharmony_ci        # must change the version
837db96d56Sopenharmony_ci        self.check_version_dont_change(d, d.__setitem__, 'key', value)
847db96d56Sopenharmony_ci
857db96d56Sopenharmony_ci        # setting a key to the same value with dict.update
867db96d56Sopenharmony_ci        # must change the version
877db96d56Sopenharmony_ci        self.check_version_dont_change(d, d.update, key=value)
887db96d56Sopenharmony_ci
897db96d56Sopenharmony_ci        d2 = self.new_dict(key=value)
907db96d56Sopenharmony_ci        self.check_version_dont_change(d, d.update, d2)
917db96d56Sopenharmony_ci
927db96d56Sopenharmony_ci    def test_setitem_equal(self):
937db96d56Sopenharmony_ci        class AlwaysEqual:
947db96d56Sopenharmony_ci            def __eq__(self, other):
957db96d56Sopenharmony_ci                return True
967db96d56Sopenharmony_ci
977db96d56Sopenharmony_ci        value1 = AlwaysEqual()
987db96d56Sopenharmony_ci        value2 = AlwaysEqual()
997db96d56Sopenharmony_ci        self.assertTrue(value1 == value2)
1007db96d56Sopenharmony_ci        self.assertFalse(value1 != value2)
1017db96d56Sopenharmony_ci        self.assertIsNot(value1, value2)
1027db96d56Sopenharmony_ci
1037db96d56Sopenharmony_ci        d = self.new_dict()
1047db96d56Sopenharmony_ci        self.check_version_changed(d, d.__setitem__, 'key', value1)
1057db96d56Sopenharmony_ci        self.assertIs(d['key'], value1)
1067db96d56Sopenharmony_ci
1077db96d56Sopenharmony_ci        # setting a key to a value equal to the current value
1087db96d56Sopenharmony_ci        # with dict.__setitem__() must change the version
1097db96d56Sopenharmony_ci        self.check_version_changed(d, d.__setitem__, 'key', value2)
1107db96d56Sopenharmony_ci        self.assertIs(d['key'], value2)
1117db96d56Sopenharmony_ci
1127db96d56Sopenharmony_ci        # setting a key to a value equal to the current value
1137db96d56Sopenharmony_ci        # with dict.update() must change the version
1147db96d56Sopenharmony_ci        self.check_version_changed(d, d.update, key=value1)
1157db96d56Sopenharmony_ci        self.assertIs(d['key'], value1)
1167db96d56Sopenharmony_ci
1177db96d56Sopenharmony_ci        d2 = self.new_dict(key=value2)
1187db96d56Sopenharmony_ci        self.check_version_changed(d, d.update, d2)
1197db96d56Sopenharmony_ci        self.assertIs(d['key'], value2)
1207db96d56Sopenharmony_ci
1217db96d56Sopenharmony_ci    def test_setdefault(self):
1227db96d56Sopenharmony_ci        d = self.new_dict()
1237db96d56Sopenharmony_ci
1247db96d56Sopenharmony_ci        # setting a key with dict.setdefault() must change the version
1257db96d56Sopenharmony_ci        self.check_version_changed(d, d.setdefault, 'key', 'value1')
1267db96d56Sopenharmony_ci
1277db96d56Sopenharmony_ci        # don't change the version if the key already exists
1287db96d56Sopenharmony_ci        self.check_version_dont_change(d, d.setdefault, 'key', 'value2')
1297db96d56Sopenharmony_ci
1307db96d56Sopenharmony_ci    def test_delitem(self):
1317db96d56Sopenharmony_ci        d = self.new_dict(key='value')
1327db96d56Sopenharmony_ci
1337db96d56Sopenharmony_ci        # deleting a key with dict.__delitem__() must change the version
1347db96d56Sopenharmony_ci        self.check_version_changed(d, d.__delitem__, 'key')
1357db96d56Sopenharmony_ci
1367db96d56Sopenharmony_ci        # don't change the version if the key doesn't exist
1377db96d56Sopenharmony_ci        self.check_version_dont_change(d, self.assertRaises, KeyError,
1387db96d56Sopenharmony_ci                                       d.__delitem__, 'key')
1397db96d56Sopenharmony_ci
1407db96d56Sopenharmony_ci    def test_pop(self):
1417db96d56Sopenharmony_ci        d = self.new_dict(key='value')
1427db96d56Sopenharmony_ci
1437db96d56Sopenharmony_ci        # pop() must change the version if the key exists
1447db96d56Sopenharmony_ci        self.check_version_changed(d, d.pop, 'key')
1457db96d56Sopenharmony_ci
1467db96d56Sopenharmony_ci        # pop() must not change the version if the key does not exist
1477db96d56Sopenharmony_ci        self.check_version_dont_change(d, self.assertRaises, KeyError,
1487db96d56Sopenharmony_ci                                       d.pop, 'key')
1497db96d56Sopenharmony_ci
1507db96d56Sopenharmony_ci    def test_popitem(self):
1517db96d56Sopenharmony_ci        d = self.new_dict(key='value')
1527db96d56Sopenharmony_ci
1537db96d56Sopenharmony_ci        # popitem() must change the version if the dict is not empty
1547db96d56Sopenharmony_ci        self.check_version_changed(d, d.popitem)
1557db96d56Sopenharmony_ci
1567db96d56Sopenharmony_ci        # popitem() must not change the version if the dict is empty
1577db96d56Sopenharmony_ci        self.check_version_dont_change(d, self.assertRaises, KeyError,
1587db96d56Sopenharmony_ci                                       d.popitem)
1597db96d56Sopenharmony_ci
1607db96d56Sopenharmony_ci    def test_update(self):
1617db96d56Sopenharmony_ci        d = self.new_dict(key='value')
1627db96d56Sopenharmony_ci
1637db96d56Sopenharmony_ci        # update() calling with no argument must not change the version
1647db96d56Sopenharmony_ci        self.check_version_dont_change(d, d.update)
1657db96d56Sopenharmony_ci
1667db96d56Sopenharmony_ci        # update() must change the version
1677db96d56Sopenharmony_ci        self.check_version_changed(d, d.update, key='new value')
1687db96d56Sopenharmony_ci
1697db96d56Sopenharmony_ci        d2 = self.new_dict(key='value 3')
1707db96d56Sopenharmony_ci        self.check_version_changed(d, d.update, d2)
1717db96d56Sopenharmony_ci
1727db96d56Sopenharmony_ci    def test_clear(self):
1737db96d56Sopenharmony_ci        d = self.new_dict(key='value')
1747db96d56Sopenharmony_ci
1757db96d56Sopenharmony_ci        # clear() must change the version if the dict is not empty
1767db96d56Sopenharmony_ci        self.check_version_changed(d, d.clear)
1777db96d56Sopenharmony_ci
1787db96d56Sopenharmony_ci        # clear() must not change the version if the dict is empty
1797db96d56Sopenharmony_ci        self.check_version_dont_change(d, d.clear)
1807db96d56Sopenharmony_ci
1817db96d56Sopenharmony_ci
1827db96d56Sopenharmony_ciclass Dict(dict):
1837db96d56Sopenharmony_ci    pass
1847db96d56Sopenharmony_ci
1857db96d56Sopenharmony_ci
1867db96d56Sopenharmony_ciclass DictSubtypeVersionTests(DictVersionTests):
1877db96d56Sopenharmony_ci    type2test = Dict
1887db96d56Sopenharmony_ci
1897db96d56Sopenharmony_ci
1907db96d56Sopenharmony_ciif __name__ == "__main__":
1917db96d56Sopenharmony_ci    unittest.main()
192