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