diff options
author | Mark Dickinson <dickinsm@gmail.com> | 2009-11-15 12:31:13 (GMT) |
---|---|---|
committer | Mark Dickinson <dickinsm@gmail.com> | 2009-11-15 12:31:13 (GMT) |
commit | 009ae861f2a3ffcc3d6586fb1bcfdbd99547855a (patch) | |
tree | f45f81d60dfa73539102e5ee5a14225dddbe8398 /Lib/test/test_xrange.py | |
parent | 20eb4f078237e8bc7a5ac970714cee4d8feb7a09 (diff) | |
download | cpython-009ae861f2a3ffcc3d6586fb1bcfdbd99547855a.zip cpython-009ae861f2a3ffcc3d6586fb1bcfdbd99547855a.tar.gz cpython-009ae861f2a3ffcc3d6586fb1bcfdbd99547855a.tar.bz2 |
Avoid signed overflow in some xrange calculations, and extend
xrange tests to cover some special cases that caused problems
in py3k. This is a partial backport of r76292-76293 (see
issue #7298.)
Diffstat (limited to 'Lib/test/test_xrange.py')
-rw-r--r-- | Lib/test/test_xrange.py | 68 |
1 files changed, 68 insertions, 0 deletions
diff --git a/Lib/test/test_xrange.py b/Lib/test/test_xrange.py index a0b94fa..8e65477 100644 --- a/Lib/test/test_xrange.py +++ b/Lib/test/test_xrange.py @@ -3,12 +3,49 @@ import test.test_support, unittest import sys import pickle +import itertools import warnings warnings.filterwarnings("ignore", "integer argument expected", DeprecationWarning, "unittest") +# pure Python implementations (3 args only), for comparison +def pyrange(start, stop, step): + if (start - stop) // step < 0: + # replace stop with next element in the sequence of integers + # that are congruent to start modulo step. + stop += (start - stop) % step + while start != stop: + yield start + start += step + +def pyrange_reversed(start, stop, step): + stop += (start - stop) % step + return pyrange(stop - step, start - step, -step) + + class XrangeTest(unittest.TestCase): + def assert_iterators_equal(self, xs, ys, test_id, limit=None): + # check that an iterator xs matches the expected results ys, + # up to a given limit. + if limit is not None: + xs = itertools.islice(xs, limit) + ys = itertools.islice(ys, limit) + sentinel = object() + pairs = itertools.izip_longest(xs, ys, fillvalue=sentinel) + for i, (x, y) in enumerate(pairs): + if x == y: + continue + elif x == sentinel: + self.fail('{}: iterator ended unexpectedly ' + 'at position {}; expected {}'.format(test_id, i, y)) + elif y == sentinel: + self.fail('{}: unexpected excess element {} at ' + 'position {}'.format(test_id, x, i)) + else: + self.fail('{}: wrong element at position {};' + 'expected {}, got {}'.format(test_id, i, y, x)) + def test_xrange(self): self.assertEqual(list(xrange(3)), [0, 1, 2]) self.assertEqual(list(xrange(1, 5)), [1, 2, 3, 4]) @@ -67,6 +104,37 @@ class XrangeTest(unittest.TestCase): self.assertEquals(list(pickle.loads(pickle.dumps(r, proto))), list(r)) + def test_range_iterators(self): + # see issue 7298 + limits = [base + jiggle + for M in (2**32, 2**64) + for base in (-M, -M//2, 0, M//2, M) + for jiggle in (-2, -1, 0, 1, 2)] + test_ranges = [(start, end, step) + for start in limits + for end in limits + for step in (-2**63, -2**31, -2, -1, 1, 2)] + + for start, end, step in test_ranges: + try: + iter1 = xrange(start, end, step) + except OverflowError: + pass + else: + iter2 = pyrange(start, end, step) + test_id = "xrange({}, {}, {})".format(start, end, step) + # check first 100 entries + self.assert_iterators_equal(iter1, iter2, test_id, limit=100) + + try: + iter1 = reversed(xrange(start, end, step)) + except OverflowError: + pass + else: + iter2 = pyrange_reversed(start, end, step) + test_id = "reversed(xrange({}, {}, {}))".format(start, end, step) + self.assert_iterators_equal(iter1, iter2, test_id, limit=100) + def test_main(): test.test_support.run_unittest(XrangeTest) |