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