PageRenderTime 136ms CodeModel.GetById 92ms app.highlight 39ms RepoModel.GetById 1ms app.codeStats 0ms

/Lib/test/test_deque.py

http://unladen-swallow.googlecode.com/
Python | 705 lines | 675 code | 25 blank | 5 comment | 25 complexity | 9524415fd11032f7d520bbe2be28b563 MD5 | raw file
  1from collections import deque
  2import unittest
  3from test import test_support, seq_tests
  4import gc
  5import weakref
  6import copy
  7import cPickle as pickle
  8import random
  9import os
 10
 11BIG = 100000
 12
 13def fail():
 14    raise SyntaxError
 15    yield 1
 16
 17class BadCmp:
 18    def __eq__(self, other):
 19        raise RuntimeError
 20
 21class MutateCmp:
 22    def __init__(self, deque, result):
 23        self.deque = deque
 24        self.result = result
 25    def __eq__(self, other):
 26        self.deque.clear()
 27        return self.result
 28
 29class TestBasic(unittest.TestCase):
 30
 31    def test_basics(self):
 32        d = deque(xrange(-5125, -5000))
 33        d.__init__(xrange(200))
 34        for i in xrange(200, 400):
 35            d.append(i)
 36        for i in reversed(xrange(-200, 0)):
 37            d.appendleft(i)
 38        self.assertEqual(list(d), range(-200, 400))
 39        self.assertEqual(len(d), 600)
 40
 41        left = [d.popleft() for i in xrange(250)]
 42        self.assertEqual(left, range(-200, 50))
 43        self.assertEqual(list(d), range(50, 400))
 44
 45        right = [d.pop() for i in xrange(250)]
 46        right.reverse()
 47        self.assertEqual(right, range(150, 400))
 48        self.assertEqual(list(d), range(50, 150))
 49
 50    def test_maxlen(self):
 51        self.assertRaises(ValueError, deque, 'abc', -1)
 52        self.assertRaises(ValueError, deque, 'abc', -2)
 53        d = deque(range(10), maxlen=3)
 54        self.assertEqual(repr(d), 'deque([7, 8, 9], maxlen=3)')
 55        self.assertEqual(list(d), range(7, 10))
 56        self.assertEqual(d, deque(range(10), 3))
 57        d.append(10)
 58        self.assertEqual(list(d), range(8, 11))
 59        d.appendleft(7)
 60        self.assertEqual(list(d), range(7, 10))
 61        d.extend([10, 11])
 62        self.assertEqual(list(d), range(9, 12))
 63        d.extendleft([8, 7])
 64        self.assertEqual(list(d), range(7, 10))
 65        d = deque(xrange(200), maxlen=10)
 66        d.append(d)
 67        test_support.unlink(test_support.TESTFN)
 68        fo = open(test_support.TESTFN, "wb")
 69        try:
 70            print >> fo, d,
 71            fo.close()
 72            fo = open(test_support.TESTFN, "rb")
 73            self.assertEqual(fo.read(), repr(d))
 74        finally:
 75            fo.close()
 76            test_support.unlink(test_support.TESTFN)
 77
 78        d = deque(range(10), maxlen=None)
 79        self.assertEqual(repr(d), 'deque([0, 1, 2, 3, 4, 5, 6, 7, 8, 9])')
 80        fo = open(test_support.TESTFN, "wb")
 81        try:
 82            print >> fo, d,
 83            fo.close()
 84            fo = open(test_support.TESTFN, "rb")
 85            self.assertEqual(fo.read(), repr(d))
 86        finally:
 87            fo.close()
 88            test_support.unlink(test_support.TESTFN)
 89
 90    def test_comparisons(self):
 91        d = deque('xabc'); d.popleft()
 92        for e in [d, deque('abc'), deque('ab'), deque(), list(d)]:
 93            self.assertEqual(d==e, type(d)==type(e) and list(d)==list(e))
 94            self.assertEqual(d!=e, not(type(d)==type(e) and list(d)==list(e)))
 95
 96        args = map(deque, ('', 'a', 'b', 'ab', 'ba', 'abc', 'xba', 'xabc', 'cba'))
 97        for x in args:
 98            for y in args:
 99                self.assertEqual(x == y, list(x) == list(y), (x,y))
