summaryrefslogtreecommitdiffstats
path: root/Lib
diff options
context:
space:
mode:
authorMark Dickinson <dickinsm@gmail.com>2009-11-15 10:17:48 (GMT)
committerMark Dickinson <dickinsm@gmail.com>2009-11-15 10:17:48 (GMT)
commitb6447512ab853a92ff52a19c357fd354800ff638 (patch)
tree89935ca474c1acd975908e1a204eeb94fa2e7ccc /Lib
parentb58474f8c7d78057debf4d50854faf358b81e5b6 (diff)
downloadcpython-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.py61
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)