Home | History | Annotate | Download | only in test
      1 # tests common to dict and UserDict
      2 import unittest
      3 import collections
      4 
      5 
      6 class BasicTestMappingProtocol(unittest.TestCase):
      7     # This base class can be used to check that an object conforms to the
      8     # mapping protocol
      9 
     10     # Functions that can be useful to override to adapt to dictionary
     11     # semantics
     12     type2test = None # which class is being tested (overwrite in subclasses)
     13 
     14     def _reference(self):
     15         """Return a dictionary of values which are invariant by storage
     16         in the object under test."""
     17         return {"1": "2", "key1":"value1", "key2":(1,2,3)}
     18     def _empty_mapping(self):
     19         """Return an empty mapping object"""
     20         return self.type2test()
     21     def _full_mapping(self, data):
     22         """Return a mapping object with the value contained in data
     23         dictionary"""
     24         x = self._empty_mapping()
     25         for key, value in data.items():
     26             x[key] = value
     27         return x
     28 
     29     def __init__(self, *args, **kw):
     30         unittest.TestCase.__init__(self, *args, **kw)
     31         self.reference = self._reference().copy()
     32 
     33         # A (key, value) pair not in the mapping
     34         key, value = self.reference.popitem()
     35         self.other = {key:value}
     36 
     37         # A (key, value) pair in the mapping
     38         key, value = self.reference.popitem()
     39         self.inmapping = {key:value}
     40         self.reference[key] = value
     41 
     42     def test_read(self):
     43         # Test for read only operations on mapping
     44         p = self._empty_mapping()
     45         p1 = dict(p) #workaround for singleton objects
     46         d = self._full_mapping(self.reference)
     47         if d is p:
     48             p = p1
     49         #Indexing
     50         for key, value in self.reference.items():
     51             self.assertEqual(d[key], value)
     52         knownkey = list(self.other.keys())[0]
     53         self.assertRaises(KeyError, lambda:d[knownkey])
     54         #len
     55         self.assertEqual(len(p), 0)
     56         self.assertEqual(len(d), len(self.reference))
     57         #__contains__
     58         for k in self.reference:
     59             self.assertIn(k, d)
     60         for k in self.other:
     61             self.assertNotIn(k, d)
     62         #cmp
     63         self.assertEqual(p, p)
     64         self.assertEqual(d, d)
     65         self.assertNotEqual(p, d)
     66         self.assertNotEqual(d, p)
     67         #bool
     68         if p: self.fail("Empty mapping must compare to False")
     69         if not d: self.fail("Full mapping must compare to True")
     70         # keys(), items(), iterkeys() ...
     71         def check_iterandlist(iter, lst, ref):
     72             self.assertTrue(hasattr(iter, '__next__'))
     73             self.assertTrue(hasattr(iter, '__iter__'))
     74             x = list(iter)
     75             self.assertTrue(set(x)==set(lst)==set(ref))
     76         check_iterandlist(iter(d.keys()), list(d.keys()),
     77                           self.reference.keys())
     78         check_iterandlist(iter(d), list(d.keys()), self.reference.keys())
     79         check_iterandlist(iter(d.values()), list(d.values()),
     80                           self.reference.values())
     81         check_iterandlist(iter(d.items()), list(d.items()),
     82                           self.reference.items())
     83         #get
     84         key, value = next(iter(d.items()))
     85         knownkey, knownvalue = next(iter(self.other.items()))
     86         self.assertEqual(d.get(key, knownvalue), value)
     87         self.assertEqual(d.get(knownkey, knownvalue), knownvalue)
     88         self.assertNotIn(knownkey, d)
     89 
     90     def test_write(self):
     91         # Test for write operations on mapping
     92         p = self._empty_mapping()
     93         #Indexing
     94         for key, value in self.reference.items():
     95             p[key] = value
     96             self.assertEqual(p[key], value)
     97         for key in self.reference.keys():
     98             del p[key]
     99             self.assertRaises(KeyError, lambda:p[key])
    100         p = self._empty_mapping()
    101         #update
    102         p.update(self.reference)
    103         self.assertEqual(dict(p), self.reference)
    104         items = list(p.items())
    105         p = self._empty_mapping()
    106         p.update(items)
    107         self.assertEqual(dict(p), self.reference)
    108         d = self._full_mapping(self.reference)
    109         #setdefault
    110         key, value = next(iter(d.items()))
    111         knownkey, knownvalue = next(iter(self.other.items()))
    112         self.assertEqual(d.setdefault(key, knownvalue), value)
    113         self.assertEqual(d[key], value)
    114         self.assertEqual(d.setdefault(knownkey, knownvalue), knownvalue)
    115         self.assertEqual(d[knownkey], knownvalue)
    116         #pop
    117         self.assertEqual(d.pop(knownkey), knownvalue)
    118         self.assertNotIn(knownkey, d)
    119         self.assertRaises(KeyError, d.pop, knownkey)
    120         default = 909
    121         d[knownkey] = knownvalue
    122         self.assertEqual(d.pop(knownkey, default), knownvalue)
    123         self.assertNotIn(knownkey, d)
    124         self.assertEqual(d.pop(knownkey, default), default)
    125         #popitem
    126         key, value = d.popitem()
    127         self.assertNotIn(key, d)
    128         self.assertEqual(value, self.reference[key])
    129         p=self._empty_mapping()
    130         self.assertRaises(KeyError, p.popitem)
    131 
    132     def test_constructor(self):
    133         self.assertEqual(self._empty_mapping(), self._empty_mapping())
    134 
    135     def test_bool(self):
    136         self.assertTrue(not self._empty_mapping())
    137         self.assertTrue(self.reference)
    138         self.assertTrue(bool(self._empty_mapping()) is False)
    139         self.assertTrue(bool(self.reference) is True)
    140 
    141     def test_keys(self):
    142         d = self._empty_mapping()
    143         self.assertEqual(list(d.keys()), [])
    144         d = self.reference
    145         self.assertIn(list(self.inmapping.keys())[0], d.keys())
    146         self.assertNotIn(list(self.other.keys())[0], d.keys())
    147         self.assertRaises(TypeError, d.keys, None)
    148 
    149     def test_values(self):
    150         d = self._empty_mapping()
    151         self.assertEqual(list(d.values()), [])
    152 
    153         self.assertRaises(TypeError, d.values, None)
    154 
    155     def test_items(self):
    156         d = self._empty_mapping()
    157         self.assertEqual(list(d.items()), [])
    158 
    159         self.assertRaises(TypeError, d.items, None)
    160 
    161     def test_len(self):
    162         d = self._empty_mapping()
    163         self.assertEqual(len(d), 0)
    164 
    165     def test_getitem(self):
    166         d = self.reference
    167         self.assertEqual(d[list(self.inmapping.keys())[0]],
    168                          list(self.inmapping.values())[0])
    169 
    170         self.assertRaises(TypeError, d.__getitem__)
    171 
    172     def test_update(self):
    173         # mapping argument
    174         d = self._empty_mapping()
    175         d.update(self.other)
    176         self.assertEqual(list(d.items()), list(self.other.items()))
    177 
    178         # No argument
    179         d = self._empty_mapping()
    180         d.update()
    181         self.assertEqual(d, self._empty_mapping())
    182 
    183         # item sequence
    184         d = self._empty_mapping()
    185         d.update(self.other.items())
    186         self.assertEqual(list(d.items()), list(self.other.items()))
    187 
    188         # Iterator
    189         d = self._empty_mapping()
    190         d.update(self.other.items())
    191         self.assertEqual(list(d.items()), list(self.other.items()))
    192 
    193         # FIXME: Doesn't work with UserDict
    194         # self.assertRaises((TypeError, AttributeError), d.update, None)
    195         self.assertRaises((TypeError, AttributeError), d.update, 42)
    196 
    197         outerself = self
    198         class SimpleUserDict:
    199             def __init__(self):
    200                 self.d = outerself.reference
    201             def keys(self):
    202                 return self.d.keys()
    203             def __getitem__(self, i):
    204                 return self.d[i]
    205         d.clear()
    206         d.update(SimpleUserDict())
    207         i1 = sorted(d.items())
    208         i2 = sorted(self.reference.items())
    209         self.assertEqual(i1, i2)
    210 
    211         class Exc(Exception): pass
    212 
    213         d = self._empty_mapping()
    214         class FailingUserDict:
    215             def keys(self):
    216                 raise Exc
    217         self.assertRaises(Exc, d.update, FailingUserDict())
    218 
    219         d.clear()
    220 
    221         class FailingUserDict:
    222             def keys(self):
    223                 class BogonIter:
    224                     def __init__(self):
    225                         self.i = 1
    226                     def __iter__(self):
    227                         return self
    228                     def __next__(self):
    229                         if self.i:
    230                             self.i = 0
    231                             return 'a'
    232                         raise Exc
    233                 return BogonIter()
    234             def __getitem__(self, key):
    235                 return key
    236         self.assertRaises(Exc, d.update, FailingUserDict())
    237 
    238         class FailingUserDict:
    239             def keys(self):
    240                 class BogonIter:
    241                     def __init__(self):
    242                         self.i = ord('a')
    243                     def __iter__(self):
    244                         return self
    245                     def __next__(self):
    246                         if self.i <= ord('z'):
    247                             rtn = chr(self.i)
    248                             self.i += 1
    249                             return rtn
    250                         raise StopIteration
    251                 return BogonIter()
    252             def __getitem__(self, key):
    253                 raise Exc
    254         self.assertRaises(Exc, d.update, FailingUserDict())
    255 
    256         d = self._empty_mapping()
    257         class badseq(object):
    258             def __iter__(self):
    259                 return self
    260             def __next__(self):
    261                 raise Exc()
    262 
    263         self.assertRaises(Exc, d.update, badseq())
    264 
    265         self.assertRaises(ValueError, d.update, [(1, 2, 3)])
    266 
    267     # no test_fromkeys or test_copy as both os.environ and selves don't support it
    268 
    269     def test_get(self):
    270         d = self._empty_mapping()
    271         self.assertTrue(d.get(list(self.other.keys())[0]) is None)
    272         self.assertEqual(d.get(list(self.other.keys())[0], 3), 3)
    273         d = self.reference
    274         self.assertTrue(d.get(list(self.other.keys())[0]) is None)
    275         self.assertEqual(d.get(list(self.other.keys())[0], 3), 3)
    276         self.assertEqual(d.get(list(self.inmapping.keys())[0]),
    277                          list(self.inmapping.values())[0])
    278         self.assertEqual(d.get(list(self.inmapping.keys())[0], 3),
    279                          list(self.inmapping.values())[0])
    280         self.assertRaises(TypeError, d.get)
    281         self.assertRaises(TypeError, d.get, None, None, None)
    282 
    283     def test_setdefault(self):
    284         d = self._empty_mapping()
    285         self.assertRaises(TypeError, d.setdefault)
    286 
    287     def test_popitem(self):
    288         d = self._empty_mapping()
    289         self.assertRaises(KeyError, d.popitem)
    290         self.assertRaises(TypeError, d.popitem, 42)
    291 
    292     def test_pop(self):
    293         d = self._empty_mapping()
    294         k, v = list(self.inmapping.items())[0]
    295         d[k] = v
    296         self.assertRaises(KeyError, d.pop, list(self.other.keys())[0])
    297 
    298         self.assertEqual(d.pop(k), v)
    299         self.assertEqual(len(d), 0)
    300 
    301         self.assertRaises(KeyError, d.pop, k)
    302 
    303 
    304 class TestMappingProtocol(BasicTestMappingProtocol):
    305     def test_constructor(self):
    306         BasicTestMappingProtocol.test_constructor(self)
    307         self.assertTrue(self._empty_mapping() is not self._empty_mapping())
    308         self.assertEqual(self.type2test(x=1, y=2), {"x": 1, "y": 2})
    309 
    310     def test_bool(self):
    311         BasicTestMappingProtocol.test_bool(self)
    312         self.assertTrue(not self._empty_mapping())
    313         self.assertTrue(self._full_mapping({"x": "y"}))
    314         self.assertTrue(bool(self._empty_mapping()) is False)
    315         self.assertTrue(bool(self._full_mapping({"x": "y"})) is True)
    316 
    317     def test_keys(self):
    318         BasicTestMappingProtocol.test_keys(self)
    319         d = self._empty_mapping()
    320         self.assertEqual(list(d.keys()), [])
    321         d = self._full_mapping({'a': 1, 'b': 2})
    322         k = d.keys()
    323         self.assertIn('a', k)
    324         self.assertIn('b', k)
    325         self.assertNotIn('c', k)
    326 
    327     def test_values(self):
    328         BasicTestMappingProtocol.test_values(self)
    329         d = self._full_mapping({1:2})
    330         self.assertEqual(list(d.values()), [2])
    331 
    332     def test_items(self):
    333         BasicTestMappingProtocol.test_items(self)
    334 
    335         d = self._full_mapping({1:2})
    336         self.assertEqual(list(d.items()), [(1, 2)])
    337 
    338     def test_contains(self):
    339         d = self._empty_mapping()
    340         self.assertNotIn('a', d)
    341         self.assertTrue(not ('a' in d))
    342         self.assertTrue('a' not in d)
    343         d = self._full_mapping({'a': 1, 'b': 2})
    344         self.assertIn('a', d)
    345         self.assertIn('b', d)
    346         self.assertNotIn('c', d)
    347 
    348         self.assertRaises(TypeError, d.__contains__)
    349 
    350     def test_len(self):
    351         BasicTestMappingProtocol.test_len(self)
    352         d = self._full_mapping({'a': 1, 'b': 2})
    353         self.assertEqual(len(d), 2)
    354 
    355     def test_getitem(self):
    356         BasicTestMappingProtocol.test_getitem(self)
    357         d = self._full_mapping({'a': 1, 'b': 2})
    358         self.assertEqual(d['a'], 1)
    359         self.assertEqual(d['b'], 2)
    360         d['c'] = 3
    361         d['a'] = 4
    362         self.assertEqual(d['c'], 3)
    363         self.assertEqual(d['a'], 4)
    364         del d['b']
    365         self.assertEqual(d, {'a': 4, 'c': 3})
    366 
    367         self.assertRaises(TypeError, d.__getitem__)
    368 
    369     def test_clear(self):
    370         d = self._full_mapping({1:1, 2:2, 3:3})
    371         d.clear()
    372         self.assertEqual(d, {})
    373 
    374         self.assertRaises(TypeError, d.clear, None)
    375 
    376     def test_update(self):
    377         BasicTestMappingProtocol.test_update(self)
    378         # mapping argument
    379         d = self._empty_mapping()
    380         d.update({1:100})
    381         d.update({2:20})
    382         d.update({1:1, 2:2, 3:3})
    383         self.assertEqual(d, {1:1, 2:2, 3:3})
    384 
    385         # no argument
    386         d.update()
    387         self.assertEqual(d, {1:1, 2:2, 3:3})
    388 
    389         # keyword arguments
    390         d = self._empty_mapping()
    391         d.update(x=100)
    392         d.update(y=20)
    393         d.update(x=1, y=2, z=3)
    394         self.assertEqual(d, {"x":1, "y":2, "z":3})
    395 
    396         # item sequence
    397         d = self._empty_mapping()
    398         d.update([("x", 100), ("y", 20)])
    399         self.assertEqual(d, {"x":100, "y":20})
    400 
    401         # Both item sequence and keyword arguments
    402         d = self._empty_mapping()
    403         d.update([("x", 100), ("y", 20)], x=1, y=2)
    404         self.assertEqual(d, {"x":1, "y":2})
    405 
    406         # iterator
    407         d = self._full_mapping({1:3, 2:4})
    408         d.update(self._full_mapping({1:2, 3:4, 5:6}).items())
    409         self.assertEqual(d, {1:2, 2:4, 3:4, 5:6})
    410 
    411         class SimpleUserDict:
    412             def __init__(self):
    413                 self.d = {1:1, 2:2, 3:3}
    414             def keys(self):
    415                 return self.d.keys()
    416             def __getitem__(self, i):
    417                 return self.d[i]
    418         d.clear()
    419         d.update(SimpleUserDict())
    420         self.assertEqual(d, {1:1, 2:2, 3:3})
    421 
    422     def test_fromkeys(self):
    423         self.assertEqual(self.type2test.fromkeys('abc'), {'a':None, 'b':None, 'c':None})
    424         d = self._empty_mapping()
    425         self.assertTrue(not(d.fromkeys('abc') is d))
    426         self.assertEqual(d.fromkeys('abc'), {'a':None, 'b':None, 'c':None})
    427         self.assertEqual(d.fromkeys((4,5),0), {4:0, 5:0})
    428         self.assertEqual(d.fromkeys([]), {})
    429         def g():
    430             yield 1
    431         self.assertEqual(d.fromkeys(g()), {1:None})
    432         self.assertRaises(TypeError, {}.fromkeys, 3)
    433         class dictlike(self.type2test): pass
    434         self.assertEqual(dictlike.fromkeys('a'), {'a':None})
    435         self.assertEqual(dictlike().fromkeys('a'), {'a':None})
    436         self.assertTrue(dictlike.fromkeys('a').__class__ is dictlike)
    437         self.assertTrue(dictlike().fromkeys('a').__class__ is dictlike)
    438         self.assertTrue(type(dictlike.fromkeys('a')) is dictlike)
    439         class mydict(self.type2test):
    440             def __new__(cls):
    441                 return collections.UserDict()
    442         ud = mydict.fromkeys('ab')
    443         self.assertEqual(ud, {'a':None, 'b':None})
    444         self.assertIsInstance(ud, collections.UserDict)
    445         self.assertRaises(TypeError, dict.fromkeys)
    446 
    447         class Exc(Exception): pass
    448 
    449         class baddict1(self.type2test):
    450             def __init__(self):
    451                 raise Exc()
    452 
    453         self.assertRaises(Exc, baddict1.fromkeys, [1])
    454 
    455         class BadSeq(object):
    456             def __iter__(self):
    457                 return self
    458             def __next__(self):
    459                 raise Exc()
    460 
    461         self.assertRaises(Exc, self.type2test.fromkeys, BadSeq())
    462 
    463         class baddict2(self.type2test):
    464             def __setitem__(self, key, value):
    465                 raise Exc()
    466 
    467         self.assertRaises(Exc, baddict2.fromkeys, [1])
    468 
    469     def test_copy(self):
    470         d = self._full_mapping({1:1, 2:2, 3:3})
    471         self.assertEqual(d.copy(), {1:1, 2:2, 3:3})
    472         d = self._empty_mapping()
    473         self.assertEqual(d.copy(), d)
    474         self.assertIsInstance(d.copy(), d.__class__)
    475         self.assertRaises(TypeError, d.copy, None)
    476 
    477     def test_get(self):
    478         BasicTestMappingProtocol.test_get(self)
    479         d = self._empty_mapping()
    480         self.assertTrue(d.get('c') is None)
    481         self.assertEqual(d.get('c', 3), 3)
    482         d = self._full_mapping({'a' : 1, 'b' : 2})
    483         self.assertTrue(d.get('c') is None)
    484         self.assertEqual(d.get('c', 3), 3)
    485         self.assertEqual(d.get('a'), 1)
    486         self.assertEqual(d.get('a', 3), 1)
    487 
    488     def test_setdefault(self):
    489         BasicTestMappingProtocol.test_setdefault(self)
    490         d = self._empty_mapping()
    491         self.assertTrue(d.setdefault('key0') is None)
    492         d.setdefault('key0', [])
    493         self.assertTrue(d.setdefault('key0') is None)
    494         d.setdefault('key', []).append(3)
    495         self.assertEqual(d['key'][0], 3)
    496         d.setdefault('key', []).append(4)
    497         self.assertEqual(len(d['key']), 2)
    498 
    499     def test_popitem(self):
    500         BasicTestMappingProtocol.test_popitem(self)
    501         for copymode in -1, +1:
    502             # -1: b has same structure as a
    503             # +1: b is a.copy()
    504             for log2size in range(12):
    505                 size = 2**log2size
    506                 a = self._empty_mapping()
    507                 b = self._empty_mapping()
    508                 for i in range(size):
    509                     a[repr(i)] = i
    510                     if copymode < 0:
    511                         b[repr(i)] = i
    512                 if copymode > 0:
    513                     b = a.copy()
    514                 for i in range(size):
    515                     ka, va = ta = a.popitem()
    516                     self.assertEqual(va, int(ka))
    517                     kb, vb = tb = b.popitem()
    518                     self.assertEqual(vb, int(kb))
    519                     self.assertTrue(not(copymode < 0 and ta != tb))
    520                 self.assertTrue(not a)
    521                 self.assertTrue(not b)
    522 
    523     def test_pop(self):
    524         BasicTestMappingProtocol.test_pop(self)
    525 
    526         # Tests for pop with specified key
    527         d = self._empty_mapping()
    528         k, v = 'abc', 'def'
    529 
    530         self.assertEqual(d.pop(k, v), v)
    531         d[k] = v
    532         self.assertEqual(d.pop(k, 1), v)
    533 
    534 
    535 class TestHashMappingProtocol(TestMappingProtocol):
    536 
    537     def test_getitem(self):
    538         TestMappingProtocol.test_getitem(self)
    539         class Exc(Exception): pass
    540 
    541         class BadEq(object):
    542             def __eq__(self, other):
    543                 raise Exc()
    544             def __hash__(self):
    545                 return 24
    546 
    547         d = self._empty_mapping()
    548         d[BadEq()] = 42
    549         self.assertRaises(KeyError, d.__getitem__, 23)
    550 
    551         class BadHash(object):
    552             fail = False
    553             def __hash__(self):
    554                 if self.fail:
    555                     raise Exc()
    556                 else:
    557                     return 42
    558 
    559         d = self._empty_mapping()
    560         x = BadHash()
    561         d[x] = 42
    562         x.fail = True
    563         self.assertRaises(Exc, d.__getitem__, x)
    564 
    565     def test_fromkeys(self):
    566         TestMappingProtocol.test_fromkeys(self)
    567         class mydict(self.type2test):
    568             def __new__(cls):
    569                 return collections.UserDict()
    570         ud = mydict.fromkeys('ab')
    571         self.assertEqual(ud, {'a':None, 'b':None})
    572         self.assertIsInstance(ud, collections.UserDict)
    573 
    574     def test_pop(self):
    575         TestMappingProtocol.test_pop(self)
    576 
    577         class Exc(Exception): pass
    578 
    579         class BadHash(object):
    580             fail = False
    581             def __hash__(self):
    582                 if self.fail:
    583                     raise Exc()
    584                 else:
    585                     return 42
    586 
    587         d = self._empty_mapping()
    588         x = BadHash()
    589         d[x] = 42
    590         x.fail = True
    591         self.assertRaises(Exc, d.pop, x)
    592 
    593     def test_mutatingiteration(self):
    594         d = self._empty_mapping()
    595         d[1] = 1
    596         try:
    597             for i in d:
    598                 d[i+1] = 1
    599         except RuntimeError:
    600             pass
    601         else:
    602             self.fail("changing dict size during iteration doesn't raise Error")
    603 
    604     def test_repr(self):
    605         d = self._empty_mapping()
    606         self.assertEqual(repr(d), '{}')
    607         d[1] = 2
    608         self.assertEqual(repr(d), '{1: 2}')
    609         d = self._empty_mapping()
    610         d[1] = d
    611         self.assertEqual(repr(d), '{1: {...}}')
    612 
    613         class Exc(Exception): pass
    614 
    615         class BadRepr(object):
    616             def __repr__(self):
    617                 raise Exc()
    618 
    619         d = self._full_mapping({1: BadRepr()})
    620         self.assertRaises(Exc, repr, d)
    621 
    622     def test_eq(self):
    623         self.assertEqual(self._empty_mapping(), self._empty_mapping())
    624         self.assertEqual(self._full_mapping({1: 2}),
    625                          self._full_mapping({1: 2}))
    626 
    627         class Exc(Exception): pass
    628 
    629         class BadCmp(object):
    630             def __eq__(self, other):
    631                 raise Exc()
    632             def __hash__(self):
    633                 return 1
    634 
    635         d1 = self._full_mapping({BadCmp(): 1})
    636         d2 = self._full_mapping({1: 1})
    637         self.assertRaises(Exc, lambda: BadCmp()==1)
    638         self.assertRaises(Exc, lambda: d1==d2)
    639 
    640     def test_setdefault(self):
    641         TestMappingProtocol.test_setdefault(self)
    642 
    643         class Exc(Exception): pass
    644 
    645         class BadHash(object):
    646             fail = False
    647             def __hash__(self):
    648                 if self.fail:
    649                     raise Exc()
    650                 else:
    651                     return 42
    652 
    653         d = self._empty_mapping()
    654         x = BadHash()
    655         d[x] = 42
    656         x.fail = True
    657         self.assertRaises(Exc, d.setdefault, x, [])
    658