diff options
author | Mark Dickinson <dickinsm@gmail.com> | 2009-11-15 10:17:48 (GMT) |
---|---|---|
committer | Mark Dickinson <dickinsm@gmail.com> | 2009-11-15 10:17:48 (GMT) |
commit | b6447512ab853a92ff52a19c357fd354800ff638 (patch) | |
tree | 89935ca474c1acd975908e1a204eeb94fa2e7ccc /Lib | |
parent | b58474f8c7d78057debf4d50854faf358b81e5b6 (diff) | |
download | cpython-b6447512ab853a92ff52a19c357fd354800ff638.zip cpython-b6447512ab853a92ff52a19c357fd354800ff638.tar.gz cpython-b6447512ab853a92ff52a19c357fd354800ff638.tar.bz2 |
Merged revisions 76292-76293 via svnmerge from
svn+ssh://pythondev@svn.python.org/python/branches/py3k
........
r76292 | mark.dickinson | 2009-11-15 09:57:26 +0000 (Sun, 15 Nov 2009) | 6 lines
Issue #7298: Fix a variety of problems leading to wrong results with
the fast versions of range.__reversed__ and range iteration. Also
fix wrong results and a refleak for PyLong version of range.__reversed__.
Thanks Eric Smith for reviewing, and for suggesting improved tests.
........
r76293 | mark.dickinson | 2009-11-15 10:04:50 +0000 (Sun, 15 Nov 2009) | 1 line
r76292 commit accidentally committed some extra code; remove it
........
Diffstat (limited to 'Lib')
-rw-r--r-- | Lib/test/test_range.py | 61 |
1 files changed, 61 insertions, 0 deletions
diff --git a/Lib/test/test_range.py b/Lib/test/test_range.py index 24836d0..ba028a6 100644 --- a/Lib/test/test_range.py +++ b/Lib/test/test_range.py @@ -3,12 +3,49 @@ import 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 RangeTest(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.zip_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_range(self): self.assertEqual(list(range(3)), [0, 1, 2]) self.assertEqual(list(range(1, 5)), [1, 2, 3, 4]) @@ -78,6 +115,30 @@ class RangeTest(unittest.TestCase): with self.assertRaises(TypeError): range([], 1, -1) + def test_range_iterators(self): + # exercise 'fast' iterators, that use a rangeiterobject internally. + # 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: + iter1 = range(start, end, step) + iter2 = pyrange(start, end, step) + test_id = "range({}, {}, {})".format(start, end, step) + # check first 100 entries + self.assert_iterators_equal(iter1, iter2, test_id, limit=100) + + iter1 = reversed(range(start, end, step)) + iter2 = pyrange_reversed(start, end, step) + test_id = "reversed(range({}, {}, {}))".format(start, end, step) + self.assert_iterators_equal(iter1, iter2, test_id, limit=100) + def test_main(): test.support.run_unittest(RangeTest) |