100                self.assertEqual(x != y, list(x) != list(y), (x,y))
101                self.assertEqual(x <  y, list(x) <  list(y), (x,y))
102                self.assertEqual(x <= y, list(x) <= list(y), (x,y))
103                self.assertEqual(x >  y, list(x) >  list(y), (x,y))
104                self.assertEqual(x >= y, list(x) >= list(y), (x,y))
105                self.assertEqual(cmp(x,y), cmp(list(x),list(y)), (x,y))
106
107    def test_extend(self):
108        d = deque('a')
109        self.assertRaises(TypeError, d.extend, 1)
110        d.extend('bcd')
111        self.assertEqual(list(d), list('abcd'))
112
113    def test_extendleft(self):
114        d = deque('a')
115        self.assertRaises(TypeError, d.extendleft, 1)
116        d.extendleft('bcd')
117        self.assertEqual(list(d), list(reversed('abcd')))
118        d = deque()
119        d.extendleft(range(1000))
120        self.assertEqual(list(d), list(reversed(range(1000))))
121        self.assertRaises(SyntaxError, d.extendleft, fail())
122
123    def test_getitem(self):
124        n = 200
125        d = deque(xrange(n))
126        l = range(n)
127        for i in xrange(n):
128            d.popleft()
129            l.pop(0)
130            if random.random() < 0.5:
131                d.append(i)
132                l.append(i)
133            for j in xrange(1-len(l), len(l)):
134                assert d[j] == l[j]
135
136        d = deque('superman')
137        self.assertEqual(d[0], 's')
138        self.assertEqual(d[-1], 'n')
139        d = deque()
140        self.assertRaises(IndexError, d.__getitem__, 0)
141        self.assertRaises(IndexError, d.__getitem__, -1)
142
143    def test_setitem(self):
144        n = 200
145        d = deque(xrange(n))
146        for i in xrange(n):
147            d[i] = 10 * i
148        self.assertEqual(list(d), [10*i for i in xrange(n)])
149        l = list(d)
150        for i in xrange(1-n, 0, -1):
151            d[i] = 7*i
152            l[i] = 7*i
153        self.assertEqual(list(d), l)
154
155    def test_delitem(self):
156        n = 500         # O(n**2) test, don't make this too big
157        d = deque(xrange(n))
158        self.assertRaises(IndexError, d.__delitem__, -n-1)
159        self.assertRaises(IndexError, d.__delitem__, n)
160        for i in xrange(n):
161            self.assertEqual(len(d), n-i)
162            j = random.randrange(-len(d), len(d))
163            val = d[j]
164            self.assert_(val in d)
165            del d[j]
166            self.assert_(val not in d)
167        self.assertEqual(len(d), 0)
168
169    def test_rotate(self):
170        s = tuple('abcde')
171        n = len(s)
172
173        d = deque(s)
174        d.rotate(1)             # verify rot(1)
175        self.assertEqual(''.join(d), 'eabcd')
176
177        d = deque(s)
178        d.rotate(-1)            # verify rot(-1)
179        self.assertEqual(''.join(d), 'bcdea')
180        d.rotate()              # check default to 1
181        self.assertEqual(tuple(d), s)
182
183        for i in xrange(n*3):
184            d = deque(s)
185            e = deque(d)
186            d.rotate(i)         # check vs. rot(1) n times
187            for j in xrange(i):
188                e.rotate(1)
189            self.assertEqual(tuple(d), tuple(e))
190            d.rotate(-i)        # check that it works in reverse
191            self.assertEqual(tuple(d), s)
192            e.rotate(n-i)       # check that it wraps forward
193            self.assertEqual(tuple(e), s)
194
195        for i in xrange(n*3):
196            d = deque(s)
197            e = deque(d)
198            d.rotate(-i)
199            for j in xrange(i):
200                e.rotate(-1)    # check vs. rot(-1) n times
201            self.assertEqual(tuple(d), tuple(e))
202            d.rotate(i)         # check that it works in reverse
203            self.assertEqual(tuple(d), s)
204            e.rotate(i-n)       # check that it wraps backaround
205            self.assertEqual(tuple(e), s)
206
207        d = deque(s)
208        e = deque(s)
209        e.rotate(BIG+17)        # verify on long series of rotates
210        dr = d.rotate
211        for i in xrange(BIG+17):
212            dr()
213        self.assertEqual(tuple(d), tuple(e))
214
215        self.assertRaises(TypeError, d.rotate, 'x')   # Wrong arg type
216        self.assertRaises(TypeError, d.rotate, 1, 10) # Too many args
217
218        d = deque()
219        d.rotate()              # rotate an empty deque
220        self.assertEqual(d, deque())
221
222    def test_len(self):
223        d = deque('ab')
224        self.assertEqual(len(d), 2)
225        d.popleft()
226        self.assertEqual(len(d), 1)
227        d.pop()
228        self.assertEqual(len(d), 0)
229        self.assertRaises(IndexError, d.pop)
230        self.assertEqual(len(d), 0)
231        d.append('c')
232        self.assertEqual(len(d), 1)
233        d.appendleft('d')
234        self.assertEqual(len(d), 2)
235        d.clear()
236        self.assertEqual(len(d), 0)
237
238    def test_underflow(self):
239        d = deque()
240        self.assertRaises(IndexError, d.pop)
241        self.assertRaises(IndexError, d.popleft)
242
243    def test_clear(self):
244        d = deque(xrange(100))
245        self.assertEqual(len(d), 100)
246        d.clear()
247        self.assertEqual(len(d), 0)
248        self.assertEqual(list(d), [])
249        d.clear()               # clear an emtpy deque
250        self.assertEqual(list(d), [])
251
252    def test_remove(self):
253        d = deque('abcdefghcij')
254        d.remove('c')
255        self.assertEqual(d, deque('abdefghcij'))
256        d.remove('c')
257        self.assertEqual(d, deque('abdefghij'))
258        self.assertRaises(ValueError, d.remove, 'c')
259        self.assertEqual(d, deque('abdefghij'))
260
261        # Handle comparison errors
262        d = deque(['a', 'b', BadCmp(), 'c'])
263        e = deque(d)
264        self.assertRaises(RuntimeError, d.remove, 'c')
265        for x, y in zip(d, e):
266            # verify that original order and values are retained.
267            self.assert_(x is y)
268
269        # Handle evil mutator
270        for match in (True, False):
271            d = deque(['ab'])
272            d.extend([MutateCmp(d, match), 'c'])
273            self.assertRaises(IndexError, d.remove, 'c')
274            self.assertEqual(d, deque())
275
276    def test_repr(self):
277        d = deque(xrange(200))
278        e = eval(repr(d))
279        self.assertEqual(list(d), list(e))
280        d.append(d)
281        self.assert_('...' in repr(d))
282
283    def test_print(self):
284        d = deque(xrange(200))
285        d.append(d)
286        test_support.unlink(test_support.TESTFN)
287        fo = open(test_support.TESTFN, "wb")
288        try:
289            print >> fo, d,
290            fo.close()
291            fo = open(test_support.TESTFN, "rb")
292            self.assertEqual(fo.read(), repr(d))
293        finally:
294            fo.close()
295            test_support.unlink(test_support.TESTFN)
296
297    def test_init(self):
298        self.assertRaises(TypeError, deque, 'abc', 2, 3);
299        self.assertRaises(TypeError, deque, 1);
300
301    def test_hash(self):
302        self.assertRaises(TypeError, hash, deque('abc'))
303
304    def test_long_steadystate_queue_popleft(self):
305        for size in (0, 1, 2, 100, 1000):
306            d = deque(xrange(size))
307            append, pop = d.append, d.popleft
308            for i in xrange(size, BIG):
309                append(i)
310                x = pop()
311                if x != i - size:
312                    self.assertEqual(x, i-size)
313            self.assertEqual(list(d), range(BIG-size, BIG))
314
315    def test_long_steadystate_queue_popright(self):
316        for size in (0, 1, 2, 100, 1000):
317            d = deque(reversed(xrange(size)))
318            append, pop = d.appendleft, d.pop
319            for i in xrange(size, BIG):
320                append(i)
321                x = pop()
322                if x != i - size:
323                    self.assertEqual(x, i-size)
324            self.assertEqual(list(reversed(list(d))), range(BIG-size, BIG))
325
326    def test_big_queue_popleft(self):
327        pass
328        d = deque()
329        append, pop = d.append, d.popleft
330        for i in xrange(BIG):
331            append(i)
332        for i in xrange(BIG):
333            x = pop()
334            if x != i:
335                self.assertEqual(x, i)
336
337    def test_big_queue_popright(self):
338        d = deque()
339        append, pop = d.appendleft, d.pop
340        for i in xrange(BIG):
341            append(i)
342        for i in xrange(BIG):
343            x = pop()
344            if x != i:
345                self.assertEqual(x, i)
346
347    def test_big_stack_right(self):
348        d = deque()
349        append, pop = d.append, d.pop
350        for i in xrange(BIG):
351            append(i)
352        for i in reversed(xrange(BIG)):
353            x = pop()
354            if x != i:
355                self.assertEqual(x, i)
356        self.assertEqual(len(d), 0)
357
358    def test_big_stack_left(self):
359        d = deque()
360        append, pop = d.appendleft, d.popleft
361        for i in xrange(BIG):
362            append(i)
363        for i in reversed(xrange(BIG)):
364            x = pop()
365            if x != i:
366                self.assertEqual(x, i)
367        self.assertEqual(len(d), 0)
368
369    def test_roundtrip_iter_init(self):
370        d = deque(xrange(200))
371        e = deque(d)
372        self.assertNotEqual(id(d), id(e))
373        self.assertEqual(list(d), list(e))
374
375    def test_pickle(self):
376        d = deque(xrange(200))
377        for i in range(pickle.HIGHEST_PROTOCOL + 1):
378            s = pickle.dumps(d, i)
379            e = pickle.loads(s)
380            self.assertNotEqual(id(d), id(e))
381            self.assertEqual(list(d), list(e))
382
383##    def test_pickle_recursive(self):
384##        d = deque('abc')
385##        d.append(d)
386##        for i in range(pickle.HIGHEST_PROTOCOL + 1):
387##            e = pickle.loads(pickle.dumps(d, i))
388##            self.assertNotEqual(id(d), id(e))
389##            self.assertEqual(id(e), id(e[-1]))
390
391    def test_deepcopy(self):
392        mut = [10]
393        d = deque([mut])
394        e = copy.deepcopy(d)
395        self.assertEqual(list(d), list(e))
396        mut[0] = 11
397        self.assertNotEqual(id(d), id(e))
398        self.assertNotEqual(list(d), list(e))
399
400    def test_copy(self):
401        mut = [10]
402        d = deque([mut])
403        e = copy.copy(d)
404        self.assertEqual(list(d), list(e))
405        mut[0] = 11
406        self.assertNotEqual(id(d), id(e))
407        self.assertEqual(list(d), list(e))
408
409    def test_reversed(self):
410        for s in ('abcd', xrange(2000)):
411            self.assertEqual(list(reversed(deque(s))), list(reversed(s)))
412
413    def test_gc_doesnt_blowup(self):
414        import gc
415        # This used to assert-fail in deque_traverse() under a debug
416        # build, or run wild with a NULL pointer in a release build.
417        d = deque()
418        for i in xrange(100):
419            d.append(1)
420            gc.collect()
421
422    def test_container_iterator(self):
423        # Bug #3680: tp_traverse was not implemented for deque iterator objects
424        class C(object):
425            pass
426        for i in range(2):
427            obj = C()
428            ref = weakref.ref(obj)
429            if i == 0:
430                container = deque([obj, 1])
431            else:
432                container = reversed(deque([obj, 1]))
433            obj.x = iter(container)
434            del obj, container
435            gc.collect()
436            self.assert_(ref() is None, "Cycle was not collected")
437
438class TestVariousIteratorArgs(unittest.TestCase):
439
440    def test_constructor(self):
441        for s in ("123", "", range(1000), ('do', 1.2), xrange(2000,2200,5)):
442            for g in (seq_tests.Sequence, seq_tests.IterFunc,
443                      seq_tests.IterGen, seq_tests.IterFuncStop,
444                      seq_tests.itermulti, seq_tests.iterfunc):
445                self.assertEqual(list(deque(g(s))), list(g(s)))
446            self.assertRaises(TypeError, deque, seq_tests.IterNextOnly(s))
447            self.assertRaises(TypeError, deque, seq_tests.IterNoNext(s))
448            self.assertRaises(ZeroDivisionError, deque, seq_tests.IterGenExc(s))
449
450    def test_iter_with_altered_data(self):
451        d = deque('abcdefg')
452        it = iter(d)
453        d.pop()
454        self.assertRaises(RuntimeError, it.next)
455
456    def test_runtime_error_on_empty_deque(self):
457        d = deque()
458        it = iter(d)
459        d.append(10)
460        self.assertRaises(RuntimeError, it.next)
461
462class Deque(deque):
463    pass
464
465class DequeWithBadIter(deque):
466    def __iter__(self):
467        raise TypeError
468
469class TestSubclass(unittest.TestCase):
470
471    def test_basics(self):
472        d = Deque(xrange(25))
473        d.__init__(xrange(200))
474        for i in xrange(200, 400):
475            d.append(i)
476        for i in reversed(xrange(-200, 0)):
477            d.appendleft(i)
478        self.assertEqual(list(d), range(-200, 400))
479        self.assertEqual(len(d), 600)
480
481        left = [d.popleft() for i in xrange(250)]
482        self.assertEqual(left, range(-200, 50))
483        self.assertEqual(list(d), range(50, 400))
484
485        right = [d.pop() for i in xrange(250)]
486        right.reverse()
487        self.assertEqual(right, range(150, 400))
488        self.assertEqual(list(d), range(50, 150))
489
490        d.clear()
491        self.assertEqual(len(d), 0)
492
493    def test_copy_pickle(self):
494
495        d = Deque('abc')
496
497        e = d.__copy__()
498        self.assertEqual(type(d), type(e))
499        self.assertEqual(list(d), list(e))
500
501        e = Deque(d)
502        self.assertEqual(type(d), type(e))
503        self.assertEqual(list(d), list(e))
504
505        s = pickle.dumps(d)
506        e = pickle.loads(s)
507        self.assertNotEqual(id(d), id(e))
508        self.assertEqual(type(d), type(e))
509        self.assertEqual(list(d), list(e))
510
511        d = Deque('abcde', maxlen=4)
512
513        e = d.__copy__()
514        self.assertEqual(type(d), type(e))
515        self.assertEqual(list(d), list(e))
516
517        e = Deque(d)
518        self.assertEqual(type(d), type(e))
519        self.assertEqual(list(d), list(e))
520
521        s = pickle.dumps(d)
522        e = pickle.loads(s)
523        self.assertNotEqual(id(d), id(e))
524        self.assertEqual(type(d), type(e))
525        self.assertEqual(list(d), list(e))
526
527##    def test_pickle(self):
528##        d = Deque('abc')
529##        d.append(d)
530##
531##        e = pickle.loads(pickle.dumps(d))
532##        self.assertNotEqual(id(d), id(e))
533##        self.assertEqual(type(d), type(e))
534##        dd = d.pop()
535##        ee = e.pop()
536##        self.assertEqual(id(e), id(ee))
537##        self.assertEqual(d, e)
538##
539##        d.x = d
540##        e = pickle.loads(pickle.dumps(d))
541##        self.assertEqual(id(e), id(e.x))
542##
543##        d = DequeWithBadIter('abc')
544##        self.assertRaises(TypeError, pickle.dumps, d)
545
546    def test_weakref(self):
547        d = deque('gallahad')
548        p = weakref.proxy(d)
549        self.assertEqual(str(p), str(d))
550        d = None
551        self.assertRaises(ReferenceError, str, p)
552
553    def test_strange_subclass(self):
554        class X(deque):
555            def __iter__(self):
556                return iter([])
557        d1 = X([1,2,3])
558        d2 = X([4,5,6])
559        d1 == d2   # not clear if this is supposed to be True or False,
560                   # but it used to give a SystemError
561
562
563class SubclassWithKwargs(deque):
564    def __init__(self, newarg=1):
565        deque.__init__(self)
566
567class TestSubclassWithKwargs(unittest.TestCase):
568    def test_subclass_with_kwargs(self):
569        # SF bug #1486663 -- this used to erroneously raise a TypeError
570        SubclassWithKwargs(newarg=1)
571
572#==============================================================================
573
574libreftest = """
575Example from the Library Reference:  Doc/lib/libcollections.tex
576
577>>> from collections import deque
578>>> d = deque('ghi')                 # make a new deque with three items
579>>> for elem in d:                   # iterate over the deque's elements
580...     print elem.upper()
581G
582H
583I
584>>> d.append('j')                    # add a new entry to the right side
585>>> d.appendleft('f')                # add a new entry to the left side
586>>> d                                # show the representation of the deque
587deque(['f', 'g', 'h', 'i', 'j'])
588>>> d.pop()                          # return and remove the rightmost item
589'j'
590>>> d.popleft()                      # return and remove the leftmost item
591'f'
592>>> list(d)                          # list the contents of the deque
593['g', 'h', 'i']
594>>> d[0]                             # peek at leftmost item
595'g'
596>>> d[-1]                            # peek at rightmost item
597'i'
598>>> list(reversed(d))                # list the contents of a deque in reverse
599['i', 'h', 'g']
600>>> 'h' in d                         # search the deque
601True
602>>> d.extend('jkl')                  # add multiple elements at once
603>>> d
604deque(['g', 'h', 'i', 'j', 'k', 'l'])
605>>> d.rotate(1)                      # right rotation
606>>> d
607deque(['l', 'g', 'h', 'i', 'j', 'k'])
608>>> d.rotate(-1)                     # left rotation
609>>> d
610deque(['g', 'h', 'i', 'j', 'k', 'l'])
611>>> deque(reversed(d))               # make a new deque in reverse order
612deque(['l', 'k', 'j', 'i', 'h', 'g'])
613>>> d.clear()                        # empty the deque
614>>> d.pop()                          # cannot pop from an empty deque
615Traceback (most recent call last):
616  File "<pyshell#6>", line 1, in -toplevel-
617    d.pop()
618IndexError: pop from an empty deque
619
620>>> d.extendleft('abc')              # extendleft() reverses the input order
621>>> d
622deque(['c', 'b', 'a'])
623
624
625
626>>> def delete_nth(d, n):
627...     d.rotate(-n)
628...     d.popleft()
629...     d.rotate(n)
630...
631>>> d = deque('abcdef')
632>>> delete_nth(d, 2)   # remove the entry at d[2]
633>>> d
634deque(['a', 'b', 'd', 'e', 'f'])
635
636
637
638>>> def roundrobin(*iterables):
639...     pending = deque(iter(i) for i in iterables)
640...     while pending:
641...         task = pending.popleft()
642...         try:
643...             yield task.next()
644...         except StopIteration:
645...             continue
646...         pending.append(task)
647...
648
649>>> for value in roundrobin('abc', 'd', 'efgh'):
650...     print value
651...
652a
653d
654e
655b
656f
657c
658g
659h
660
661
662>>> def maketree(iterable):
663...     d = deque(iterable)
664...     while len(d) > 1:
665...         pair = [d.popleft(), d.popleft()]
666...         d.append(pair)
667...     return list(d)
668...
669>>> print maketree('abcdefgh')
670[[[['a', 'b'], ['c', 'd']], [['e', 'f'], ['g', 'h']]]]
671
672"""
673
674
675#==============================================================================
676
677__test__ = {'libreftest' : libreftest}
678
679def test_main(verbose=None):
680    import sys
681    test_classes = (
682        TestBasic,
683        TestVariousIteratorArgs,
684        TestSubclass,
685        TestSubclassWithKwargs,
686    )
687
688    test_support.run_unittest(*test_classes)
689
690    # verify reference counting
691    if verbose and hasattr(sys, "gettotalrefcount"):
692        import gc
693        counts = [None] * 5
694        for i in xrange(len(counts)):
695            test_support.run_unittest(*test_classes)
696            gc.collect()
697            counts[i] = sys.gettotalrefcount()
698        print counts
699
700    # doctests
701    from test import test_deque
702    test_support.run_doctest(test_deque, verbose)
703
704if __name__ == "__main__":
705    test_main(verbose=True)