PageRenderTime 76ms CodeModel.GetById 15ms app.highlight 56ms RepoModel.GetById 1ms app.codeStats 0ms

/Lib/test/test_dict.py

http://unladen-swallow.googlecode.com/
Python | 592 lines | 548 code | 22 blank | 22 comment | 21 complexity | def008ac0970e10e2bcd602c94ac42dc MD5 | raw file
  1import unittest
  2from test import test_support
  3
  4import UserDict, random, string
  5import gc, weakref
  6
  7
  8class DictTest(unittest.TestCase):
  9    def test_constructor(self):
 10        # calling built-in types without argument must return empty
 11        self.assertEqual(dict(), {})
 12        self.assert_(dict() is not {})
 13
 14    def test_literal_constructor(self):
 15        # check literal constructor for different sized dicts (to exercise the BUILD_MAP oparg
 16        for n in (0, 1, 6, 256, 400):
 17            items = [(''.join([random.choice(string.letters)
 18                               for j in range(8)]),
 19                      i)
 20                     for i in range(n)]
 21            random.shuffle(items)
 22            dictliteral = '{' + ', '.join('%r: %d' % item for item in items) + '}'
 23            self.assertEqual(eval(dictliteral), dict(items))
 24
 25    def test_bool(self):
 26        self.assert_(not {})
 27        self.assert_({1: 2})
 28        self.assert_(bool({}) is False)
 29        self.assert_(bool({1: 2}) is True)
 30
 31    def test_keys(self):
 32        d = {}
 33        self.assertEqual(d.keys(), [])
 34        d = {'a': 1, 'b': 2}
 35        k = d.keys()
 36        self.assert_(d.has_key('a'))
 37        self.assert_(d.has_key('b'))
 38
 39        self.assertRaises(TypeError, d.keys, None)
 40
 41    def test_values(self):
 42        d = {}
 43        self.assertEqual(d.values(), [])
 44        d = {1:2}
 45        self.assertEqual(d.values(), [2])
 46
 47        self.assertRaises(TypeError, d.values, None)
 48
 49    def test_items(self):
 50        d = {}
 51        self.assertEqual(d.items(), [])
 52
 53        d = {1:2}
 54        self.assertEqual(d.items(), [(1, 2)])
 55
 56        self.assertRaises(TypeError, d.items, None)
 57
 58    def test_has_key(self):
 59        d = {}
 60        self.assert_(not d.has_key('a'))
 61        d = {'a': 1, 'b': 2}
 62        k = d.keys()
 63        k.sort()
 64        self.assertEqual(k, ['a', 'b'])
 65
 66        self.assertRaises(TypeError, d.has_key)
 67
 68    def test_contains(self):
 69        d = {}
 70        self.assert_(not ('a' in d))
 71        self.assert_('a' not in d)
 72        d = {'a': 1, 'b': 2}
 73        self.assert_('a' in d)
 74        self.assert_('b' in d)
 75        self.assert_('c' not in d)
 76
 77        self.assertRaises(TypeError, d.__contains__)
 78
 79    def test_len(self):
 80        d = {}
 81        self.assertEqual(len(d), 0)
 82        d = {'a': 1, 'b': 2}
 83        self.assertEqual(len(d), 2)
 84
 85    def test_getitem(self):
 86        d = {'a': 1, 'b': 2}
 87        self.assertEqual(d['a'], 1)
 88        self.assertEqual(d['b'], 2)
 89        d['c'] = 3
 90        d['a'] = 4
 91        self.assertEqual(d['c'], 3)
 92        self.assertEqual(d['a'], 4)
 93        del d['b']
 94        self.assertEqual(d, {'a': 4, 'c': 3})
 95
 96        self.assertRaises(TypeError, d.__getitem__)
 97
 98        class BadEq(object):
 99            def __eq__(self, other):
