test_enumerate.py revision 913835763a4734097423c49e284ce8d4b1093917
1import unittest 2import sys 3 4from test import test_support 5 6class 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 13class 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 26class 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 35class 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 46class 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 56class 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 64class 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', 'a') # wrong type 104 self.assertRaises(TypeError, self.enum, 'abc', 2, 3) # too many arguments 105 106 def test_tuple_reuse(self): 107 # Tests an implementation detail where tuple is reused 108 # whenever nothing else holds a reference to it 109 self.assertEqual(len(set(map(id, list(enumerate(self.seq))))), len(self.seq)) 110 self.assertEqual(len(set(map(id, enumerate(self.seq)))), min(1,len(self.seq))) 111 112class MyEnum(enumerate): 113 pass 114 115class SubclassTestCase(EnumerateTestCase): 116 117 enum = MyEnum 118 119class TestEmpty(EnumerateTestCase): 120 121 seq, res = '', [] 122 123class TestBig(EnumerateTestCase): 124 125 seq = range(10,20000,2) 126 res = zip(range(20000), seq) 127 128class TestReversed(unittest.TestCase): 129 130 def test_simple(self): 131 class A: 132 def __getitem__(self, i): 133 if i < 5: 134 return str(i) 135 raise StopIteration 136 def __len__(self): 137 return 5 138 for data in 'abc', range(5), tuple(enumerate('abc')), A(), xrange(1,17,5): 139 self.assertEqual(list(data)[::-1], list(reversed(data))) 140 self.assertRaises(TypeError, reversed, {}) 141 142 def test_xrange_optimization(self): 143 x = xrange(1) 144 self.assertEqual(type(reversed(x)), type(iter(x))) 145 146 def test_len(self): 147 # This is an implementation detail, not an interface requirement 148 from test.test_iterlen import len 149 for s in ('hello', tuple('hello'), list('hello'), xrange(5)): 150 self.assertEqual(len(reversed(s)), len(s)) 151 r = reversed(s) 152 list(r) 153 self.assertEqual(len(r), 0) 154 class SeqWithWeirdLen: 155 called = False 156 def __len__(self): 157 if not self.called: 158 self.called = True 159 return 10 160 raise ZeroDivisionError 161 def __getitem__(self, index): 162 return index 163 r = reversed(SeqWithWeirdLen()) 164 self.assertRaises(ZeroDivisionError, len, r) 165 166 167 def test_gc(self): 168 class Seq: 169 def __len__(self): 170 return 10 171 def __getitem__(self, index): 172 return index 173 s = Seq() 174 r = reversed(s) 175 s.r = r 176 177 def test_args(self): 178 self.assertRaises(TypeError, reversed) 179 self.assertRaises(TypeError, reversed, [], 'extra') 180 181 def test_bug1229429(self): 182 # this bug was never in reversed, it was in 183 # PyObject_CallMethod, and reversed_new calls that sometimes. 184 if not hasattr(sys, "getrefcount"): 185 return 186 def f(): 187 pass 188 r = f.__reversed__ = object() 189 rc = sys.getrefcount(r) 190 for i in range(10): 191 try: 192 reversed(f) 193 except TypeError: 194 pass 195 else: 196 self.fail("non-callable __reversed__ didn't raise!") 197 self.assertEqual(rc, sys.getrefcount(r)) 198 199 200class TestStart(EnumerateTestCase): 201 202 enum = lambda i: enumerate(i, start=11) 203 seq, res = 'abc', [(1, 'a'), (2, 'b'), (3, 'c')] 204 205 206class TestLongStart(EnumerateTestCase): 207 208 enum = lambda i: enumerate(i, start=sys.maxint+1) 209 seq, res = 'abc', [(sys.maxint+1,'a'), (sys.maxint+2,'b'), 210 (sys.maxint+3,'c')] 211 212 213def test_main(verbose=None): 214 testclasses = (EnumerateTestCase, SubclassTestCase, TestEmpty, TestBig, 215 TestReversed) 216 test_support.run_unittest(*testclasses) 217 218 # verify reference counting 219 import sys 220 if verbose and hasattr(sys, "gettotalrefcount"): 221 counts = [None] * 5 222 for i in xrange(len(counts)): 223 test_support.run_unittest(*testclasses) 224 counts[i] = sys.gettotalrefcount() 225 print counts 226 227if __name__ == "__main__": 228 test_main(verbose=True) 229