PageRenderTime 14ms CodeModel.GetById 1ms app.highlight 10ms RepoModel.GetById 1ms app.codeStats 0ms

/Lib/test/test_enumerate.py

http://unladen-swallow.googlecode.com/
Python | 230 lines | 199 code | 27 blank | 4 comment | 17 complexity | 6844d8c0a91e51cc5888b69206d49343 MD5 | raw file
  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        # don't allow keyword arguments
142        self.assertRaises(TypeError, reversed, [], a=1)
143
144    def test_xrange_optimization(self):
145        x = xrange(1)
146        self.assertEqual(type(reversed(x)), type(iter(x)))
147
148    def test_len(self):
149        # This is an implementation detail, not an interface requirement
150        from test.test_iterlen import len
151        for s in ('hello', tuple('hello'), list('hello'), xrange(5)):
152            self.assertEqual(len(reversed(s)), len(s))
153            r = reversed(s)
154            list(r)
155            self.assertEqual(len(r), 0)
156        class SeqWithWeirdLen:
157            called = False
158            def __len__(self):
159                if not self.called:
160                    self.called = True
161                    return 10
162                raise ZeroDivisionError
163            def __getitem__(self, index):
164                return index
165        r = reversed(SeqWithWeirdLen())
166        self.assertRaises(ZeroDivisionError, len, r)
167
168
169    def test_gc(self):
170        class Seq:
171            def __len__(self):
172                return 10
173            def __getitem__(self, index):
174                return index
175        s = Seq()
176        r = reversed(s)
177        s.r = r
178
179    def test_args(self):
180        self.assertRaises(TypeError, reversed)
181        self.assertRaises(TypeError, reversed, [], 'extra')
182
183    def test_bug1229429(self):
184        # this bug was never in reversed, it was in
185        # PyObject_CallMethod, and reversed_new calls that sometimes.
186        if not hasattr(sys, "getrefcount"):
187            return
188        def f():
189            pass
190        r = f.__reversed__ = object()
191        rc = sys.getrefcount(r)
192        for i in range(10):
193            try:
194                reversed(f)
195            except TypeError:
196                pass
197            else:
198                self.fail("non-callable __reversed__ didn't raise!")
199        self.assertEqual(rc, sys.getrefcount(r))
200
201
202class TestStart(EnumerateTestCase):
203
204    enum = lambda i: enumerate(i, start=11)
205    seq, res = 'abc', [(1, 'a'), (2, 'b'), (3, 'c')]
206
207
208class TestLongStart(EnumerateTestCase):
209
210    enum = lambda i: enumerate(i, start=sys.maxint+1)
211    seq, res = 'abc', [(sys.maxint+1,'a'), (sys.maxint+2,'b'),
212                       (sys.maxint+3,'c')]
213
214
215def test_main(verbose=None):
216    testclasses = (EnumerateTestCase, SubclassTestCase, TestEmpty, TestBig,
217                   TestReversed)
218    test_support.run_unittest(*testclasses)
219
220    # verify reference counting
221    import sys
222    if verbose and hasattr(sys, "gettotalrefcount"):
223        counts = [None] * 5
224        for i in xrange(len(counts)):
225            test_support.run_unittest(*testclasses)
226            counts[i] = sys.gettotalrefcount()
227        print counts
228
229if __name__ == "__main__":
230    test_main(verbose=True)