test_xrange.py 7.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218
  1. # Python test set -- built-in functions
  2. import test.test_support, unittest
  3. import sys
  4. import pickle
  5. import itertools
  6. import warnings
  7. warnings.filterwarnings("ignore", "integer argument expected",
  8. DeprecationWarning, "unittest")
  9. # pure Python implementations (3 args only), for comparison
  10. def pyrange(start, stop, step):
  11. if (start - stop) // step < 0:
  12. # replace stop with next element in the sequence of integers
  13. # that are congruent to start modulo step.
  14. stop += (start - stop) % step
  15. while start != stop:
  16. yield start
  17. start += step
  18. def pyrange_reversed(start, stop, step):
  19. stop += (start - stop) % step
  20. return pyrange(stop - step, start - step, -step)
  21. class XrangeTest(unittest.TestCase):
  22. def assert_iterators_equal(self, xs, ys, test_id, limit=None):
  23. # check that an iterator xs matches the expected results ys,
  24. # up to a given limit.
  25. if limit is not None:
  26. xs = itertools.islice(xs, limit)
  27. ys = itertools.islice(ys, limit)
  28. sentinel = object()
  29. pairs = itertools.izip_longest(xs, ys, fillvalue=sentinel)
  30. for i, (x, y) in enumerate(pairs):
  31. if x == y:
  32. continue
  33. elif x == sentinel:
  34. self.fail('{}: iterator ended unexpectedly '
  35. 'at position {}; expected {}'.format(test_id, i, y))
  36. elif y == sentinel:
  37. self.fail('{}: unexpected excess element {} at '
  38. 'position {}'.format(test_id, x, i))
  39. else:
  40. self.fail('{}: wrong element at position {};'
  41. 'expected {}, got {}'.format(test_id, i, y, x))
  42. def assert_xranges_equivalent(self, x, y):
  43. # Check that two xrange objects are equivalent, in the sense of the
  44. # associated sequences being the same. We want to use this for large
  45. # xrange objects, so instead of converting to lists and comparing
  46. # directly we do a number of indirect checks.
  47. if len(x) != len(y):
  48. self.fail('{} and {} have different '
  49. 'lengths: {} and {} '.format(x, y, len(x), len(y)))
  50. if len(x) >= 1:
  51. if x[0] != y[0]:
  52. self.fail('{} and {} have different initial '
  53. 'elements: {} and {} '.format(x, y, x[0], y[0]))
  54. if x[-1] != y[-1]:
  55. self.fail('{} and {} have different final '
  56. 'elements: {} and {} '.format(x, y, x[-1], y[-1]))
  57. if len(x) >= 2:
  58. x_step = x[1] - x[0]
  59. y_step = y[1] - y[0]
  60. if x_step != y_step:
  61. self.fail('{} and {} have different step: '
  62. '{} and {} '.format(x, y, x_step, y_step))
  63. def test_xrange(self):
  64. self.assertEqual(list(xrange(3)), [0, 1, 2])
  65. self.assertEqual(list(xrange(1, 5)), [1, 2, 3, 4])
  66. self.assertEqual(list(xrange(0)), [])
  67. self.assertEqual(list(xrange(-3)), [])
  68. self.assertEqual(list(xrange(1, 10, 3)), [1, 4, 7])
  69. self.assertEqual(list(xrange(5, -5, -3)), [5, 2, -1, -4])
  70. a = 10
  71. b = 100
  72. c = 50
  73. self.assertEqual(list(xrange(a, a+2)), [a, a+1])
  74. self.assertEqual(list(xrange(a+2, a, -1L)), [a+2, a+1])
  75. self.assertEqual(list(xrange(a+4, a, -2)), [a+4, a+2])
  76. seq = list(xrange(a, b, c))
  77. self.assertIn(a, seq)
  78. self.assertNotIn(b, seq)
  79. self.assertEqual(len(seq), 2)
  80. seq = list(xrange(b, a, -c))
  81. self.assertIn(b, seq)
  82. self.assertNotIn(a, seq)
  83. self.assertEqual(len(seq), 2)
  84. seq = list(xrange(-a, -b, -c))
  85. self.assertIn(-a, seq)
  86. self.assertNotIn(-b, seq)
  87. self.assertEqual(len(seq), 2)
  88. self.assertRaises(TypeError, xrange)
  89. self.assertRaises(TypeError, xrange, 1, 2, 3, 4)
  90. self.assertRaises(ValueError, xrange, 1, 2, 0)
  91. self.assertRaises(OverflowError, xrange, 10**100, 10**101, 10**101)
  92. self.assertRaises(TypeError, xrange, 0, "spam")
  93. self.assertRaises(TypeError, xrange, 0, 42, "spam")
  94. self.assertEqual(len(xrange(0, sys.maxint, sys.maxint-1)), 2)
  95. self.assertRaises(OverflowError, xrange, -sys.maxint, sys.maxint)
  96. self.assertRaises(OverflowError, xrange, 0, 2*sys.maxint)
  97. r = xrange(-sys.maxint, sys.maxint, 2)
  98. self.assertEqual(len(r), sys.maxint)
  99. self.assertRaises(OverflowError, xrange, -sys.maxint-1, sys.maxint, 2)
  100. def test_pickling(self):
  101. testcases = [(13,), (0, 11), (-22, 10), (20, 3, -1),
  102. (13, 21, 3), (-2, 2, 2)]
  103. for proto in range(pickle.HIGHEST_PROTOCOL + 1):
  104. for t in testcases:
  105. r = xrange(*t)
  106. self.assertEqual(list(pickle.loads(pickle.dumps(r, proto))),
  107. list(r))
  108. M = min(sys.maxint, sys.maxsize)
  109. large_testcases = testcases + [
  110. (0, M, 1),
  111. (M, 0, -1),
  112. (0, M, M - 1),
  113. (M // 2, M, 1),
  114. (0, -M, -1),
  115. (0, -M, 1 - M),
  116. (-M, M, 2),
  117. (-M, M, 1024),
  118. (-M, M, 10585),
  119. (M, -M, -2),
  120. (M, -M, -1024),
  121. (M, -M, -10585),
  122. ]
  123. for proto in range(pickle.HIGHEST_PROTOCOL + 1):
  124. for t in large_testcases:
  125. r = xrange(*t)
  126. r_out = pickle.loads(pickle.dumps(r, proto))
  127. self.assert_xranges_equivalent(r_out, r)
  128. def test_repr(self):
  129. # Check that repr of an xrange is a valid representation
  130. # of that xrange.
  131. # Valid xranges have at most min(sys.maxint, sys.maxsize) elements.
  132. M = min(sys.maxint, sys.maxsize)
  133. testcases = [
  134. (13,),
  135. (0, 11),
  136. (-22, 10),
  137. (20, 3, -1),
  138. (13, 21, 3),
  139. (-2, 2, 2),
  140. (0, M, 1),
  141. (M, 0, -1),
  142. (0, M, M - 1),
  143. (M // 2, M, 1),
  144. (0, -M, -1),
  145. (0, -M, 1 - M),
  146. (-M, M, 2),
  147. (-M, M, 1024),
  148. (-M, M, 10585),
  149. (M, -M, -2),
  150. (M, -M, -1024),
  151. (M, -M, -10585),
  152. ]
  153. for t in testcases:
  154. r = xrange(*t)
  155. r_out = eval(repr(r))
  156. self.assert_xranges_equivalent(r, r_out)
  157. def test_range_iterators(self):
  158. # see issue 7298
  159. limits = [base + jiggle
  160. for M in (2**32, 2**64)
  161. for base in (-M, -M//2, 0, M//2, M)
  162. for jiggle in (-2, -1, 0, 1, 2)]
  163. test_ranges = [(start, end, step)
  164. for start in limits
  165. for end in limits
  166. for step in (-2**63, -2**31, -2, -1, 1, 2)]
  167. for start, end, step in test_ranges:
  168. try:
  169. iter1 = xrange(start, end, step)
  170. except OverflowError:
  171. pass
  172. else:
  173. iter2 = pyrange(start, end, step)
  174. test_id = "xrange({}, {}, {})".format(start, end, step)
  175. # check first 100 entries
  176. self.assert_iterators_equal(iter1, iter2, test_id, limit=100)
  177. try:
  178. iter1 = reversed(xrange(start, end, step))
  179. except OverflowError:
  180. pass
  181. else:
  182. iter2 = pyrange_reversed(start, end, step)
  183. test_id = "reversed(xrange({}, {}, {}))".format(start, end, step)
  184. self.assert_iterators_equal(iter1, iter2, test_id, limit=100)
  185. def test_main():
  186. test.test_support.run_unittest(XrangeTest)
  187. if __name__ == "__main__":
  188. test_main()