Home | History | Annotate | Download | only in test
      1 """
      2 Test implementation of the PEP 509: dictionary versionning.
      3 """
      4 import unittest
      5 from test import support
      6 
      7 # PEP 509 is implemented in CPython but other Python implementations
      8 # don't require to implement it
      9 _testcapi = support.import_module('_testcapi')
     10 
     11 
     12 class DictVersionTests(unittest.TestCase):
     13     type2test = dict
     14 
     15     def setUp(self):
     16         self.seen_versions = set()
     17         self.dict = None
     18 
     19     def check_version_unique(self, mydict):
     20         version = _testcapi.dict_get_version(mydict)
     21         self.assertNotIn(version, self.seen_versions)
     22         self.seen_versions.add(version)
     23 
     24     def check_version_changed(self, mydict, method, *args, **kw):
     25         result = method(*args, **kw)
     26         self.check_version_unique(mydict)
     27         return result
     28 
     29     def check_version_dont_change(self, mydict, method, *args, **kw):
     30         version1 = _testcapi.dict_get_version(mydict)
     31         self.seen_versions.add(version1)
     32 
     33         result = method(*args, **kw)
     34 
     35         version2 = _testcapi.dict_get_version(mydict)
     36         self.assertEqual(version2, version1, "version changed")
     37 
     38         return  result
     39 
     40     def new_dict(self, *args, **kw):
     41         d = self.type2test(*args, **kw)
     42         self.check_version_unique(d)
     43         return d
     44 
     45     def test_constructor(self):
     46         # new empty dictionaries must all have an unique version
     47         empty1 = self.new_dict()
     48         empty2 = self.new_dict()
     49         empty3 = self.new_dict()
     50 
     51         # non-empty dictionaries must also have an unique version
     52         nonempty1 = self.new_dict(x='x')
     53         nonempty2 = self.new_dict(x='x', y='y')
     54 
     55     def test_copy(self):
     56         d = self.new_dict(a=1, b=2)
     57 
     58         d2 = self.check_version_dont_change(d, d.copy)
     59 
     60         # dict.copy() must create a dictionary with a new unique version
     61         self.check_version_unique(d2)
     62 
     63     def test_setitem(self):
     64         d = self.new_dict()
     65 
     66         # creating new keys must change the version
     67         self.check_version_changed(d, d.__setitem__, 'x', 'x')
     68         self.check_version_changed(d, d.__setitem__, 'y', 'y')
     69 
     70         # changing values must change the version
     71         self.check_version_changed(d, d.__setitem__, 'x', 1)
     72         self.check_version_changed(d, d.__setitem__, 'y', 2)
     73 
     74     def test_setitem_same_value(self):
     75         value = object()
     76         d = self.new_dict()
     77 
     78         # setting a key must change the version
     79         self.check_version_changed(d, d.__setitem__, 'key', value)
     80 
     81         # setting a key to the same value with dict.__setitem__
     82         # must change the version
     83         self.check_version_changed(d, d.__setitem__, 'key', value)
     84 
     85         # setting a key to the same value with dict.update
     86         # must change the version
     87         self.check_version_changed(d, d.update, key=value)
     88 
     89         d2 = self.new_dict(key=value)
     90         self.check_version_changed(d, d.update, d2)
     91 
     92     def test_setitem_equal(self):
     93         class AlwaysEqual:
     94             def __eq__(self, other):
     95                 return True
     96 
     97         value1 = AlwaysEqual()
     98         value2 = AlwaysEqual()
     99         self.assertTrue(value1 == value2)
    100         self.assertFalse(value1 != value2)
    101 
    102         d = self.new_dict()
    103         self.check_version_changed(d, d.__setitem__, 'key', value1)
    104 
    105         # setting a key to a value equal to the current value
    106         # with dict.__setitem__() must change the version
    107         self.check_version_changed(d, d.__setitem__, 'key', value2)
    108 
    109         # setting a key to a value equal to the current value
    110         # with dict.update() must change the version
    111         self.check_version_changed(d, d.update, key=value1)
    112 
    113         d2 = self.new_dict(key=value2)
    114         self.check_version_changed(d, d.update, d2)
    115 
    116     def test_setdefault(self):
    117         d = self.new_dict()
    118 
    119         # setting a key with dict.setdefault() must change the version
    120         self.check_version_changed(d, d.setdefault, 'key', 'value1')
    121 
    122         # don't change the version if the key already exists
    123         self.check_version_dont_change(d, d.setdefault, 'key', 'value2')
    124 
    125     def test_delitem(self):
    126         d = self.new_dict(key='value')
    127 
    128         # deleting a key with dict.__delitem__() must change the version
    129         self.check_version_changed(d, d.__delitem__, 'key')
    130 
    131         # don't change the version if the key doesn't exist
    132         self.check_version_dont_change(d, self.assertRaises, KeyError,
    133                                        d.__delitem__, 'key')
    134 
    135     def test_pop(self):
    136         d = self.new_dict(key='value')
    137 
    138         # pop() must change the version if the key exists
    139         self.check_version_changed(d, d.pop, 'key')
    140 
    141         # pop() must not change the version if the key does not exist
    142         self.check_version_dont_change(d, self.assertRaises, KeyError,
    143                                        d.pop, 'key')
    144 
    145     def test_popitem(self):
    146         d = self.new_dict(key='value')
    147 
    148         # popitem() must change the version if the dict is not empty
    149         self.check_version_changed(d, d.popitem)
    150 
    151         # popitem() must not change the version if the dict is empty
    152         self.check_version_dont_change(d, self.assertRaises, KeyError,
    153                                        d.popitem)
    154 
    155     def test_update(self):
    156         d = self.new_dict(key='value')
    157 
    158         # update() calling with no argument must not change the version
    159         self.check_version_dont_change(d, d.update)
    160 
    161         # update() must change the version
    162         self.check_version_changed(d, d.update, key='new value')
    163 
    164         d2 = self.new_dict(key='value 3')
    165         self.check_version_changed(d, d.update, d2)
    166 
    167     def test_clear(self):
    168         d = self.new_dict(key='value')
    169 
    170         # clear() must change the version if the dict is not empty
    171         self.check_version_changed(d, d.clear)
    172 
    173         # clear() must not change the version if the dict is empty
    174         self.check_version_dont_change(d, d.clear)
    175 
    176 
    177 class Dict(dict):
    178     pass
    179 
    180 
    181 class DictSubtypeVersionTests(DictVersionTests):
    182     type2test = Dict
    183 
    184 
    185 if __name__ == "__main__":
    186     unittest.main()
    187