Back to index

python3.2  3.2.2
mapping_tests.py
Go to the documentation of this file.
00001 # tests common to dict and UserDict
00002 import unittest
00003 import collections
00004 
00005 
00006 class BasicTestMappingProtocol(unittest.TestCase):
00007     # This base class can be used to check that an object conforms to the
00008     # mapping protocol
00009 
00010     # Functions that can be useful to override to adapt to dictionary
00011     # semantics
00012     type2test = None # which class is being tested (overwrite in subclasses)
00013 
00014     def _reference(self):
00015         """Return a dictionary of values which are invariant by storage
00016         in the object under test."""
00017         return {1:2, "key1":"value1", "key2":(1,2,3)}
00018     def _empty_mapping(self):
00019         """Return an empty mapping object"""
00020         return self.type2test()
00021     def _full_mapping(self, data):
00022         """Return a mapping object with the value contained in data
00023         dictionary"""
00024         x = self._empty_mapping()
00025         for key, value in data.items():
00026             x[key] = value
00027         return x
00028 
00029     def __init__(self, *args, **kw):
00030         unittest.TestCase.__init__(self, *args, **kw)
00031         self.reference = self._reference().copy()
00032 
00033         # A (key, value) pair not in the mapping
00034         key, value = self.reference.popitem()
00035         self.other = {key:value}
00036 
00037         # A (key, value) pair in the mapping
00038         key, value = self.reference.popitem()
00039         self.inmapping = {key:value}
00040         self.reference[key] = value
00041 
00042     def test_read(self):
00043         # Test for read only operations on mapping
00044         p = self._empty_mapping()
00045         p1 = dict(p) #workaround for singleton objects
00046         d = self._full_mapping(self.reference)
00047         if d is p:
00048             p = p1
00049         #Indexing
00050         for key, value in self.reference.items():
00051             self.assertEqual(d[key], value)
00052         knownkey = list(self.other.keys())[0]
00053         self.assertRaises(KeyError, lambda:d[knownkey])
00054         #len
00055         self.assertEqual(len(p), 0)
00056         self.assertEqual(len(d), len(self.reference))
00057         #__contains__
00058         for k in self.reference:
00059             self.assertIn(k, d)
00060         for k in self.other:
00061             self.assertNotIn(k, d)
00062         #cmp
00063         self.assertEqual(p, p)
00064         self.assertEqual(d, d)
00065         self.assertNotEqual(p, d)
00066         self.assertNotEqual(d, p)
00067         #__non__zero__
00068         if p: self.fail("Empty mapping must compare to False")
00069         if not d: self.fail("Full mapping must compare to True")
00070         # keys(), items(), iterkeys() ...
00071         def check_iterandlist(iter, lst, ref):
00072             self.assertTrue(hasattr(iter, '__next__'))
00073             self.assertTrue(hasattr(iter, '__iter__'))
00074             x = list(iter)
00075             self.assertTrue(set(x)==set(lst)==set(ref))
00076         check_iterandlist(iter(d.keys()), list(d.keys()),
00077                           self.reference.keys())
00078         check_iterandlist(iter(d), list(d.keys()), self.reference.keys())
00079         check_iterandlist(iter(d.values()), list(d.values()),
00080                           self.reference.values())
00081         check_iterandlist(iter(d.items()), list(d.items()),
00082                           self.reference.items())
00083         #get
00084         key, value = next(iter(d.items()))
00085         knownkey, knownvalue = next(iter(self.other.items()))
00086         self.assertEqual(d.get(key, knownvalue), value)
00087         self.assertEqual(d.get(knownkey, knownvalue), knownvalue)
00088         self.assertNotIn(knownkey, d)
00089 
00090     def test_write(self):
00091         # Test for write operations on mapping
00092         p = self._empty_mapping()
00093         #Indexing
00094         for key, value in self.reference.items():
00095             p[key] = value
00096             self.assertEqual(p[key], value)
00097         for key in self.reference.keys():
00098             del p[key]
00099             self.assertRaises(KeyError, lambda:p[key])
00100         p = self._empty_mapping()
00101         #update
00102         p.update(self.reference)
00103         self.assertEqual(dict(p), self.reference)
00104         items = list(p.items())
00105         p = self._empty_mapping()
00106         p.update(items)
00107         self.assertEqual(dict(p), self.reference)
00108         d = self._full_mapping(self.reference)
00109         #setdefault
00110         key, value = next(iter(d.items()))
00111         knownkey, knownvalue = next(iter(self.other.items()))
00112         self.assertEqual(d.setdefault(key, knownvalue), value)
00113         self.assertEqual(d[key], value)
00114         self.assertEqual(d.setdefault(knownkey, knownvalue), knownvalue)
00115         self.assertEqual(d[knownkey], knownvalue)
00116         #pop
00117         self.assertEqual(d.pop(knownkey), knownvalue)
00118         self.assertNotIn(knownkey, d)
00119         self.assertRaises(KeyError, d.pop, knownkey)
00120         default = 909
00121         d[knownkey] = knownvalue
00122         self.assertEqual(d.pop(knownkey, default), knownvalue)
00123         self.assertNotIn(knownkey, d)
00124         self.assertEqual(d.pop(knownkey, default), default)
00125         #popitem
00126         key, value = d.popitem()
00127         self.assertNotIn(key, d)
00128         self.assertEqual(value, self.reference[key])
00129         p=self._empty_mapping()
00130         self.assertRaises(KeyError, p.popitem)
00131 
00132     def test_constructor(self):
00133         self.assertEqual(self._empty_mapping(), self._empty_mapping())
00134 
00135     def test_bool(self):
00136         self.assertTrue(not self._empty_mapping())
00137         self.assertTrue(self.reference)
00138         self.assertTrue(bool(self._empty_mapping()) is False)
00139         self.assertTrue(bool(self.reference) is True)
00140 
00141     def test_keys(self):
00142         d = self._empty_mapping()
00143         self.assertEqual(list(d.keys()), [])
00144         d = self.reference
00145         self.assertIn(list(self.inmapping.keys())[0], d.keys())
00146         self.assertNotIn(list(self.other.keys())[0], d.keys())
00147         self.assertRaises(TypeError, d.keys, None)
00148 
00149     def test_values(self):
00150         d = self._empty_mapping()
00151         self.assertEqual(list(d.values()), [])
00152 
00153         self.assertRaises(TypeError, d.values, None)
00154 
00155     def test_items(self):
00156         d = self._empty_mapping()
00157         self.assertEqual(list(d.items()), [])
00158 
00159         self.assertRaises(TypeError, d.items, None)
00160 
00161     def test_len(self):
00162         d = self._empty_mapping()
00163         self.assertEqual(len(d), 0)
00164 
00165     def test_getitem(self):
00166         d = self.reference
00167         self.assertEqual(d[list(self.inmapping.keys())[0]],
00168                          list(self.inmapping.values())[0])
00169 
00170         self.assertRaises(TypeError, d.__getitem__)
00171 
00172     def test_update(self):
00173         # mapping argument
00174         d = self._empty_mapping()
00175         d.update(self.other)
00176         self.assertEqual(list(d.items()), list(self.other.items()))
00177 
00178         # No argument
00179         d = self._empty_mapping()
00180         d.update()
00181         self.assertEqual(d, self._empty_mapping())
00182 
00183         # item sequence
00184         d = self._empty_mapping()
00185         d.update(self.other.items())
00186         self.assertEqual(list(d.items()), list(self.other.items()))
00187 
00188         # Iterator
00189         d = self._empty_mapping()
00190         d.update(self.other.items())
00191         self.assertEqual(list(d.items()), list(self.other.items()))
00192 
00193         # FIXME: Doesn't work with UserDict
00194         # self.assertRaises((TypeError, AttributeError), d.update, None)
00195         self.assertRaises((TypeError, AttributeError), d.update, 42)
00196 
00197         outerself = self
00198         class SimpleUserDict:
00199             def __init__(self):
00200                 self.d = outerself.reference
00201             def keys(self):
00202                 return self.d.keys()
00203             def __getitem__(self, i):
00204                 return self.d[i]
00205         d.clear()
00206         d.update(SimpleUserDict())
00207         i1 = sorted(d.items())
00208         i2 = sorted(self.reference.items())
00209         self.assertEqual(i1, i2)
00210 
00211         class Exc(Exception): pass
00212 
00213         d = self._empty_mapping()
00214         class FailingUserDict:
00215             def keys(self):
00216                 raise Exc
00217         self.assertRaises(Exc, d.update, FailingUserDict())
00218 
00219         d.clear()
00220 
00221         class FailingUserDict:
00222             def keys(self):
00223                 class BogonIter:
00224                     def __init__(self):
00225                         self.i = 1
00226                     def __iter__(self):
00227                         return self
00228                     def __next__(self):
00229                         if self.i:
00230                             self.i = 0
00231                             return 'a'
00232                         raise Exc
00233                 return BogonIter()
00234             def __getitem__(self, key):
00235                 return key
00236         self.assertRaises(Exc, d.update, FailingUserDict())
00237 
00238         class FailingUserDict:
00239             def keys(self):
00240                 class BogonIter:
00241                     def __init__(self):
00242                         self.i = ord('a')
00243                     def __iter__(self):
00244                         return self
00245                     def __next__(self):
00246                         if self.i <= ord('z'):
00247                             rtn = chr(self.i)
00248                             self.i += 1
00249                             return rtn
00250                         raise StopIteration
00251                 return BogonIter()
00252             def __getitem__(self, key):
00253                 raise Exc
00254         self.assertRaises(Exc, d.update, FailingUserDict())
00255 
00256         d = self._empty_mapping()
00257         class badseq(object):
00258             def __iter__(self):
00259                 return self
00260             def __next__(self):
00261                 raise Exc()
00262 
00263         self.assertRaises(Exc, d.update, badseq())
00264 
00265         self.assertRaises(ValueError, d.update, [(1, 2, 3)])
00266 
00267     # no test_fromkeys or test_copy as both os.environ and selves don't support it
00268 
00269     def test_get(self):
00270         d = self._empty_mapping()
00271         self.assertTrue(d.get(list(self.other.keys())[0]) is None)
00272         self.assertEqual(d.get(list(self.other.keys())[0], 3), 3)
00273         d = self.reference
00274         self.assertTrue(d.get(list(self.other.keys())[0]) is None)
00275         self.assertEqual(d.get(list(self.other.keys())[0], 3), 3)
00276         self.assertEqual(d.get(list(self.inmapping.keys())[0]),
00277                          list(self.inmapping.values())[0])
00278         self.assertEqual(d.get(list(self.inmapping.keys())[0], 3),
00279                          list(self.inmapping.values())[0])
00280         self.assertRaises(TypeError, d.get)
00281         self.assertRaises(TypeError, d.get, None, None, None)
00282 
00283     def test_setdefault(self):
00284         d = self._empty_mapping()
00285         self.assertRaises(TypeError, d.setdefault)
00286 
00287     def test_popitem(self):
00288         d = self._empty_mapping()
00289         self.assertRaises(KeyError, d.popitem)
00290         self.assertRaises(TypeError, d.popitem, 42)
00291 
00292     def test_pop(self):
00293         d = self._empty_mapping()
00294         k, v = list(self.inmapping.items())[0]
00295         d[k] = v
00296         self.assertRaises(KeyError, d.pop, list(self.other.keys())[0])
00297 
00298         self.assertEqual(d.pop(k), v)
00299         self.assertEqual(len(d), 0)
00300 
00301         self.assertRaises(KeyError, d.pop, k)
00302 
00303 
00304 class TestMappingProtocol(BasicTestMappingProtocol):
00305     def test_constructor(self):
00306         BasicTestMappingProtocol.test_constructor(self)
00307         self.assertTrue(self._empty_mapping() is not self._empty_mapping())
00308         self.assertEqual(self.type2test(x=1, y=2), {"x": 1, "y": 2})
00309 
00310     def test_bool(self):
00311         BasicTestMappingProtocol.test_bool(self)
00312         self.assertTrue(not self._empty_mapping())
00313         self.assertTrue(self._full_mapping({"x": "y"}))
00314         self.assertTrue(bool(self._empty_mapping()) is False)
00315         self.assertTrue(bool(self._full_mapping({"x": "y"})) is True)
00316 
00317     def test_keys(self):
00318         BasicTestMappingProtocol.test_keys(self)
00319         d = self._empty_mapping()
00320         self.assertEqual(list(d.keys()), [])
00321         d = self._full_mapping({'a': 1, 'b': 2})
00322         k = d.keys()
00323         self.assertIn('a', k)
00324         self.assertIn('b', k)
00325         self.assertNotIn('c', k)
00326 
00327     def test_values(self):
00328         BasicTestMappingProtocol.test_values(self)
00329         d = self._full_mapping({1:2})
00330         self.assertEqual(list(d.values()), [2])
00331 
00332     def test_items(self):
00333         BasicTestMappingProtocol.test_items(self)
00334 
00335         d = self._full_mapping({1:2})
00336         self.assertEqual(list(d.items()), [(1, 2)])
00337 
00338     def test_contains(self):
00339         d = self._empty_mapping()
00340         self.assertNotIn('a', d)
00341         self.assertTrue(not ('a' in d))
00342         self.assertTrue('a' not in d)
00343         d = self._full_mapping({'a': 1, 'b': 2})
00344         self.assertIn('a', d)
00345         self.assertIn('b', d)
00346         self.assertNotIn('c', d)
00347 
00348         self.assertRaises(TypeError, d.__contains__)
00349 
00350     def test_len(self):
00351         BasicTestMappingProtocol.test_len(self)
00352         d = self._full_mapping({'a': 1, 'b': 2})
00353         self.assertEqual(len(d), 2)
00354 
00355     def test_getitem(self):
00356         BasicTestMappingProtocol.test_getitem(self)
00357         d = self._full_mapping({'a': 1, 'b': 2})
00358         self.assertEqual(d['a'], 1)
00359         self.assertEqual(d['b'], 2)
00360         d['c'] = 3
00361         d['a'] = 4
00362         self.assertEqual(d['c'], 3)
00363         self.assertEqual(d['a'], 4)
00364         del d['b']
00365         self.assertEqual(d, {'a': 4, 'c': 3})
00366 
00367         self.assertRaises(TypeError, d.__getitem__)
00368 
00369     def test_clear(self):
00370         d = self._full_mapping({1:1, 2:2, 3:3})
00371         d.clear()
00372         self.assertEqual(d, {})
00373 
00374         self.assertRaises(TypeError, d.clear, None)
00375 
00376     def test_update(self):
00377         BasicTestMappingProtocol.test_update(self)
00378         # mapping argument
00379         d = self._empty_mapping()
00380         d.update({1:100})
00381         d.update({2:20})
00382         d.update({1:1, 2:2, 3:3})
00383         self.assertEqual(d, {1:1, 2:2, 3:3})
00384 
00385         # no argument
00386         d.update()
00387         self.assertEqual(d, {1:1, 2:2, 3:3})
00388 
00389         # keyword arguments
00390         d = self._empty_mapping()
00391         d.update(x=100)
00392         d.update(y=20)
00393         d.update(x=1, y=2, z=3)
00394         self.assertEqual(d, {"x":1, "y":2, "z":3})
00395 
00396         # item sequence
00397         d = self._empty_mapping()
00398         d.update([("x", 100), ("y", 20)])
00399         self.assertEqual(d, {"x":100, "y":20})
00400 
00401         # Both item sequence and keyword arguments
00402         d = self._empty_mapping()
00403         d.update([("x", 100), ("y", 20)], x=1, y=2)
00404         self.assertEqual(d, {"x":1, "y":2})
00405 
00406         # iterator
00407         d = self._full_mapping({1:3, 2:4})
00408         d.update(self._full_mapping({1:2, 3:4, 5:6}).items())
00409         self.assertEqual(d, {1:2, 2:4, 3:4, 5:6})
00410 
00411         class SimpleUserDict:
00412             def __init__(self):
00413                 self.d = {1:1, 2:2, 3:3}
00414             def keys(self):
00415                 return self.d.keys()
00416             def __getitem__(self, i):
00417                 return self.d[i]
00418         d.clear()
00419         d.update(SimpleUserDict())
00420         self.assertEqual(d, {1:1, 2:2, 3:3})
00421 
00422     def test_fromkeys(self):
00423         self.assertEqual(self.type2test.fromkeys('abc'), {'a':None, 'b':None, 'c':None})
00424         d = self._empty_mapping()
00425         self.assertTrue(not(d.fromkeys('abc') is d))
00426         self.assertEqual(d.fromkeys('abc'), {'a':None, 'b':None, 'c':None})
00427         self.assertEqual(d.fromkeys((4,5),0), {4:0, 5:0})
00428         self.assertEqual(d.fromkeys([]), {})
00429         def g():
00430             yield 1
00431         self.assertEqual(d.fromkeys(g()), {1:None})
00432         self.assertRaises(TypeError, {}.fromkeys, 3)
00433         class dictlike(self.type2test): pass
00434         self.assertEqual(dictlike.fromkeys('a'), {'a':None})
00435         self.assertEqual(dictlike().fromkeys('a'), {'a':None})
00436         self.assertTrue(dictlike.fromkeys('a').__class__ is dictlike)
00437         self.assertTrue(dictlike().fromkeys('a').__class__ is dictlike)
00438         self.assertTrue(type(dictlike.fromkeys('a')) is dictlike)
00439         class mydict(self.type2test):
00440             def __new__(cls):
00441                 return collections.UserDict()
00442         ud = mydict.fromkeys('ab')
00443         self.assertEqual(ud, {'a':None, 'b':None})
00444         self.assertIsInstance(ud, collections.UserDict)
00445         self.assertRaises(TypeError, dict.fromkeys)
00446 
00447         class Exc(Exception): pass
00448 
00449         class baddict1(self.type2test):
00450             def __init__(self):
00451                 raise Exc()
00452 
00453         self.assertRaises(Exc, baddict1.fromkeys, [1])
00454 
00455         class BadSeq(object):
00456             def __iter__(self):
00457                 return self
00458             def __next__(self):
00459                 raise Exc()
00460 
00461         self.assertRaises(Exc, self.type2test.fromkeys, BadSeq())
00462 
00463         class baddict2(self.type2test):
00464             def __setitem__(self, key, value):
00465                 raise Exc()
00466 
00467         self.assertRaises(Exc, baddict2.fromkeys, [1])
00468 
00469     def test_copy(self):
00470         d = self._full_mapping({1:1, 2:2, 3:3})
00471         self.assertEqual(d.copy(), {1:1, 2:2, 3:3})
00472         d = self._empty_mapping()
00473         self.assertEqual(d.copy(), d)
00474         self.assertIsInstance(d.copy(), d.__class__)
00475         self.assertRaises(TypeError, d.copy, None)
00476 
00477     def test_get(self):
00478         BasicTestMappingProtocol.test_get(self)
00479         d = self._empty_mapping()
00480         self.assertTrue(d.get('c') is None)
00481         self.assertEqual(d.get('c', 3), 3)
00482         d = self._full_mapping({'a' : 1, 'b' : 2})
00483         self.assertTrue(d.get('c') is None)
00484         self.assertEqual(d.get('c', 3), 3)
00485         self.assertEqual(d.get('a'), 1)
00486         self.assertEqual(d.get('a', 3), 1)
00487 
00488     def test_setdefault(self):
00489         BasicTestMappingProtocol.test_setdefault(self)
00490         d = self._empty_mapping()
00491         self.assertTrue(d.setdefault('key0') is None)
00492         d.setdefault('key0', [])
00493         self.assertTrue(d.setdefault('key0') is None)
00494         d.setdefault('key', []).append(3)
00495         self.assertEqual(d['key'][0], 3)
00496         d.setdefault('key', []).append(4)
00497         self.assertEqual(len(d['key']), 2)
00498 
00499     def test_popitem(self):
00500         BasicTestMappingProtocol.test_popitem(self)
00501         for copymode in -1, +1:
00502             # -1: b has same structure as a
00503             # +1: b is a.copy()
00504             for log2size in range(12):
00505                 size = 2**log2size
00506                 a = self._empty_mapping()
00507                 b = self._empty_mapping()
00508                 for i in range(size):
00509                     a[repr(i)] = i
00510                     if copymode < 0:
00511                         b[repr(i)] = i
00512                 if copymode > 0:
00513                     b = a.copy()
00514                 for i in range(size):
00515                     ka, va = ta = a.popitem()
00516                     self.assertEqual(va, int(ka))
00517                     kb, vb = tb = b.popitem()
00518                     self.assertEqual(vb, int(kb))
00519                     self.assertTrue(not(copymode < 0 and ta != tb))
00520                 self.assertTrue(not a)
00521                 self.assertTrue(not b)
00522 
00523     def test_pop(self):
00524         BasicTestMappingProtocol.test_pop(self)
00525 
00526         # Tests for pop with specified key
00527         d = self._empty_mapping()
00528         k, v = 'abc', 'def'
00529 
00530         self.assertEqual(d.pop(k, v), v)
00531         d[k] = v
00532         self.assertEqual(d.pop(k, 1), v)
00533 
00534 
00535 class TestHashMappingProtocol(TestMappingProtocol):
00536 
00537     def test_getitem(self):
00538         TestMappingProtocol.test_getitem(self)
00539         class Exc(Exception): pass
00540 
00541         class BadEq(object):
00542             def __eq__(self, other):
00543                 raise Exc()
00544             def __hash__(self):
00545                 return 24
00546 
00547         d = self._empty_mapping()
00548         d[BadEq()] = 42
00549         self.assertRaises(KeyError, d.__getitem__, 23)
00550 
00551         class BadHash(object):
00552             fail = False
00553             def __hash__(self):
00554                 if self.fail:
00555                     raise Exc()
00556                 else:
00557                     return 42
00558 
00559         d = self._empty_mapping()
00560         x = BadHash()
00561         d[x] = 42
00562         x.fail = True
00563         self.assertRaises(Exc, d.__getitem__, x)
00564 
00565     def test_fromkeys(self):
00566         TestMappingProtocol.test_fromkeys(self)
00567         class mydict(self.type2test):
00568             def __new__(cls):
00569                 return collections.UserDict()
00570         ud = mydict.fromkeys('ab')
00571         self.assertEqual(ud, {'a':None, 'b':None})
00572         self.assertIsInstance(ud, collections.UserDict)
00573 
00574     def test_pop(self):
00575         TestMappingProtocol.test_pop(self)
00576 
00577         class Exc(Exception): pass
00578 
00579         class BadHash(object):
00580             fail = False
00581             def __hash__(self):
00582                 if self.fail:
00583                     raise Exc()
00584                 else:
00585                     return 42
00586 
00587         d = self._empty_mapping()
00588         x = BadHash()
00589         d[x] = 42
00590         x.fail = True
00591         self.assertRaises(Exc, d.pop, x)
00592 
00593     def test_mutatingiteration(self):
00594         d = self._empty_mapping()
00595         d[1] = 1
00596         try:
00597             for i in d:
00598                 d[i+1] = 1
00599         except RuntimeError:
00600             pass
00601         else:
00602             self.fail("changing dict size during iteration doesn't raise Error")
00603 
00604     def test_repr(self):
00605         d = self._empty_mapping()
00606         self.assertEqual(repr(d), '{}')
00607         d[1] = 2
00608         self.assertEqual(repr(d), '{1: 2}')
00609         d = self._empty_mapping()
00610         d[1] = d
00611         self.assertEqual(repr(d), '{1: {...}}')
00612 
00613         class Exc(Exception): pass
00614 
00615         class BadRepr(object):
00616             def __repr__(self):
00617                 raise Exc()
00618 
00619         d = self._full_mapping({1: BadRepr()})
00620         self.assertRaises(Exc, repr, d)
00621 
00622     def test_eq(self):
00623         self.assertEqual(self._empty_mapping(), self._empty_mapping())
00624         self.assertEqual(self._full_mapping({1: 2}),
00625                          self._full_mapping({1: 2}))
00626 
00627         class Exc(Exception): pass
00628 
00629         class BadCmp(object):
00630             def __eq__(self, other):
00631                 raise Exc()
00632             def __hash__(self):
00633                 return 1
00634 
00635         d1 = self._full_mapping({BadCmp(): 1})
00636         d2 = self._full_mapping({1: 1})
00637         self.assertRaises(Exc, lambda: BadCmp()==1)
00638         self.assertRaises(Exc, lambda: d1==d2)
00639 
00640     def test_setdefault(self):
00641         TestMappingProtocol.test_setdefault(self)
00642 
00643         class Exc(Exception): pass
00644 
00645         class BadHash(object):
00646             fail = False
00647             def __hash__(self):
00648                 if self.fail:
00649                     raise Exc()
00650                 else:
00651                     return 42
00652 
00653         d = self._empty_mapping()
00654         x = BadHash()
00655         d[x] = 42
00656         x.fail = True
00657         self.assertRaises(Exc, d.setdefault, x, [])