summaryrefslogtreecommitdiffstats
path: root/Lib/test/test_xrange.py
diff options
context:
space:
mode:
authorMark Dickinson <dickinsm@gmail.com>2009-11-15 12:34:12 (GMT)
committerMark Dickinson <dickinsm@gmail.com>2009-11-15 12:34:12 (GMT)
commitcc83afd803478ee234df97054bd2d182432c1297 (patch)
tree229ecdcb3d988571dda2d8c6b81f2df5e1776e7a /Lib/test/test_xrange.py
parent10c858ac4d80ef4b50a96ae57c128178d5ecfa05 (diff)
downloadcpython-cc83afd803478ee234df97054bd2d182432c1297.zip
cpython-cc83afd803478ee234df97054bd2d182432c1297.tar.gz
cpython-cc83afd803478ee234df97054bd2d182432c1297.tar.bz2
Merged revisions 76295 via svnmerge from
svn+ssh://pythondev@svn.python.org/python/trunk ........ r76295 | mark.dickinson | 2009-11-15 12:31:13 +0000 (Sun, 15 Nov 2009) | 5 lines 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.py69
1 files changed, 69 insertions, 0 deletions
diff --git a/Lib/test/test_xrange.py b/Lib/test/test_xrange.py
index 7e2a1a3..dbfeb43 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('{0}: iterator ended unexpectedly '
+ 'at position {1}; expected {2}'.format(test_id, i, y))
+ elif y == sentinel:
+ self.fail('{0}: unexpected excess element {1} at '
+ 'position {2}'.format(test_id, x, i))
+ else:
+ self.fail('{0}: wrong element at position {1};'
+ 'expected {2}, got {3}'.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,38 @@ 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({0}, {1}, {2})".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({0}, {1}, {2}))".format(
+ start, end, step)
+ self.assert_iterators_equal(iter1, iter2, test_id, limit=100)
+
def test_main():
test.test_support.run_unittest(XrangeTest)