1# Python test set -- built-in functions
2
3import unittest
4import sys
5import pickle
6import itertools
7
8# pure Python implementations (3 args only), for comparison
9def pyrange(start, stop, step):
10    if (start - stop) // step < 0:
11        # replace stop with next element in the sequence of integers
12        # that are congruent to start modulo step.
13        stop += (start - stop) % step
14        while start != stop:
15            yield start
16            start += step
17
18def pyrange_reversed(start, stop, step):
19    stop += (start - stop) % step
20    return pyrange(stop - step, start - step, -step)
21
22
23class RangeTest(unittest.TestCase):
24    def assert_iterators_equal(self, xs, ys, test_id, limit=None):
25        # check that an iterator xs matches the expected results ys,
26        # up to a given limit.
27        if limit is not None:
28            xs = itertools.islice(xs, limit)
29            ys = itertools.islice(ys, limit)
30        sentinel = object()
31        pairs = itertools.zip_longest(xs, ys, fillvalue=sentinel)
32        for i, (x, y) in enumerate(pairs):
33            if x == y:
34                continue
35            elif x == sentinel:
36                self.fail('{}: iterator ended unexpectedly '
37                          'at position {}; expected {}'.format(test_id, i, y))
38            elif y == sentinel:
39                self.fail('{}: unexpected excess element {} at '
40                          'position {}'.format(test_id, x, i))
41            else:
42                self.fail('{}: wrong element at position {}; '
43                          'expected {}, got {}'.format(test_id, i, y, x))
44
45    def test_range(self):
46        self.assertEqual(list(range(3)), [0, 1, 2])
47        self.assertEqual(list(range(1, 5)), [1, 2, 3, 4])
48        self.assertEqual(list(range(0)), [])
49        self.assertEqual(list(range(-3)), [])
50        self.assertEqual(list(range(1, 10, 3)), [1, 4, 7])
51        self.assertEqual(list(range(5, -5, -3)), [5, 2, -1, -4])
52
53        a = 10
54        b = 100
55        c = 50
56
57        self.assertEqual(list(range(a, a+2)), [a, a+1])
58        self.assertEqual(list(range(a+2, a, -1)), [a+2, a+1])
59        self.assertEqual(list(range(a+4, a, -2)), [a+4, a+2])
60
61        seq = list(range(a, b, c))
62        self.assertIn(a, seq)
63        self.assertNotIn(b, seq)
64        self.assertEqual(len(seq), 2)
65
66        seq = list(range(b, a, -c))
67        self.assertIn(b, seq)
68        self.assertNotIn(a, seq)
69        self.assertEqual(len(seq), 2)
70
71        seq = list(range(-a, -b, -c))
72        self.assertIn(-a, seq)
73        self.assertNotIn(-b, seq)
74        self.assertEqual(len(seq), 2)
75
76        self.assertRaises(TypeError, range)
77        self.assertRaises(TypeError, range, 1, 2, 3, 4)
78        self.assertRaises(ValueError, range, 1, 2, 0)
79
80        self.assertRaises(TypeError, range, 0.0, 2, 1)
81        self.assertRaises(TypeError, range, 1, 2.0, 1)
82        self.assertRaises(TypeError, range, 1, 2, 1.0)
83        self.assertRaises(TypeError, range, 1e100, 1e101, 1e101)
84
85        self.assertRaises(TypeError, range, 0, "spam")
86        self.assertRaises(TypeError, range, 0, 42, "spam")
87
88        self.assertEqual(len(range(0, sys.maxsize, sys.maxsize-1)), 2)
89
90        r = range(-sys.maxsize, sys.maxsize, 2)
91        self.assertEqual(len(r), sys.maxsize)
92
93    def test_large_operands(self):
94        x = range(10**20, 10**20+10, 3)
95        self.assertEqual(len(x), 4)
96        self.assertEqual(len(list(x)), 4)
97
98        x = range(10**20+10, 10**20, 3)
99        self.assertEqual(len(x), 0)
100        self.assertEqual(len(list(x)), 0)
101        self.assertFalse(x)
102
103        x = range(10**20, 10**20+10, -3)
104        self.assertEqual(len(x), 0)
105        self.assertEqual(len(list(x)), 0)
106        self.assertFalse(x)
107
108        x = range(10**20+10, 10**20, -3)
109        self.assertEqual(len(x), 4)
110        self.assertEqual(len(list(x)), 4)
111        self.assertTrue(x)
112
113        # Now test range() with longs
114        for x in [range(-2**100),
115                  range(0, -2**100),
116                  range(0, 2**100, -1)]:
117            self.assertEqual(list(x), [])
118            self.assertFalse(x)
119
120        a = int(10 * sys.maxsize)
121        b = int(100 * sys.maxsize)
122        c = int(50 * sys.maxsize)
123
124        self.assertEqual(list(range(a, a+2)), [a, a+1])
125        self.assertEqual(list(range(a+2, a, -1)), [a+2, a+1])
126        self.assertEqual(list(range(a+4, a, -2)), [a+4, a+2])
127
128        seq = list(range(a, b, c))
129        self.assertIn(a, seq)
130        self.assertNotIn(b, seq)
131        self.assertEqual(len(seq), 2)
132        self.assertEqual(seq[0], a)
133        self.assertEqual(seq[-1], a+c)
134
135        seq = list(range(b, a, -c))
136        self.assertIn(b, seq)
137        self.assertNotIn(a, seq)
138        self.assertEqual(len(seq), 2)
139        self.assertEqual(seq[0], b)
140        self.assertEqual(seq[-1], b-c)
141
142        seq = list(range(-a, -b, -c))
143        self.assertIn(-a, seq)
144        self.assertNotIn(-b, seq)
145        self.assertEqual(len(seq), 2)
146        self.assertEqual(seq[0], -a)
147        self.assertEqual(seq[-1], -a-c)
148
149    def test_large_range(self):
150        # Check long ranges (len > sys.maxsize)
151        # len() is expected to fail due to limitations of the __len__ protocol
152        def _range_len(x):
153            try:
154                length = len(x)
155            except OverflowError:
156                step = x[1] - x[0]
157                length = 1 + ((x[-1] - x[0]) // step)
158            return length
159
160        a = -sys.maxsize
161        b = sys.maxsize
162        expected_len = b - a
163        x = range(a, b)
164        self.assertIn(a, x)
165        self.assertNotIn(b, x)
166        self.assertRaises(OverflowError, len, x)
167        self.assertTrue(x)
168        self.assertEqual(_range_len(x), expected_len)
169        self.assertEqual(x[0], a)
170        idx = sys.maxsize+1
171        self.assertEqual(x[idx], a+idx)
172        self.assertEqual(x[idx:idx+1][0], a+idx)
173        with self.assertRaises(IndexError):
174            x[-expected_len-1]
175        with self.assertRaises(IndexError):
176            x[expected_len]
177
178        a = 0
179        b = 2 * sys.maxsize
180        expected_len = b - a
181        x = range(a, b)
182        self.assertIn(a, x)
183        self.assertNotIn(b, x)
184        self.assertRaises(OverflowError, len, x)
185        self.assertTrue(x)
186        self.assertEqual(_range_len(x), expected_len)
187        self.assertEqual(x[0], a)
188        idx = sys.maxsize+1
189        self.assertEqual(x[idx], a+idx)
190        self.assertEqual(x[idx:idx+1][0], a+idx)
191        with self.assertRaises(IndexError):
192            x[-expected_len-1]
193        with self.assertRaises(IndexError):
194            x[expected_len]
195
196        a = 0
197        b = sys.maxsize**10
198        c = 2*sys.maxsize
199        expected_len = 1 + (b - a) // c
200        x = range(a, b, c)
201        self.assertIn(a, x)
202        self.assertNotIn(b, x)
203        self.assertRaises(OverflowError, len, x)
204        self.assertTrue(x)
205        self.assertEqual(_range_len(x), expected_len)
206        self.assertEqual(x[0], a)
207        idx = sys.maxsize+1
208        self.assertEqual(x[idx], a+(idx*c))
209        self.assertEqual(x[idx:idx+1][0], a+(idx*c))
210        with self.assertRaises(IndexError):
211            x[-expected_len-1]
212        with self.assertRaises(IndexError):
213            x[expected_len]
214
215        a = sys.maxsize**10
216        b = 0
217        c = -2*sys.maxsize
218        expected_len = 1 + (b - a) // c
219        x = range(a, b, c)
220        self.assertIn(a, x)
221        self.assertNotIn(b, x)
222        self.assertRaises(OverflowError, len, x)
223        self.assertTrue(x)
224        self.assertEqual(_range_len(x), expected_len)
225        self.assertEqual(x[0], a)
226        idx = sys.maxsize+1
227        self.assertEqual(x[idx], a+(idx*c))
228        self.assertEqual(x[idx:idx+1][0], a+(idx*c))
229        with self.assertRaises(IndexError):
230            x[-expected_len-1]
231        with self.assertRaises(IndexError):
232            x[expected_len]
233
234    def test_invalid_invocation(self):
235        self.assertRaises(TypeError, range)
236        self.assertRaises(TypeError, range, 1, 2, 3, 4)
237        self.assertRaises(ValueError, range, 1, 2, 0)
238        a = int(10 * sys.maxsize)
239        self.assertRaises(ValueError, range, a, a + 1, int(0))
240        self.assertRaises(TypeError, range, 1., 1., 1.)
241        self.assertRaises(TypeError, range, 1e100, 1e101, 1e101)
242        self.assertRaises(TypeError, range, 0, "spam")
243        self.assertRaises(TypeError, range, 0, 42, "spam")
244        # Exercise various combinations of bad arguments, to check
245        # refcounting logic
246        self.assertRaises(TypeError, range, 0.0)
247        self.assertRaises(TypeError, range, 0, 0.0)
248        self.assertRaises(TypeError, range, 0.0, 0)
249        self.assertRaises(TypeError, range, 0.0, 0.0)
250        self.assertRaises(TypeError, range, 0, 0, 1.0)
251        self.assertRaises(TypeError, range, 0, 0.0, 1)
252        self.assertRaises(TypeError, range, 0, 0.0, 1.0)
253        self.assertRaises(TypeError, range, 0.0, 0, 1)
254        self.assertRaises(TypeError, range, 0.0, 0, 1.0)
255        self.assertRaises(TypeError, range, 0.0, 0.0, 1)
256        self.assertRaises(TypeError, range, 0.0, 0.0, 1.0)
257
258    def test_index(self):
259        u = range(2)
260        self.assertEqual(u.index(0), 0)
261        self.assertEqual(u.index(1), 1)
262        self.assertRaises(ValueError, u.index, 2)
263
264        u = range(-2, 3)
265        self.assertEqual(u.count(0), 1)
266        self.assertEqual(u.index(0), 2)
267        self.assertRaises(TypeError, u.index)
268
269        class BadExc(Exception):
270            pass
271
272        class BadCmp:
273            def __eq__(self, other):
274                if other == 2:
275                    raise BadExc()
276                return False
277
278        a = range(4)
279        self.assertRaises(BadExc, a.index, BadCmp())
280
281        a = range(-2, 3)
282        self.assertEqual(a.index(0), 2)
283        self.assertEqual(range(1, 10, 3).index(4), 1)
284        self.assertEqual(range(1, -10, -3).index(-5), 2)
285
286        self.assertEqual(range(10**20).index(1), 1)
287        self.assertEqual(range(10**20).index(10**20 - 1), 10**20 - 1)
288
289        self.assertRaises(ValueError, range(1, 2**100, 2).index, 2**87)
290        self.assertEqual(range(1, 2**100, 2).index(2**87+1), 2**86)
291
292        class AlwaysEqual(object):
293            def __eq__(self, other):
294                return True
295        always_equal = AlwaysEqual()
296        self.assertEqual(range(10).index(always_equal), 0)
297
298    def test_user_index_method(self):
299        bignum = 2*sys.maxsize
300        smallnum = 42
301
302        # User-defined class with an __index__ method
303        class I:
304            def __init__(self, n):
305                self.n = int(n)
306            def __index__(self):
307                return self.n
308        self.assertEqual(list(range(I(bignum), I(bignum + 1))), [bignum])
309        self.assertEqual(list(range(I(smallnum), I(smallnum + 1))), [smallnum])
310
311        # User-defined class with a failing __index__ method
312        class IX:
313            def __index__(self):
314                raise RuntimeError
315        self.assertRaises(RuntimeError, range, IX())
316
317        # User-defined class with an invalid __index__ method
318        class IN:
319            def __index__(self):
320                return "not a number"
321
322        self.assertRaises(TypeError, range, IN())
323
324        # Test use of user-defined classes in slice indices.
325        self.assertEqual(range(10)[:I(5)], range(5))
326
327        with self.assertRaises(RuntimeError):
328            range(0, 10)[:IX()]
329
330        with self.assertRaises(TypeError):
331            range(0, 10)[:IN()]
332
333    def test_count(self):
334        self.assertEqual(range(3).count(-1), 0)
335        self.assertEqual(range(3).count(0), 1)
336        self.assertEqual(range(3).count(1), 1)
337        self.assertEqual(range(3).count(2), 1)
338        self.assertEqual(range(3).count(3), 0)
339        self.assertIs(type(range(3).count(-1)), int)
340        self.assertIs(type(range(3).count(1)), int)
341        self.assertEqual(range(10**20).count(1), 1)
342        self.assertEqual(range(10**20).count(10**20), 0)
343        self.assertEqual(range(3).index(1), 1)
344        self.assertEqual(range(1, 2**100, 2).count(2**87), 0)
345        self.assertEqual(range(1, 2**100, 2).count(2**87+1), 1)
346
347        class AlwaysEqual(object):
348            def __eq__(self, other):
349                return True
350        always_equal = AlwaysEqual()
351        self.assertEqual(range(10).count(always_equal), 10)
352
353        self.assertEqual(len(range(sys.maxsize, sys.maxsize+10)), 10)
354
355    def test_repr(self):
356        self.assertEqual(repr(range(1)), 'range(0, 1)')
357        self.assertEqual(repr(range(1, 2)), 'range(1, 2)')
358        self.assertEqual(repr(range(1, 2, 3)), 'range(1, 2, 3)')
359
360    def test_pickling(self):
361        testcases = [(13,), (0, 11), (-22, 10), (20, 3, -1),
362                     (13, 21, 3), (-2, 2, 2), (2**65, 2**65+2)]
363        for proto in range(pickle.HIGHEST_PROTOCOL + 1):
364            for t in testcases:
365                with self.subTest(proto=proto, test=t):
366                    r = range(*t)
367                    self.assertEqual(list(pickle.loads(pickle.dumps(r, proto))),
368                                     list(r))
369
370    def test_iterator_pickling(self):
371        testcases = [(13,), (0, 11), (-22, 10), (20, 3, -1),
372                     (13, 21, 3), (-2, 2, 2), (2**65, 2**65+2)]
373        for proto in range(pickle.HIGHEST_PROTOCOL + 1):
374            for t in testcases:
375                it = itorg = iter(range(*t))
376                data = list(range(*t))
377
378                d = pickle.dumps(it, proto)
379                it = pickle.loads(d)
380                self.assertEqual(type(itorg), type(it))
381                self.assertEqual(list(it), data)
382
383                it = pickle.loads(d)
384                try:
385                    next(it)
386                except StopIteration:
387                    continue
388                d = pickle.dumps(it, proto)
389                it = pickle.loads(d)
390                self.assertEqual(list(it), data[1:])
391
392    def test_exhausted_iterator_pickling(self):
393        for proto in range(pickle.HIGHEST_PROTOCOL + 1):
394            r = range(2**65, 2**65+2)
395            i = iter(r)
396            while True:
397                r = next(i)
398                if r == 2**65+1:
399                    break
400            d = pickle.dumps(i, proto)
401            i2 = pickle.loads(d)
402            self.assertEqual(list(i), [])
403            self.assertEqual(list(i2), [])
404
405    def test_large_exhausted_iterator_pickling(self):
406        for proto in range(pickle.HIGHEST_PROTOCOL + 1):
407            r = range(20)
408            i = iter(r)
409            while True:
410                r = next(i)
411                if r == 19:
412                    break
413            d = pickle.dumps(i, proto)
414            i2 = pickle.loads(d)
415            self.assertEqual(list(i), [])
416            self.assertEqual(list(i2), [])
417
418    def test_odd_bug(self):
419        # This used to raise a "SystemError: NULL result without error"
420        # because the range validation step was eating the exception
421        # before NULL was returned.
422        with self.assertRaises(TypeError):
423            range([], 1, -1)
424
425    def test_types(self):
426        # Non-integer objects *equal* to any of the range's items are supposed
427        # to be contained in the range.
428        self.assertIn(1.0, range(3))
429        self.assertIn(True, range(3))
430        self.assertIn(1+0j, range(3))
431
432        class C1:
433            def __eq__(self, other): return True
434        self.assertIn(C1(), range(3))
435
436        # Objects are never coerced into other types for comparison.
437        class C2:
438            def __int__(self): return 1
439            def __index__(self): return 1
440        self.assertNotIn(C2(), range(3))
441        # ..except if explicitly told so.
442        self.assertIn(int(C2()), range(3))
443
444        # Check that the range.__contains__ optimization is only
445        # used for ints, not for instances of subclasses of int.
446        class C3(int):
447            def __eq__(self, other): return True
448        self.assertIn(C3(11), range(10))
449        self.assertIn(C3(11), list(range(10)))
450
451    def test_strided_limits(self):
452        r = range(0, 101, 2)
453        self.assertIn(0, r)
454        self.assertNotIn(1, r)
455        self.assertIn(2, r)
456        self.assertNotIn(99, r)
457        self.assertIn(100, r)
458        self.assertNotIn(101, r)
459
460        r = range(0, -20, -1)
461        self.assertIn(0, r)
462        self.assertIn(-1, r)
463        self.assertIn(-19, r)
464        self.assertNotIn(-20, r)
465
466        r = range(0, -20, -2)
467        self.assertIn(-18, r)
468        self.assertNotIn(-19, r)
469        self.assertNotIn(-20, r)
470
471    def test_empty(self):
472        r = range(0)
473        self.assertNotIn(0, r)
474        self.assertNotIn(1, r)
475
476        r = range(0, -10)
477        self.assertNotIn(0, r)
478        self.assertNotIn(-1, r)
479        self.assertNotIn(1, r)
480
481    def test_range_iterators(self):
482        # exercise 'fast' iterators, that use a rangeiterobject internally.
483        # see issue 7298
484        limits = [base + jiggle
485                  for M in (2**32, 2**64)
486                  for base in (-M, -M//2, 0, M//2, M)
487                  for jiggle in (-2, -1, 0, 1, 2)]
488        test_ranges = [(start, end, step)
489                       for start in limits
490                       for end in limits
491                       for step in (-2**63, -2**31, -2, -1, 1, 2)]
492
493        for start, end, step in test_ranges:
494            iter1 = range(start, end, step)
495            iter2 = pyrange(start, end, step)
496            test_id = "range({}, {}, {})".format(start, end, step)
497            # check first 100 entries
498            self.assert_iterators_equal(iter1, iter2, test_id, limit=100)
499
500            iter1 = reversed(range(start, end, step))
501            iter2 = pyrange_reversed(start, end, step)
502            test_id = "reversed(range({}, {}, {}))".format(start, end, step)
503            self.assert_iterators_equal(iter1, iter2, test_id, limit=100)
504
505    def test_range_iterators_invocation(self):
506        # verify range iterators instances cannot be created by
507        # calling their type
508        rangeiter_type = type(iter(range(0)))
509        self.assertRaises(TypeError, rangeiter_type, 1, 3, 1)
510        long_rangeiter_type = type(iter(range(1 << 1000)))
511        self.assertRaises(TypeError, long_rangeiter_type, 1, 3, 1)
512
513    def test_slice(self):
514        def check(start, stop, step=None):
515            i = slice(start, stop, step)
516            self.assertEqual(list(r[i]), list(r)[i])
517            self.assertEqual(len(r[i]), len(list(r)[i]))
518        for r in [range(10),
519                  range(0),
520                  range(1, 9, 3),
521                  range(8, 0, -3),
522                  range(sys.maxsize+1, sys.maxsize+10),
523                  ]:
524            check(0, 2)
525            check(0, 20)
526            check(1, 2)
527            check(20, 30)
528            check(-30, -20)
529            check(-1, 100, 2)
530            check(0, -1)
531            check(-1, -3, -1)
532
533    def test_contains(self):
534        r = range(10)
535        self.assertIn(0, r)
536        self.assertIn(1, r)
537        self.assertIn(5.0, r)
538        self.assertNotIn(5.1, r)
539        self.assertNotIn(-1, r)
540        self.assertNotIn(10, r)
541        self.assertNotIn("", r)
542        r = range(9, -1, -1)
543        self.assertIn(0, r)
544        self.assertIn(1, r)
545        self.assertIn(5.0, r)
546        self.assertNotIn(5.1, r)
547        self.assertNotIn(-1, r)
548        self.assertNotIn(10, r)
549        self.assertNotIn("", r)
550        r = range(0, 10, 2)
551        self.assertIn(0, r)
552        self.assertNotIn(1, r)
553        self.assertNotIn(5.0, r)
554        self.assertNotIn(5.1, r)
555        self.assertNotIn(-1, r)
556        self.assertNotIn(10, r)
557        self.assertNotIn("", r)
558        r = range(9, -1, -2)
559        self.assertNotIn(0, r)
560        self.assertIn(1, r)
561        self.assertIn(5.0, r)
562        self.assertNotIn(5.1, r)
563        self.assertNotIn(-1, r)
564        self.assertNotIn(10, r)
565        self.assertNotIn("", r)
566
567    def test_reverse_iteration(self):
568        for r in [range(10),
569                  range(0),
570                  range(1, 9, 3),
571                  range(8, 0, -3),
572                  range(sys.maxsize+1, sys.maxsize+10),
573                  ]:
574            self.assertEqual(list(reversed(r)), list(r)[::-1])
575
576    def test_issue11845(self):
577        r = range(*slice(1, 18, 2).indices(20))
578        values = {None, 0, 1, -1, 2, -2, 5, -5, 19, -19,
579                  20, -20, 21, -21, 30, -30, 99, -99}
580        for i in values:
581            for j in values:
582                for k in values - {0}:
583                    r[i:j:k]
584
585    def test_comparison(self):
586        test_ranges = [range(0), range(0, -1), range(1, 1, 3),
587                       range(1), range(5, 6), range(5, 6, 2),
588                       range(5, 7, 2), range(2), range(0, 4, 2),
589                       range(0, 5, 2), range(0, 6, 2)]
590        test_tuples = list(map(tuple, test_ranges))
591
592        # Check that equality of ranges matches equality of the corresponding
593        # tuples for each pair from the test lists above.
594        ranges_eq = [a == b for a in test_ranges for b in test_ranges]
595        tuples_eq = [a == b for a in test_tuples for b in test_tuples]
596        self.assertEqual(ranges_eq, tuples_eq)
597
598        # Check that != correctly gives the logical negation of ==
599        ranges_ne = [a != b for a in test_ranges for b in test_ranges]
600        self.assertEqual(ranges_ne, [not x for x in ranges_eq])
601
602        # Equal ranges should have equal hashes.
603        for a in test_ranges:
604            for b in test_ranges:
605                if a == b:
606                    self.assertEqual(hash(a), hash(b))
607
608        # Ranges are unequal to other types (even sequence types)
609        self.assertIs(range(0) == (), False)
610        self.assertIs(() == range(0), False)
611        self.assertIs(range(2) == [0, 1], False)
612
613        # Huge integers aren't a problem.
614        self.assertEqual(range(0, 2**100 - 1, 2),
615                         range(0, 2**100, 2))
616        self.assertEqual(hash(range(0, 2**100 - 1, 2)),
617                         hash(range(0, 2**100, 2)))
618        self.assertNotEqual(range(0, 2**100, 2),
619                            range(0, 2**100 + 1, 2))
620        self.assertEqual(range(2**200, 2**201 - 2**99, 2**100),
621                         range(2**200, 2**201, 2**100))
622        self.assertEqual(hash(range(2**200, 2**201 - 2**99, 2**100)),
623                         hash(range(2**200, 2**201, 2**100)))
624        self.assertNotEqual(range(2**200, 2**201, 2**100),
625                            range(2**200, 2**201 + 1, 2**100))
626
627        # Order comparisons are not implemented for ranges.
628        with self.assertRaises(TypeError):
629            range(0) < range(0)
630        with self.assertRaises(TypeError):
631            range(0) > range(0)
632        with self.assertRaises(TypeError):
633            range(0) <= range(0)
634        with self.assertRaises(TypeError):
635            range(0) >= range(0)
636
637
638    def test_attributes(self):
639        # test the start, stop and step attributes of range objects
640        self.assert_attrs(range(0), 0, 0, 1)
641        self.assert_attrs(range(10), 0, 10, 1)
642        self.assert_attrs(range(-10), 0, -10, 1)
643        self.assert_attrs(range(0, 10, 1), 0, 10, 1)
644        self.assert_attrs(range(0, 10, 3), 0, 10, 3)
645        self.assert_attrs(range(10, 0, -1), 10, 0, -1)
646        self.assert_attrs(range(10, 0, -3), 10, 0, -3)
647
648    def assert_attrs(self, rangeobj, start, stop, step):
649        self.assertEqual(rangeobj.start, start)
650        self.assertEqual(rangeobj.stop, stop)
651        self.assertEqual(rangeobj.step, step)
652
653        with self.assertRaises(AttributeError):
654            rangeobj.start = 0
655        with self.assertRaises(AttributeError):
656            rangeobj.stop = 10
657        with self.assertRaises(AttributeError):
658            rangeobj.step = 1
659
660        with self.assertRaises(AttributeError):
661            del rangeobj.start
662        with self.assertRaises(AttributeError):
663            del rangeobj.stop
664        with self.assertRaises(AttributeError):
665            del rangeobj.step
666
667if __name__ == "__main__":
668    unittest.main()
669