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