|
1 import unittest |
|
2 import sys |
|
3 |
|
4 from test import test_support |
|
5 |
|
6 class G: |
|
7 'Sequence using __getitem__' |
|
8 def __init__(self, seqn): |
|
9 self.seqn = seqn |
|
10 def __getitem__(self, i): |
|
11 return self.seqn[i] |
|
12 |
|
13 class I: |
|
14 'Sequence using iterator protocol' |
|
15 def __init__(self, seqn): |
|
16 self.seqn = seqn |
|
17 self.i = 0 |
|
18 def __iter__(self): |
|
19 return self |
|
20 def next(self): |
|
21 if self.i >= len(self.seqn): raise StopIteration |
|
22 v = self.seqn[self.i] |
|
23 self.i += 1 |
|
24 return v |
|
25 |
|
26 class Ig: |
|
27 'Sequence using iterator protocol defined with a generator' |
|
28 def __init__(self, seqn): |
|
29 self.seqn = seqn |
|
30 self.i = 0 |
|
31 def __iter__(self): |
|
32 for val in self.seqn: |
|
33 yield val |
|
34 |
|
35 class X: |
|
36 'Missing __getitem__ and __iter__' |
|
37 def __init__(self, seqn): |
|
38 self.seqn = seqn |
|
39 self.i = 0 |
|
40 def next(self): |
|
41 if self.i >= len(self.seqn): raise StopIteration |
|
42 v = self.seqn[self.i] |
|
43 self.i += 1 |
|
44 return v |
|
45 |
|
46 class E: |
|
47 'Test propagation of exceptions' |
|
48 def __init__(self, seqn): |
|
49 self.seqn = seqn |
|
50 self.i = 0 |
|
51 def __iter__(self): |
|
52 return self |
|
53 def next(self): |
|
54 3 // 0 |
|
55 |
|
56 class N: |
|
57 'Iterator missing next()' |
|
58 def __init__(self, seqn): |
|
59 self.seqn = seqn |
|
60 self.i = 0 |
|
61 def __iter__(self): |
|
62 return self |
|
63 |
|
64 class EnumerateTestCase(unittest.TestCase): |
|
65 |
|
66 enum = enumerate |
|
67 seq, res = 'abc', [(0,'a'), (1,'b'), (2,'c')] |
|
68 |
|
69 def test_basicfunction(self): |
|
70 self.assertEqual(type(self.enum(self.seq)), self.enum) |
|
71 e = self.enum(self.seq) |
|
72 self.assertEqual(iter(e), e) |
|
73 self.assertEqual(list(self.enum(self.seq)), self.res) |
|
74 self.enum.__doc__ |
|
75 |
|
76 def test_getitemseqn(self): |
|
77 self.assertEqual(list(self.enum(G(self.seq))), self.res) |
|
78 e = self.enum(G('')) |
|
79 self.assertRaises(StopIteration, e.next) |
|
80 |
|
81 def test_iteratorseqn(self): |
|
82 self.assertEqual(list(self.enum(I(self.seq))), self.res) |
|
83 e = self.enum(I('')) |
|
84 self.assertRaises(StopIteration, e.next) |
|
85 |
|
86 def test_iteratorgenerator(self): |
|
87 self.assertEqual(list(self.enum(Ig(self.seq))), self.res) |
|
88 e = self.enum(Ig('')) |
|
89 self.assertRaises(StopIteration, e.next) |
|
90 |
|
91 def test_noniterable(self): |
|
92 self.assertRaises(TypeError, self.enum, X(self.seq)) |
|
93 |
|
94 def test_illformediterable(self): |
|
95 self.assertRaises(TypeError, list, self.enum(N(self.seq))) |
|
96 |
|
97 def test_exception_propagation(self): |
|
98 self.assertRaises(ZeroDivisionError, list, self.enum(E(self.seq))) |
|
99 |
|
100 def test_argumentcheck(self): |
|
101 self.assertRaises(TypeError, self.enum) # no arguments |
|
102 self.assertRaises(TypeError, self.enum, 1) # wrong type (not iterable) |
|
103 self.assertRaises(TypeError, self.enum, 'abc', 2) # too many arguments |
|
104 |
|
105 def test_tuple_reuse(self): |
|
106 # Tests an implementation detail where tuple is reused |
|
107 # whenever nothing else holds a reference to it |
|
108 self.assertEqual(len(set(map(id, list(enumerate(self.seq))))), len(self.seq)) |
|
109 self.assertEqual(len(set(map(id, enumerate(self.seq)))), min(1,len(self.seq))) |
|
110 |
|
111 class MyEnum(enumerate): |
|
112 pass |
|
113 |
|
114 class SubclassTestCase(EnumerateTestCase): |
|
115 |
|
116 enum = MyEnum |
|
117 |
|
118 class TestEmpty(EnumerateTestCase): |
|
119 |
|
120 seq, res = '', [] |
|
121 |
|
122 class TestBig(EnumerateTestCase): |
|
123 |
|
124 seq = range(10,20000,2) |
|
125 res = zip(range(20000), seq) |
|
126 |
|
127 class TestReversed(unittest.TestCase): |
|
128 |
|
129 def test_simple(self): |
|
130 class A: |
|
131 def __getitem__(self, i): |
|
132 if i < 5: |
|
133 return str(i) |
|
134 raise StopIteration |
|
135 def __len__(self): |
|
136 return 5 |
|
137 for data in 'abc', range(5), tuple(enumerate('abc')), A(), xrange(1,17,5): |
|
138 self.assertEqual(list(data)[::-1], list(reversed(data))) |
|
139 self.assertRaises(TypeError, reversed, {}) |
|
140 |
|
141 def test_xrange_optimization(self): |
|
142 x = xrange(1) |
|
143 self.assertEqual(type(reversed(x)), type(iter(x))) |
|
144 |
|
145 def test_len(self): |
|
146 # This is an implementation detail, not an interface requirement |
|
147 from test.test_iterlen import len |
|
148 for s in ('hello', tuple('hello'), list('hello'), xrange(5)): |
|
149 self.assertEqual(len(reversed(s)), len(s)) |
|
150 r = reversed(s) |
|
151 list(r) |
|
152 self.assertEqual(len(r), 0) |
|
153 class SeqWithWeirdLen: |
|
154 called = False |
|
155 def __len__(self): |
|
156 if not self.called: |
|
157 self.called = True |
|
158 return 10 |
|
159 raise ZeroDivisionError |
|
160 def __getitem__(self, index): |
|
161 return index |
|
162 r = reversed(SeqWithWeirdLen()) |
|
163 self.assertRaises(ZeroDivisionError, len, r) |
|
164 |
|
165 |
|
166 def test_gc(self): |
|
167 class Seq: |
|
168 def __len__(self): |
|
169 return 10 |
|
170 def __getitem__(self, index): |
|
171 return index |
|
172 s = Seq() |
|
173 r = reversed(s) |
|
174 s.r = r |
|
175 |
|
176 def test_args(self): |
|
177 self.assertRaises(TypeError, reversed) |
|
178 self.assertRaises(TypeError, reversed, [], 'extra') |
|
179 |
|
180 def test_bug1229429(self): |
|
181 # this bug was never in reversed, it was in |
|
182 # PyObject_CallMethod, and reversed_new calls that sometimes. |
|
183 if not hasattr(sys, "getrefcount"): |
|
184 return |
|
185 def f(): |
|
186 pass |
|
187 r = f.__reversed__ = object() |
|
188 rc = sys.getrefcount(r) |
|
189 for i in range(10): |
|
190 try: |
|
191 reversed(f) |
|
192 except TypeError: |
|
193 pass |
|
194 else: |
|
195 self.fail("non-callable __reversed__ didn't raise!") |
|
196 self.assertEqual(rc, sys.getrefcount(r)) |
|
197 |
|
198 |
|
199 def test_main(verbose=None): |
|
200 testclasses = (EnumerateTestCase, SubclassTestCase, TestEmpty, TestBig, |
|
201 TestReversed) |
|
202 test_support.run_unittest(*testclasses) |
|
203 |
|
204 # verify reference counting |
|
205 import sys |
|
206 if verbose and hasattr(sys, "gettotalrefcount"): |
|
207 counts = [None] * 5 |
|
208 for i in xrange(len(counts)): |
|
209 test_support.run_unittest(*testclasses) |
|
210 counts[i] = sys.gettotalrefcount() |
|
211 print counts |
|
212 |
|
213 if __name__ == "__main__": |
|
214 test_main(verbose=True) |