blob: 906bfc21a26aede0a6a9d9014e95c385b43c53b2 [file] [log] [blame]
Guido van Rossum7dab2422002-04-26 19:40:56 +00001import unittest
Armin Ronacheraa9a79d2012-10-06 14:03:24 +02002import operator
Michael W. Hudson0edc7a02005-07-12 10:21:19 +00003import sys
Kristján Valur Jónsson31668b82012-04-03 10:49:41 +00004import pickle
Brandt Bucher226a0122020-12-04 19:45:57 -08005import gc
Guido van Rossum7dab2422002-04-26 19:40:56 +00006
Benjamin Petersonee8712c2008-05-20 21:35:26 +00007from test import support
Guido van Rossum7dab2422002-04-26 19:40:56 +00008
Guido van Rossum7dab2422002-04-26 19:40:56 +00009class G:
10 'Sequence using __getitem__'
11 def __init__(self, seqn):
12 self.seqn = seqn
13 def __getitem__(self, i):
14 return self.seqn[i]
15
16class I:
17 'Sequence using iterator protocol'
18 def __init__(self, seqn):
19 self.seqn = seqn
20 self.i = 0
21 def __iter__(self):
22 return self
Georg Brandla18af4e2007-04-21 15:47:16 +000023 def __next__(self):
Guido van Rossum7dab2422002-04-26 19:40:56 +000024 if self.i >= len(self.seqn): raise StopIteration
25 v = self.seqn[self.i]
26 self.i += 1
27 return v
28
29class Ig:
30 'Sequence using iterator protocol defined with a generator'
31 def __init__(self, seqn):
32 self.seqn = seqn
33 self.i = 0
34 def __iter__(self):
35 for val in self.seqn:
36 yield val
37
38class X:
39 'Missing __getitem__ and __iter__'
40 def __init__(self, seqn):
41 self.seqn = seqn
42 self.i = 0
Georg Brandla18af4e2007-04-21 15:47:16 +000043 def __next__(self):
Guido van Rossum7dab2422002-04-26 19:40:56 +000044 if self.i >= len(self.seqn): raise StopIteration
45 v = self.seqn[self.i]
46 self.i += 1
47 return v
48
49class E:
50 'Test propagation of exceptions'
51 def __init__(self, seqn):
52 self.seqn = seqn
53 self.i = 0
54 def __iter__(self):
55 return self
Georg Brandla18af4e2007-04-21 15:47:16 +000056 def __next__(self):
Raymond Hettingerffdb8bb2004-09-27 15:29:05 +000057 3 // 0
Guido van Rossum7dab2422002-04-26 19:40:56 +000058
59class N:
Georg Brandla18af4e2007-04-21 15:47:16 +000060 'Iterator missing __next__()'
Guido van Rossum7dab2422002-04-26 19:40:56 +000061 def __init__(self, seqn):
62 self.seqn = seqn
63 self.i = 0
64 def __iter__(self):
65 return self
66
Kristján Valur Jónsson31668b82012-04-03 10:49:41 +000067class PickleTest:
68 # Helper to check picklability
69 def check_pickle(self, itorg, seq):
Serhiy Storchakabad12572014-12-15 14:03:42 +020070 for proto in range(pickle.HIGHEST_PROTOCOL + 1):
71 d = pickle.dumps(itorg, proto)
72 it = pickle.loads(d)
73 self.assertEqual(type(itorg), type(it))
74 self.assertEqual(list(it), seq)
Kristján Valur Jónsson31668b82012-04-03 10:49:41 +000075
Serhiy Storchakabad12572014-12-15 14:03:42 +020076 it = pickle.loads(d)
77 try:
78 next(it)
79 except StopIteration:
80 self.assertFalse(seq[1:])
81 continue
82 d = pickle.dumps(it, proto)
83 it = pickle.loads(d)
84 self.assertEqual(list(it), seq[1:])
Kristján Valur Jónsson31668b82012-04-03 10:49:41 +000085
86class EnumerateTestCase(unittest.TestCase, PickleTest):
Guido van Rossum7dab2422002-04-26 19:40:56 +000087
88 enum = enumerate
Raymond Hettingere8b0f042003-05-28 14:05:34 +000089 seq, res = 'abc', [(0,'a'), (1,'b'), (2,'c')]
Guido van Rossum7dab2422002-04-26 19:40:56 +000090
91 def test_basicfunction(self):
Raymond Hettingere8b0f042003-05-28 14:05:34 +000092 self.assertEqual(type(self.enum(self.seq)), self.enum)
93 e = self.enum(self.seq)
Guido van Rossum7dab2422002-04-26 19:40:56 +000094 self.assertEqual(iter(e), e)
Raymond Hettingere8b0f042003-05-28 14:05:34 +000095 self.assertEqual(list(self.enum(self.seq)), self.res)
Guido van Rossum7dab2422002-04-26 19:40:56 +000096 self.enum.__doc__
97
Kristján Valur Jónsson31668b82012-04-03 10:49:41 +000098 def test_pickle(self):
99 self.check_pickle(self.enum(self.seq), self.res)
100
Guido van Rossum7dab2422002-04-26 19:40:56 +0000101 def test_getitemseqn(self):
Raymond Hettingere8b0f042003-05-28 14:05:34 +0000102 self.assertEqual(list(self.enum(G(self.seq))), self.res)
Guido van Rossum7dab2422002-04-26 19:40:56 +0000103 e = self.enum(G(''))
Georg Brandla18af4e2007-04-21 15:47:16 +0000104 self.assertRaises(StopIteration, next, e)
Guido van Rossum7dab2422002-04-26 19:40:56 +0000105
106 def test_iteratorseqn(self):
Raymond Hettingere8b0f042003-05-28 14:05:34 +0000107 self.assertEqual(list(self.enum(I(self.seq))), self.res)
Guido van Rossum7dab2422002-04-26 19:40:56 +0000108 e = self.enum(I(''))
Georg Brandla18af4e2007-04-21 15:47:16 +0000109 self.assertRaises(StopIteration, next, e)
Guido van Rossum7dab2422002-04-26 19:40:56 +0000110
111 def test_iteratorgenerator(self):
Raymond Hettingere8b0f042003-05-28 14:05:34 +0000112 self.assertEqual(list(self.enum(Ig(self.seq))), self.res)
Guido van Rossum7dab2422002-04-26 19:40:56 +0000113 e = self.enum(Ig(''))
Georg Brandla18af4e2007-04-21 15:47:16 +0000114 self.assertRaises(StopIteration, next, e)
Guido van Rossum7dab2422002-04-26 19:40:56 +0000115
116 def test_noniterable(self):
Raymond Hettingere8b0f042003-05-28 14:05:34 +0000117 self.assertRaises(TypeError, self.enum, X(self.seq))
Guido van Rossum7dab2422002-04-26 19:40:56 +0000118
119 def test_illformediterable(self):
Thomas Wouters1034dad2006-04-15 09:16:16 +0000120 self.assertRaises(TypeError, self.enum, N(self.seq))
Guido van Rossum7dab2422002-04-26 19:40:56 +0000121
122 def test_exception_propagation(self):
Raymond Hettingere8b0f042003-05-28 14:05:34 +0000123 self.assertRaises(ZeroDivisionError, list, self.enum(E(self.seq)))
124
125 def test_argumentcheck(self):
126 self.assertRaises(TypeError, self.enum) # no arguments
127 self.assertRaises(TypeError, self.enum, 1) # wrong type (not iterable)
Alexandre Vassalottie9f305f2008-05-16 04:39:54 +0000128 self.assertRaises(TypeError, self.enum, 'abc', 'a') # wrong type
129 self.assertRaises(TypeError, self.enum, 'abc', 2, 3) # too many arguments
Raymond Hettingere8b0f042003-05-28 14:05:34 +0000130
Benjamin Peterson4fd283a2010-06-25 23:24:35 +0000131 @support.cpython_only
Raymond Hettingere8b0f042003-05-28 14:05:34 +0000132 def test_tuple_reuse(self):
133 # Tests an implementation detail where tuple is reused
134 # whenever nothing else holds a reference to it
Raymond Hettingera690a992003-11-16 16:17:49 +0000135 self.assertEqual(len(set(map(id, list(enumerate(self.seq))))), len(self.seq))
136 self.assertEqual(len(set(map(id, enumerate(self.seq)))), min(1,len(self.seq)))
Guido van Rossum7dab2422002-04-26 19:40:56 +0000137
Brandt Bucher226a0122020-12-04 19:45:57 -0800138 @support.cpython_only
139 def test_enumerate_result_gc(self):
140 # bpo-42536: enumerate's tuple-reuse speed trick breaks the GC's
141 # assumptions about what can be untracked. Make sure we re-track result
142 # tuples whenever we reuse them.
143 it = self.enum([[]])
144 gc.collect()
145 # That GC collection probably untracked the recycled internal result
146 # tuple, which is initialized to (None, None). Make sure it's re-tracked
147 # when it's mutated and returned from __next__:
148 self.assertTrue(gc.is_tracked(next(it)))
149
Guido van Rossum7dab2422002-04-26 19:40:56 +0000150class MyEnum(enumerate):
151 pass
152
153class SubclassTestCase(EnumerateTestCase):
154
155 enum = MyEnum
156
Raymond Hettingere8b0f042003-05-28 14:05:34 +0000157class TestEmpty(EnumerateTestCase):
158
159 seq, res = '', []
160
161class TestBig(EnumerateTestCase):
162
163 seq = range(10,20000,2)
Guido van Rossum801f0d72006-08-24 19:48:10 +0000164 res = list(zip(range(20000), seq))
Raymond Hettingere8b0f042003-05-28 14:05:34 +0000165
Kristján Valur Jónsson31668b82012-04-03 10:49:41 +0000166class TestReversed(unittest.TestCase, PickleTest):
Raymond Hettinger85c20a42003-11-06 14:06:48 +0000167
168 def test_simple(self):
169 class A:
170 def __getitem__(self, i):
171 if i < 5:
172 return str(i)
173 raise StopIteration
174 def __len__(self):
175 return 5
Rémi Lapeyre6531bf62018-11-06 01:38:54 +0100176 for data in ('abc', range(5), tuple(enumerate('abc')), A(),
177 range(1,17,5), dict.fromkeys('abcde')):
Raymond Hettinger85c20a42003-11-06 14:06:48 +0000178 self.assertEqual(list(data)[::-1], list(reversed(data)))
Alexandre Vassalottibee32532008-05-16 18:15:12 +0000179 # don't allow keyword arguments
180 self.assertRaises(TypeError, reversed, [], a=1)
Raymond Hettinger85c20a42003-11-06 14:06:48 +0000181
Guido van Rossum805365e2007-05-07 22:24:25 +0000182 def test_range_optimization(self):
183 x = range(1)
Raymond Hettinger85c20a42003-11-06 14:06:48 +0000184 self.assertEqual(type(reversed(x)), type(iter(x)))
Raymond Hettingere8b0f042003-05-28 14:05:34 +0000185
Raymond Hettinger029dba52004-02-10 09:33:39 +0000186 def test_len(self):
Guido van Rossum805365e2007-05-07 22:24:25 +0000187 for s in ('hello', tuple('hello'), list('hello'), range(5)):
Armin Ronacheraa9a79d2012-10-06 14:03:24 +0200188 self.assertEqual(operator.length_hint(reversed(s)), len(s))
Raymond Hettingerff5dc0e2004-09-29 11:40:50 +0000189 r = reversed(s)
190 list(r)
Armin Ronacheraa9a79d2012-10-06 14:03:24 +0200191 self.assertEqual(operator.length_hint(r), 0)
Raymond Hettingerff5dc0e2004-09-29 11:40:50 +0000192 class SeqWithWeirdLen:
193 called = False
194 def __len__(self):
195 if not self.called:
196 self.called = True
197 return 10
198 raise ZeroDivisionError
199 def __getitem__(self, index):
200 return index
201 r = reversed(SeqWithWeirdLen())
Armin Ronacheraa9a79d2012-10-06 14:03:24 +0200202 self.assertRaises(ZeroDivisionError, operator.length_hint, r)
Raymond Hettingerff5dc0e2004-09-29 11:40:50 +0000203
204
205 def test_gc(self):
206 class Seq:
207 def __len__(self):
208 return 10
209 def __getitem__(self, index):
210 return index
211 s = Seq()
212 r = reversed(s)
213 s.r = r
214
215 def test_args(self):
216 self.assertRaises(TypeError, reversed)
217 self.assertRaises(TypeError, reversed, [], 'extra')
Raymond Hettinger029dba52004-02-10 09:33:39 +0000218
Serhiy Storchaka43767632013-11-03 21:31:38 +0200219 @unittest.skipUnless(hasattr(sys, 'getrefcount'), 'test needs sys.getrefcount()')
Michael W. Hudson0edc7a02005-07-12 10:21:19 +0000220 def test_bug1229429(self):
221 # this bug was never in reversed, it was in
222 # PyObject_CallMethod, and reversed_new calls that sometimes.
Michael W. Hudson0edc7a02005-07-12 10:21:19 +0000223 def f():
224 pass
225 r = f.__reversed__ = object()
226 rc = sys.getrefcount(r)
227 for i in range(10):
228 try:
229 reversed(f)
230 except TypeError:
231 pass
232 else:
233 self.fail("non-callable __reversed__ didn't raise!")
234 self.assertEqual(rc, sys.getrefcount(r))
Tim Petersf5f32b42005-07-17 23:16:17 +0000235
Mark Dickinsonfb3dc942010-05-25 19:06:24 +0000236 def test_objmethods(self):
237 # Objects must have __len__() and __getitem__() implemented.
238 class NoLen(object):
Guido van Rossum97c1adf2016-08-18 09:22:23 -0700239 def __getitem__(self, i): return 1
Mark Dickinsonfb3dc942010-05-25 19:06:24 +0000240 nl = NoLen()
241 self.assertRaises(TypeError, reversed, nl)
242
243 class NoGetItem(object):
244 def __len__(self): return 2
245 ngi = NoGetItem()
246 self.assertRaises(TypeError, reversed, ngi)
247
Guido van Rossum97c1adf2016-08-18 09:22:23 -0700248 class Blocked(object):
249 def __getitem__(self, i): return 1
250 def __len__(self): return 2
251 __reversed__ = None
252 b = Blocked()
253 self.assertRaises(TypeError, reversed, b)
254
Kristján Valur Jónsson31668b82012-04-03 10:49:41 +0000255 def test_pickle(self):
256 for data in 'abc', range(5), tuple(enumerate('abc')), range(1,17,5):
257 self.check_pickle(reversed(data), list(data)[::-1])
258
Michael W. Hudson0edc7a02005-07-12 10:21:19 +0000259
Benjamin Peterson06507eb2010-05-08 16:51:16 +0000260class EnumerateStartTestCase(EnumerateTestCase):
Alexandre Vassalottie9f305f2008-05-16 04:39:54 +0000261
Benjamin Peterson06507eb2010-05-08 16:51:16 +0000262 def test_basicfunction(self):
263 e = self.enum(self.seq)
264 self.assertEqual(iter(e), e)
265 self.assertEqual(list(self.enum(self.seq)), self.res)
Alexandre Vassalottie9f305f2008-05-16 04:39:54 +0000266
267
Benjamin Peterson06507eb2010-05-08 16:51:16 +0000268class TestStart(EnumerateStartTestCase):
Alexandre Vassalottie9f305f2008-05-16 04:39:54 +0000269
Benjamin Peterson06507eb2010-05-08 16:51:16 +0000270 enum = lambda self, i: enumerate(i, start=11)
271 seq, res = 'abc', [(11, 'a'), (12, 'b'), (13, 'c')]
272
273
274class TestLongStart(EnumerateStartTestCase):
275
276 enum = lambda self, i: enumerate(i, start=sys.maxsize+1)
Alexandre Vassalottie9f305f2008-05-16 04:39:54 +0000277 seq, res = 'abc', [(sys.maxsize+1,'a'), (sys.maxsize+2,'b'),
278 (sys.maxsize+3,'c')]
279
280
Guido van Rossum7dab2422002-04-26 19:40:56 +0000281if __name__ == "__main__":
Zachary Ware38c707e2015-04-13 15:00:43 -0500282 unittest.main()