100                raise Exc()
101            def __hash__(self):
102                return 24
103
104        d = {}
105        d[BadEq()] = 42
106        self.assertRaises(KeyError, d.__getitem__, 23)
107
108        class Exc(Exception): pass
109
110        class BadHash(object):
111            fail = False
112            def __hash__(self):
113                if self.fail:
114                    raise Exc()
115                else:
116                    return 42
117
118        x = BadHash()
119        d[x] = 42
120        x.fail = True
121        self.assertRaises(Exc, d.__getitem__, x)
122
123    def test_clear(self):
124        d = {1:1, 2:2, 3:3}
125        d.clear()
126        self.assertEqual(d, {})
127
128        self.assertRaises(TypeError, d.clear, None)
129
130    def test_update(self):
131        d = {}
132        d.update({1:100})
133        d.update({2:20})
134        d.update({1:1, 2:2, 3:3})
135        self.assertEqual(d, {1:1, 2:2, 3:3})
136
137        d.update()
138        self.assertEqual(d, {1:1, 2:2, 3:3})
139
140        self.assertRaises((TypeError, AttributeError), d.update, None)
141
142        class SimpleUserDict:
143            def __init__(self):
144                self.d = {1:1, 2:2, 3:3}
145            def keys(self):
146                return self.d.keys()
147            def __getitem__(self, i):
148                return self.d[i]
149        d.clear()
150        d.update(SimpleUserDict())
151        self.assertEqual(d, {1:1, 2:2, 3:3})
152
153        class Exc(Exception): pass
154
155        d.clear()
156        class FailingUserDict:
157            def keys(self):
158                raise Exc
159        self.assertRaises(Exc, d.update, FailingUserDict())
160
161        class FailingUserDict:
162            def keys(self):
163                class BogonIter:
164                    def __init__(self):
165                        self.i = 1
166                    def __iter__(self):
167                        return self
168                    def next(self):
169                        if self.i:
170                            self.i = 0
171                            return 'a'
172                        raise Exc
173                return BogonIter()
174            def __getitem__(self, key):
175                return key
176        self.assertRaises(Exc, d.update, FailingUserDict())
177
178        class FailingUserDict:
179            def keys(self):
180                class BogonIter:
181                    def __init__(self):
182                        self.i = ord('a')
183                    def __iter__(self):
184                        return self
185                    def next(self):
186                        if self.i <= ord('z'):
187                            rtn = chr(self.i)
188                            self.i += 1
189                            return rtn
190                        raise StopIteration
191                return BogonIter()
192            def __getitem__(self, key):
193                raise Exc
194        self.assertRaises(Exc, d.update, FailingUserDict())
195
196        class badseq(object):
197            def __iter__(self):
198                return self
199            def next(self):
200                raise Exc()
201
202        self.assertRaises(Exc, {}.update, badseq())
203
204        self.assertRaises(ValueError, {}.update, [(1, 2, 3)])
205
206    def test_fromkeys(self):
207        self.assertEqual(dict.fromkeys('abc'), {'a':None, 'b':None, 'c':None})
208        d = {}
209        self.assert_(not(d.fromkeys('abc') is d))
210        self.assertEqual(d.fromkeys('abc'), {'a':None, 'b':None, 'c':None})
211        self.assertEqual(d.fromkeys((4,5),0), {4:0, 5:0})
212        self.assertEqual(d.fromkeys([]), {})
213        def g():
214            yield 1
215        self.assertEqual(d.fromkeys(g()), {1:None})
216        self.assertRaises(TypeError, {}.fromkeys, 3)
217        class dictlike(dict): pass
218        self.assertEqual(dictlike.fromkeys('a'), {'a':None})
219        self.assertEqual(dictlike().fromkeys('a'), {'a':None})
220        self.assert_(type(dictlike.fromkeys('a')) is dictlike)
221        self.assert_(type(dictlike().fromkeys('a')) is dictlike)
222        class mydict(dict):
223            def __new__(cls):
224                return UserDict.UserDict()
225        ud = mydict.fromkeys('ab')
226        self.assertEqual(ud, {'a':None, 'b':None})
227        self.assert_(isinstance(ud, UserDict.UserDict))
228        self.assertRaises(TypeError, dict.fromkeys)
229
230        class Exc(Exception): pass
231
232        class baddict1(dict):
233            def __init__(self):
234                raise Exc()
235
236        self.assertRaises(Exc, baddict1.fromkeys, [1])
237
238        class BadSeq(object):
239            def __iter__(self):
240                return self
241            def next(self):
242                raise Exc()
243
244        self.assertRaises(Exc, dict.fromkeys, BadSeq())
245
246        class baddict2(dict):
247            def __setitem__(self, key, value):
248                raise Exc()
249
250        self.assertRaises(Exc, baddict2.fromkeys, [1])
251
252        # test fast path for dictionary inputs
253        d = dict(zip(range(6), range(6)))
254        self.assertEqual(dict.fromkeys(d, 0), dict(zip(range(6), [0]*6)))
255
256    def test_copy(self):
257        d = {1:1, 2:2, 3:3}
258        self.assertEqual(d.copy(), {1:1, 2:2, 3:3})
259        self.assertEqual({}.copy(), {})
260        self.assertRaises(TypeError, d.copy, None)
261
262    def test_get(self):
263        d = {}
264        self.assert_(d.get('c') is None)
265        self.assertEqual(d.get('c', 3), 3)
266        d = {'a' : 1, 'b' : 2}
267        self.assert_(d.get('c') is None)
268        self.assertEqual(d.get('c', 3), 3)
269        self.assertEqual(d.get('a'), 1)
270        self.assertEqual(d.get('a', 3), 1)
271        self.assertRaises(TypeError, d.get)
272        self.assertRaises(TypeError, d.get, None, None, None)
273
274    def test_setdefault(self):
275        # dict.setdefault()
276        d = {}
277        self.assert_(d.setdefault('key0') is None)
278        d.setdefault('key0', [])
279        self.assert_(d.setdefault('key0') is None)
280        d.setdefault('key', []).append(3)
281        self.assertEqual(d['key'][0], 3)
282        d.setdefault('key', []).append(4)
283        self.assertEqual(len(d['key']), 2)
284        self.assertRaises(TypeError, d.setdefault)
285
286        class Exc(Exception): pass
287
288        class BadHash(object):
289            fail = False
290            def __hash__(self):
291                if self.fail:
292                    raise Exc()
293                else:
294                    return 42
295
296        x = BadHash()
297        d[x] = 42
298        x.fail = True
299        self.assertRaises(Exc, d.setdefault, x, [])
300
301    def test_popitem(self):
302        # dict.popitem()
303        for copymode in -1, +1:
304            # -1: b has same structure as a
305            # +1: b is a.copy()
306            for log2size in range(12):
307                size = 2**log2size
308                a = {}
309                b = {}
310                for i in range(size):
311                    a[repr(i)] = i
312                    if copymode < 0:
313                        b[repr(i)] = i
314                if copymode > 0:
315                    b = a.copy()
316                for i in range(size):
317                    ka, va = ta = a.popitem()
318                    self.assertEqual(va, int(ka))
319                    kb, vb = tb = b.popitem()
320                    self.assertEqual(vb, int(kb))
321                    self.assert_(not(copymode < 0 and ta != tb))
322                self.assert_(not a)
323                self.assert_(not b)
324
325        d = {}
326        self.assertRaises(KeyError, d.popitem)
327
328    def test_pop(self):
329        # Tests for pop with specified key
330        d = {}
331        k, v = 'abc', 'def'
332        d[k] = v
333        self.assertRaises(KeyError, d.pop, 'ghi')
334
335        self.assertEqual(d.pop(k), v)
336        self.assertEqual(len(d), 0)
337
338        self.assertRaises(KeyError, d.pop, k)
339
340        # verify longs/ints get same value when key > 32 bits (for 64-bit archs)
341        # see SF bug #689659
342        x = 4503599627370496L
343        y = 4503599627370496
344        h = {x: 'anything', y: 'something else'}
345        self.assertEqual(h[x], h[y])
346
347        self.assertEqual(d.pop(k, v), v)
348        d[k] = v
349        self.assertEqual(d.pop(k, 1), v)
350
351        self.assertRaises(TypeError, d.pop)
352
353        class Exc(Exception): pass
354
355        class BadHash(object):
356            fail = False
357            def __hash__(self):
358                if self.fail:
359                    raise Exc()
360                else:
361                    return 42
362
363        x = BadHash()
364        d[x] = 42
365        x.fail = True
366        self.assertRaises(Exc, d.pop, x)
367
368    def test_mutatingiteration(self):
369        d = {}
370        d[1] = 1
371        try:
372            for i in d:
373                d[i+1] = 1
374        except RuntimeError:
375            pass
376        else:
377            self.fail("changing dict size during iteration doesn't raise Error")
378
379    def test_repr(self):
380        d = {}
381        self.assertEqual(repr(d), '{}')
382        d[1] = 2
383        self.assertEqual(repr(d), '{1: 2}')
384        d = {}
385        d[1] = d
386        self.assertEqual(repr(d), '{1: {...}}')
387
388        class Exc(Exception): pass
389
390        class BadRepr(object):
391            def __repr__(self):
392                raise Exc()
393
394        d = {1: BadRepr()}
395        self.assertRaises(Exc, repr, d)
396
397    def test_le(self):
398        self.assert_(not ({} < {}))
399        self.assert_(not ({1: 2} < {1L: 2L}))
400
401        class Exc(Exception): pass
402
403        class BadCmp(object):
404            def __eq__(self, other):
405                raise Exc()
406            def __hash__(self):
407                return 42
408
409        d1 = {BadCmp(): 1}
410        d2 = {1: 1}
411        try:
412            d1 < d2
413        except Exc:
414            pass
415        else:
416            self.fail("< didn't raise Exc")
417
418    def test_missing(self):
419        # Make sure dict doesn't have a __missing__ method
420        self.assertEqual(hasattr(dict, "__missing__"), False)
421        self.assertEqual(hasattr({}, "__missing__"), False)
422        # Test several cases:
423        # (D) subclass defines __missing__ method returning a value
424        # (E) subclass defines __missing__ method raising RuntimeError
425        # (F) subclass sets __missing__ instance variable (no effect)
426        # (G) subclass doesn't define __missing__ at a all
427        class D(dict):
428            def __missing__(self, key):
429                return 42
430        d = D({1: 2, 3: 4})
431        self.assertEqual(d[1], 2)
432        self.assertEqual(d[3], 4)
433        self.assert_(2 not in d)
434        self.assert_(2 not in d.keys())
435        self.assertEqual(d[2], 42)
436        class E(dict):
437            def __missing__(self, key):
438                raise RuntimeError(key)
439        e = E()
440        try:
441            e[42]
442        except RuntimeError, err:
443            self.assertEqual(err.args, (42,))
444        else:
445            self.fail("e[42] didn't raise RuntimeError")
446        class F(dict):
447            def __init__(self):
448                # An instance variable __missing__ should have no effect
449                self.__missing__ = lambda key: None
450        f = F()
451        try:
452            f[42]
453        except KeyError, err:
454            self.assertEqual(err.args, (42,))
455        else:
456            self.fail("f[42] didn't raise KeyError")
457        class G(dict):
458            pass
459        g = G()
460        try:
461            g[42]
462        except KeyError, err:
463            self.assertEqual(err.args, (42,))
464        else:
465            self.fail("g[42] didn't raise KeyError")
466
467    def test_tuple_keyerror(self):
468        # SF #1576657
469        d = {}
470        try:
471            d[(1,)]
472        except KeyError, e:
473            self.assertEqual(e.args, ((1,),))
474        else:
475            self.fail("missing KeyError")
476
477    def test_bad_key(self):
478        # Dictionary lookups should fail if __cmp__() raises an exception.
479        class CustomException(Exception):
480            pass
481
482        class BadDictKey:
483            def __hash__(self):
484                return hash(self.__class__)
485
486            def __cmp__(self, other):
487                if isinstance(other, self.__class__):
488                    raise CustomException
489                return other
490
491        d = {}
492        x1 = BadDictKey()
493        x2 = BadDictKey()
494        d[x1] = 1
495        for stmt in ['d[x2] = 2',
496                     'z = d[x2]',
497                     'x2 in d',
498                     'd.has_key(x2)',
499                     'd.get(x2)',
500                     'd.setdefault(x2, 42)',
501                     'd.pop(x2)',
502                     'd.update({x2: 2})']:
503            try:
504                exec stmt in locals()
505            except CustomException:
506                pass
507            else:
508                self.fail("Statement didn't raise exception")
509
510    def test_resize1(self):
511        # Dict resizing bug, found by Jack Jansen in 2.2 CVS development.
512        # This version got an assert failure in debug build, infinite loop in
513        # release build.  Unfortunately, provoking this kind of stuff requires
514        # a mix of inserts and deletes hitting exactly the right hash codes in
515        # exactly the right order, and I can't think of a randomized approach
516        # that would be *likely* to hit a failing case in reasonable time.
517
518        d = {}
519        for i in range(5):
520            d[i] = i
521        for i in range(5):
522            del d[i]
523        for i in range(5, 9):  # i==8 was the problem
524            d[i] = i
525
526    def test_resize2(self):
527        # Another dict resizing bug (SF bug #1456209).
528        # This caused Segmentation faults or Illegal instructions.
529
530        class X(object):
531            def __hash__(self):
532                return 5
533            def __eq__(self, other):
534                if resizing:
535                    d.clear()
536                return False
537        d = {}
538        resizing = False
539        d[X()] = 1
540        d[X()] = 2
541        d[X()] = 3
542        d[X()] = 4
543        d[X()] = 5
544        # now trigger a resize
545        resizing = True
546        d[9] = 6
547
548    def test_empty_presized_dict_in_freelist(self):
549        # Bug #3537: if an empty but presized dict with a size larger
550        # than 7 was in the freelist, it triggered an assertion failure
551        try:
552            d = {'a': 1/0,  'b': None, 'c': None, 'd': None, 'e': None,
553                 'f': None, 'g': None, 'h': None}
554        except ZeroDivisionError:
555            pass
556        d = {}
557
558    def test_container_iterator(self):
559        # Bug #3680: tp_traverse was not implemented for dictiter objects
560        class C(object):
561            pass
562        iterators = (dict.iteritems, dict.itervalues, dict.iterkeys)
563        for i in iterators:
564            obj = C()
565            ref = weakref.ref(obj)
566            container = {obj: 1}
567            obj.x = i(container)
568            del obj, container
569            gc.collect()
570            self.assert_(ref() is None, "Cycle was not collected")
571
572
573from test import mapping_tests
574
575class GeneralMappingTests(mapping_tests.BasicTestMappingProtocol):
576    type2test = dict
577
578class Dict(dict):
579    pass
580
581class SubclassMappingTests(mapping_tests.BasicTestMappingProtocol):
582    type2test = Dict
583
584def test_main():
585    test_support.run_unittest(
586        DictTest,
587        GeneralMappingTests,
588        SubclassMappingTests,
589    )
590
591if __name__ == "__main__":
592    test_main()