blob: 13800ea215f2879f351d3877be08b8b9378f8e47 [file] [log] [blame]
Raymond Hettinger756b3f32004-01-29 06:37:52 +00001from collections import deque
2import unittest
3from test import test_support
Raymond Hettinger691d8052004-05-30 07:26:47 +00004from weakref import proxy
Raymond Hettinger756b3f32004-01-29 06:37:52 +00005import copy
6import cPickle as pickle
7from cStringIO import StringIO
Raymond Hettinger0a4977c2004-03-01 23:16:22 +00008import random
Raymond Hettinger756b3f32004-01-29 06:37:52 +00009
10BIG = 100000
11
12class TestBasic(unittest.TestCase):
13
14 def test_basics(self):
15 d = deque(xrange(100))
16 d.__init__(xrange(100, 200))
17 for i in xrange(200, 400):
18 d.append(i)
19 for i in reversed(xrange(-200, 0)):
20 d.appendleft(i)
21 self.assertEqual(list(d), range(-200, 400))
22 self.assertEqual(len(d), 600)
23
24 left = [d.popleft() for i in xrange(250)]
25 self.assertEqual(left, range(-200, 50))
26 self.assertEqual(list(d), range(50, 400))
27
28 right = [d.pop() for i in xrange(250)]
29 right.reverse()
30 self.assertEqual(right, range(150, 400))
31 self.assertEqual(list(d), range(50, 150))
32
Raymond Hettinger738ec902004-02-29 02:15:56 +000033 def test_comparisons(self):
34 d = deque('xabc'); d.popleft()
35 for e in [d, deque('abc'), deque('ab'), deque(), list(d)]:
36 self.assertEqual(d==e, type(d)==type(e) and list(d)==list(e))
37 self.assertEqual(d!=e, not(type(d)==type(e) and list(d)==list(e)))
38
39 args = map(deque, ('', 'a', 'b', 'ab', 'ba', 'abc', 'xba', 'xabc', 'cba'))
40 for x in args:
41 for y in args:
42 self.assertEqual(x == y, list(x) == list(y), (x,y))
43 self.assertEqual(x != y, list(x) != list(y), (x,y))
44 self.assertEqual(x < y, list(x) < list(y), (x,y))
45 self.assertEqual(x <= y, list(x) <= list(y), (x,y))
46 self.assertEqual(x > y, list(x) > list(y), (x,y))
47 self.assertEqual(x >= y, list(x) >= list(y), (x,y))
48 self.assertEqual(cmp(x,y), cmp(list(x),list(y)), (x,y))
49
Raymond Hettinger3ba85c22004-02-06 19:04:56 +000050 def test_extend(self):
51 d = deque('a')
52 self.assertRaises(TypeError, d.extend, 1)
53 d.extend('bcd')
54 self.assertEqual(list(d), list('abcd'))
55
56 def test_extendleft(self):
57 d = deque('a')
58 self.assertRaises(TypeError, d.extendleft, 1)
59 d.extendleft('bcd')
60 self.assertEqual(list(d), list(reversed('abcd')))
61
Raymond Hettinger0a4977c2004-03-01 23:16:22 +000062 def test_getitem(self):
63 n = 200
64 d = deque(xrange(n))
65 l = range(n)
66 for i in xrange(n):
67 d.popleft()
68 l.pop(0)
69 if random.random() < 0.5:
70 d.append(i)
71 l.append(i)
72 for j in xrange(1-len(l), len(l)):
73 assert d[j] == l[j]
74
Raymond Hettinger738ec902004-02-29 02:15:56 +000075 d = deque('superman')
Raymond Hettinger0a4977c2004-03-01 23:16:22 +000076 self.assertEqual(d[0], 's')
77 self.assertEqual(d[-1], 'n')
Raymond Hettinger738ec902004-02-29 02:15:56 +000078 d = deque()
Raymond Hettinger0a4977c2004-03-01 23:16:22 +000079 self.assertRaises(IndexError, d.__getitem__, 0)
80 self.assertRaises(IndexError, d.__getitem__, -1)
81
82 def test_setitem(self):
83 n = 200
84 d = deque(xrange(n))
85 for i in xrange(n):
86 d[i] = 10 * i
87 self.assertEqual(list(d), [10*i for i in xrange(n)])
88 l = list(d)
89 for i in xrange(1-n, 0, -1):
90 d[i] = 7*i
91 l[i] = 7*i
92 self.assertEqual(list(d), l)
Raymond Hettinger738ec902004-02-29 02:15:56 +000093
Raymond Hettinger0e371f22004-05-12 20:55:56 +000094 def test_delitem(self):
95 n = 500 # O(n**2) test, don't make this too big
96 d = deque(xrange(n))
97 self.assertRaises(IndexError, d.__delitem__, -n-1)
98 self.assertRaises(IndexError, d.__delitem__, n)
99 for i in xrange(n):
100 self.assertEqual(len(d), n-i)
101 j = random.randrange(-len(d), len(d))
102 val = d[j]
103 self.assert_(val in d)
104 del d[j]
105 self.assert_(val not in d)
106 self.assertEqual(len(d), 0)
107
Raymond Hettinger5c5eb862004-02-07 21:13:00 +0000108 def test_rotate(self):
Raymond Hettingeree33b272004-02-08 04:05:26 +0000109 s = tuple('abcde')
110 n = len(s)
111
Raymond Hettinger5c5eb862004-02-07 21:13:00 +0000112 d = deque(s)
Raymond Hettingeree33b272004-02-08 04:05:26 +0000113 d.rotate(1) # verify rot(1)
114 self.assertEqual(''.join(d), 'eabcd')
115
116 d = deque(s)
117 d.rotate(-1) # verify rot(-1)
118 self.assertEqual(''.join(d), 'bcdea')
119 d.rotate() # check default to 1
120 self.assertEqual(tuple(d), s)
121
122 for i in xrange(n*3):
123 d = deque(s)
124 e = deque(d)
125 d.rotate(i) # check vs. rot(1) n times
126 for j in xrange(i):
127 e.rotate(1)
128 self.assertEqual(tuple(d), tuple(e))
129 d.rotate(-i) # check that it works in reverse
130 self.assertEqual(tuple(d), s)
131 e.rotate(n-i) # check that it wraps forward
132 self.assertEqual(tuple(e), s)
133
134 for i in xrange(n*3):
135 d = deque(s)
136 e = deque(d)
137 d.rotate(-i)
138 for j in xrange(i):
139 e.rotate(-1) # check vs. rot(-1) n times
140 self.assertEqual(tuple(d), tuple(e))
141 d.rotate(i) # check that it works in reverse
142 self.assertEqual(tuple(d), s)
143 e.rotate(i-n) # check that it wraps backaround
144 self.assertEqual(tuple(e), s)
145
146 d = deque(s)
147 e = deque(s)
148 e.rotate(BIG+17) # verify on long series of rotates
149 dr = d.rotate
150 for i in xrange(BIG+17):
151 dr()
152 self.assertEqual(tuple(d), tuple(e))
Raymond Hettinger5c5eb862004-02-07 21:13:00 +0000153
Raymond Hettinger756b3f32004-01-29 06:37:52 +0000154 def test_len(self):
155 d = deque('ab')
156 self.assertEqual(len(d), 2)
157 d.popleft()
158 self.assertEqual(len(d), 1)
159 d.pop()
160 self.assertEqual(len(d), 0)
Raymond Hettinger738ec902004-02-29 02:15:56 +0000161 self.assertRaises(IndexError, d.pop)
Raymond Hettinger756b3f32004-01-29 06:37:52 +0000162 self.assertEqual(len(d), 0)
163 d.append('c')
164 self.assertEqual(len(d), 1)
165 d.appendleft('d')
166 self.assertEqual(len(d), 2)
167 d.clear()
168 self.assertEqual(len(d), 0)
169
170 def test_underflow(self):
171 d = deque()
Raymond Hettinger738ec902004-02-29 02:15:56 +0000172 self.assertRaises(IndexError, d.pop)
173 self.assertRaises(IndexError, d.popleft)
Raymond Hettinger756b3f32004-01-29 06:37:52 +0000174
175 def test_clear(self):
176 d = deque(xrange(100))
177 self.assertEqual(len(d), 100)
178 d.clear()
179 self.assertEqual(len(d), 0)
180 self.assertEqual(list(d), [])
181
182 def test_repr(self):
183 d = deque(xrange(200))
184 e = eval(repr(d))
185 self.assertEqual(list(d), list(e))
186 d.append(d)
187 self.assert_('...' in repr(d))
188
189 def test_print(self):
190 d = deque(xrange(200))
191 d.append(d)
192 f = StringIO()
193 print >> f, d,
194 self.assertEqual(f.getvalue(), repr(d))
195 f.close()
196
197 def test_hash(self):
198 self.assertRaises(TypeError, hash, deque('abc'))
199
200 def test_long_steadystate_queue_popleft(self):
201 for size in (0, 1, 2, 100, 1000):
202 d = deque(xrange(size))
203 append, pop = d.append, d.popleft
204 for i in xrange(size, BIG):
205 append(i)
206 x = pop()
207 if x != i - size:
208 self.assertEqual(x, i-size)
209 self.assertEqual(list(d), range(BIG-size, BIG))
210
211 def test_long_steadystate_queue_popright(self):
212 for size in (0, 1, 2, 100, 1000):
213 d = deque(reversed(xrange(size)))
214 append, pop = d.appendleft, d.pop
215 for i in xrange(size, BIG):
216 append(i)
217 x = pop()
218 if x != i - size:
219 self.assertEqual(x, i-size)
220 self.assertEqual(list(reversed(list(d))), range(BIG-size, BIG))
221
222 def test_big_queue_popleft(self):
223 pass
224 d = deque()
225 append, pop = d.append, d.popleft
226 for i in xrange(BIG):
227 append(i)
228 for i in xrange(BIG):
229 x = pop()
230 if x != i:
231 self.assertEqual(x, i)
232
233 def test_big_queue_popright(self):
234 d = deque()
235 append, pop = d.appendleft, d.pop
236 for i in xrange(BIG):
237 append(i)
238 for i in xrange(BIG):
239 x = pop()
240 if x != i:
241 self.assertEqual(x, i)
242
243 def test_big_stack_right(self):
244 d = deque()
245 append, pop = d.append, d.pop
246 for i in xrange(BIG):
247 append(i)
248 for i in reversed(xrange(BIG)):
249 x = pop()
250 if x != i:
251 self.assertEqual(x, i)
252 self.assertEqual(len(d), 0)
253
254 def test_big_stack_left(self):
255 d = deque()
256 append, pop = d.appendleft, d.popleft
257 for i in xrange(BIG):
258 append(i)
259 for i in reversed(xrange(BIG)):
260 x = pop()
261 if x != i:
262 self.assertEqual(x, i)
263 self.assertEqual(len(d), 0)
264
265 def test_roundtrip_iter_init(self):
266 d = deque(xrange(200))
267 e = deque(d)
268 self.assertNotEqual(id(d), id(e))
269 self.assertEqual(list(d), list(e))
270
271 def test_pickle(self):
272 d = deque(xrange(200))
273 s = pickle.dumps(d)
274 e = pickle.loads(s)
275 self.assertNotEqual(id(d), id(e))
276 self.assertEqual(list(d), list(e))
277
278 def test_deepcopy(self):
279 mut = [10]
280 d = deque([mut])
281 e = copy.deepcopy(d)
282 self.assertEqual(list(d), list(e))
283 mut[0] = 11
284 self.assertNotEqual(id(d), id(e))
285 self.assertNotEqual(list(d), list(e))
286
287 def test_copy(self):
288 mut = [10]
289 d = deque([mut])
290 e = copy.copy(d)
291 self.assertEqual(list(d), list(e))
292 mut[0] = 11
293 self.assertNotEqual(id(d), id(e))
294 self.assertEqual(list(d), list(e))
295
Raymond Hettingerc058fd12004-02-07 02:45:22 +0000296 def test_reversed(self):
297 for s in ('abcd', xrange(2000)):
298 self.assertEqual(list(reversed(deque(s))), list(reversed(s)))
299
Raymond Hettinger756b3f32004-01-29 06:37:52 +0000300def R(seqn):
301 'Regular generator'
302 for i in seqn:
303 yield i
304
305class G:
306 'Sequence using __getitem__'
307 def __init__(self, seqn):
308 self.seqn = seqn
309 def __getitem__(self, i):
310 return self.seqn[i]
311
312class I:
313 'Sequence using iterator protocol'
314 def __init__(self, seqn):
315 self.seqn = seqn
316 self.i = 0
317 def __iter__(self):
318 return self
319 def next(self):
320 if self.i >= len(self.seqn): raise StopIteration
321 v = self.seqn[self.i]
322 self.i += 1
323 return v
324
325class Ig:
326 'Sequence using iterator protocol defined with a generator'
327 def __init__(self, seqn):
328 self.seqn = seqn
329 self.i = 0
330 def __iter__(self):
331 for val in self.seqn:
332 yield val
333
334class X:
335 'Missing __getitem__ and __iter__'
336 def __init__(self, seqn):
337 self.seqn = seqn
338 self.i = 0
339 def next(self):
340 if self.i >= len(self.seqn): raise StopIteration
341 v = self.seqn[self.i]
342 self.i += 1
343 return v
344
345class N:
346 'Iterator missing next()'
347 def __init__(self, seqn):
348 self.seqn = seqn
349 self.i = 0
350 def __iter__(self):
351 return self
352
353class E:
354 'Test propagation of exceptions'
355 def __init__(self, seqn):
356 self.seqn = seqn
357 self.i = 0
358 def __iter__(self):
359 return self
360 def next(self):
361 3/0
362
363class S:
364 'Test immediate stop'
365 def __init__(self, seqn):
366 pass
367 def __iter__(self):
368 return self
369 def next(self):
370 raise StopIteration
371
372from itertools import chain, imap
373def L(seqn):
374 'Test multiple tiers of iterators'
375 return chain(imap(lambda x:x, R(Ig(G(seqn)))))
376
377
378class TestVariousIteratorArgs(unittest.TestCase):
379
380 def test_constructor(self):
381 for s in ("123", "", range(1000), ('do', 1.2), xrange(2000,2200,5)):
382 for g in (G, I, Ig, S, L, R):
383 self.assertEqual(list(deque(g(s))), list(g(s)))
384 self.assertRaises(TypeError, deque, X(s))
385 self.assertRaises(TypeError, deque, N(s))
386 self.assertRaises(ZeroDivisionError, deque, E(s))
387
388 def test_iter_with_altered_data(self):
389 d = deque('abcdefg')
390 it = iter(d)
391 d.pop()
392 self.assertRaises(RuntimeError, it.next)
393
394class Deque(deque):
395 pass
396
397class TestSubclass(unittest.TestCase):
398
399 def test_basics(self):
400 d = Deque(xrange(100))
401 d.__init__(xrange(100, 200))
402 for i in xrange(200, 400):
403 d.append(i)
404 for i in reversed(xrange(-200, 0)):
405 d.appendleft(i)
406 self.assertEqual(list(d), range(-200, 400))
407 self.assertEqual(len(d), 600)
408
409 left = [d.popleft() for i in xrange(250)]
410 self.assertEqual(left, range(-200, 50))
411 self.assertEqual(list(d), range(50, 400))
412
413 right = [d.pop() for i in xrange(250)]
414 right.reverse()
415 self.assertEqual(right, range(150, 400))
416 self.assertEqual(list(d), range(50, 150))
417
418 d.clear()
419 self.assertEqual(len(d), 0)
420
421 def test_copy_pickle(self):
422
423 d = Deque('abc')
424
425 e = d.__copy__()
426 self.assertEqual(type(d), type(e))
427 self.assertEqual(list(d), list(e))
428
429 e = Deque(d)
430 self.assertEqual(type(d), type(e))
431 self.assertEqual(list(d), list(e))
432
433 s = pickle.dumps(d)
434 e = pickle.loads(s)
435 self.assertNotEqual(id(d), id(e))
436 self.assertEqual(type(d), type(e))
437 self.assertEqual(list(d), list(e))
438
Raymond Hettinger691d8052004-05-30 07:26:47 +0000439 def test_weakref(self):
440 d = deque('gallahad')
441 p = proxy(d)
442 self.assertEqual(str(p), str(d))
443 d = None
444 self.assertRaises(ReferenceError, str, p)
Raymond Hettinger756b3f32004-01-29 06:37:52 +0000445
446#==============================================================================
447
Raymond Hettinger738ec902004-02-29 02:15:56 +0000448libreftest = """
449Example from the Library Reference: Doc/lib/libcollections.tex
450
451>>> from collections import deque
452>>> d = deque('ghi') # make a new deque with three items
453>>> for elem in d: # iterate over the deque's elements
Raymond Hettinger0a4977c2004-03-01 23:16:22 +0000454... print elem.upper()
Raymond Hettinger738ec902004-02-29 02:15:56 +0000455G
456H
457I
458>>> d.append('j') # add a new entry to the right side
459>>> d.appendleft('f') # add a new entry to the left side
460>>> d # show the representation of the deque
461deque(['f', 'g', 'h', 'i', 'j'])
462>>> d.pop() # return and remove the rightmost item
463'j'
464>>> d.popleft() # return and remove the leftmost item
465'f'
466>>> list(d) # list the contents of the deque
467['g', 'h', 'i']
Raymond Hettinger0a4977c2004-03-01 23:16:22 +0000468>>> d[0] # peek at leftmost item
Raymond Hettinger738ec902004-02-29 02:15:56 +0000469'g'
Raymond Hettinger0a4977c2004-03-01 23:16:22 +0000470>>> d[-1] # peek at rightmost item
Raymond Hettinger738ec902004-02-29 02:15:56 +0000471'i'
472>>> list(reversed(d)) # list the contents of a deque in reverse
473['i', 'h', 'g']
474>>> 'h' in d # search the deque
475True
476>>> d.extend('jkl') # add multiple elements at once
477>>> d
478deque(['g', 'h', 'i', 'j', 'k', 'l'])
479>>> d.rotate(1) # right rotation
480>>> d
481deque(['l', 'g', 'h', 'i', 'j', 'k'])
482>>> d.rotate(-1) # left rotation
483>>> d
484deque(['g', 'h', 'i', 'j', 'k', 'l'])
485>>> deque(reversed(d)) # make a new deque in reverse order
486deque(['l', 'k', 'j', 'i', 'h', 'g'])
487>>> d.clear() # empty the deque
488>>> d.pop() # cannot pop from an empty deque
489Traceback (most recent call last):
490 File "<pyshell#6>", line 1, in -toplevel-
491 d.pop()
492IndexError: pop from an empty deque
493
494>>> d.extendleft('abc') # extendleft() reverses the input order
495>>> d
496deque(['c', 'b', 'a'])
497
Raymond Hettingere7169eb2004-05-09 01:15:01 +0000498
499
Raymond Hettingere7169eb2004-05-09 01:15:01 +0000500>>> def delete_nth(d, n):
Raymond Hettingere7169eb2004-05-09 01:15:01 +0000501... d.rotate(-n)
502... d.popleft()
503... d.rotate(n)
504...
505>>> d = deque('abcdef')
506>>> delete_nth(d, 2) # remove the entry at d[2]
507>>> d
508deque(['a', 'b', 'd', 'e', 'f'])
509
510
511
512>>> def roundrobin(*iterables):
513... pending = deque(iter(i) for i in iterables)
514... while pending:
515... task = pending.popleft()
516... try:
517... yield task.next()
518... except StopIteration:
519... continue
520... pending.append(task)
521...
522
523>>> for value in roundrobin('abc', 'd', 'efgh'):
524... print value
525...
526a
527d
528e
529b
530f
531c
532g
533h
534
535
536>>> def maketree(iterable):
537... d = deque(iterable)
538... while len(d) > 1:
539... pair = [d.popleft(), d.popleft()]
540... d.append(pair)
541... return list(d)
542...
543>>> print maketree('abcdefgh')
544[[[['a', 'b'], ['c', 'd']], [['e', 'f'], ['g', 'h']]]]
545
Raymond Hettinger738ec902004-02-29 02:15:56 +0000546"""
547
548
549#==============================================================================
550
551__test__ = {'libreftest' : libreftest}
552
Raymond Hettinger756b3f32004-01-29 06:37:52 +0000553def test_main(verbose=None):
554 import sys
555 from test import test_sets
556 test_classes = (
557 TestBasic,
558 TestVariousIteratorArgs,
559 TestSubclass,
560 )
561
562 test_support.run_unittest(*test_classes)
563
564 # verify reference counting
565 if verbose and hasattr(sys, "gettotalrefcount"):
566 import gc
567 counts = [None] * 5
568 for i in xrange(len(counts)):
569 test_support.run_unittest(*test_classes)
570 gc.collect()
571 counts[i] = sys.gettotalrefcount()
572 print counts
Raymond Hettinger0a4977c2004-03-01 23:16:22 +0000573
Raymond Hettinger738ec902004-02-29 02:15:56 +0000574 # doctests
575 from test import test_deque
Raymond Hettinger354433a2004-05-19 08:20:33 +0000576 test_support.run_doctest(test_deque, verbose)
Raymond Hettinger756b3f32004-01-29 06:37:52 +0000577
578if __name__ == "__main__":
579 test_main(verbose=True)