test_range.py 6.86 KB
Newer Older
Neal Norwitz's avatar
Neal Norwitz committed
1 2
# Python test set -- built-in functions

3
import test.support, unittest
Neal Norwitz's avatar
Neal Norwitz committed
4
import sys
5
import pickle
6
import itertools
Neal Norwitz's avatar
Neal Norwitz committed
7

8 9 10 11 12 13 14 15 16 17 18 19 20 21 22
# 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)


23
class RangeTest(unittest.TestCase):
24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44
    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))

45
    def test_range(self):
46 47 48 49 50 51
        self.assertEqual(list(range(3)), [0, 1, 2])
        self.assertEqual(list(range(1, 5)), [1, 2, 3, 4])
        self.assertEqual(list(range(0)), [])
        self.assertEqual(list(range(-3)), [])
        self.assertEqual(list(range(1, 10, 3)), [1, 4, 7])
        self.assertEqual(list(range(5, -5, -3)), [5, 2, -1, -4])
Neal Norwitz's avatar
Neal Norwitz committed
52 53 54 55 56

        a = 10
        b = 100
        c = 50

57 58 59
        self.assertEqual(list(range(a, a+2)), [a, a+1])
        self.assertEqual(list(range(a+2, a, -1)), [a+2, a+1])
        self.assertEqual(list(range(a+4, a, -2)), [a+4, a+2])
Neal Norwitz's avatar
Neal Norwitz committed
60

61
        seq = list(range(a, b, c))
62 63
        self.assertIn(a, seq)
        self.assertNotIn(b, seq)
Neal Norwitz's avatar
Neal Norwitz committed
64 65
        self.assertEqual(len(seq), 2)

66
        seq = list(range(b, a, -c))
67 68
        self.assertIn(b, seq)
        self.assertNotIn(a, seq)
Neal Norwitz's avatar
Neal Norwitz committed
69 70
        self.assertEqual(len(seq), 2)

71
        seq = list(range(-a, -b, -c))
72 73
        self.assertIn(-a, seq)
        self.assertNotIn(-b, seq)
Neal Norwitz's avatar
Neal Norwitz committed
74 75
        self.assertEqual(len(seq), 2)

76 77 78
        self.assertRaises(TypeError, range)
        self.assertRaises(TypeError, range, 1, 2, 3, 4)
        self.assertRaises(ValueError, range, 1, 2, 0)
Neal Norwitz's avatar
Neal Norwitz committed
79

80 81 82 83
        self.assertRaises(TypeError, range, 0.0, 2, 1)
        self.assertRaises(TypeError, range, 1, 2.0, 1)
        self.assertRaises(TypeError, range, 1, 2, 1.0)
        self.assertRaises(TypeError, range, 1e100, 1e101, 1e101)
Neal Norwitz's avatar
Neal Norwitz committed
84

85 86
        self.assertRaises(TypeError, range, 0, "spam")
        self.assertRaises(TypeError, range, 0, 42, "spam")
Neal Norwitz's avatar
Neal Norwitz committed
87

88
        self.assertEqual(len(range(0, sys.maxsize, sys.maxsize-1)), 2)
89

90 91
        r = range(-sys.maxsize, sys.maxsize, 2)
        self.assertEqual(len(r), sys.maxsize)
92

93
    def test_repr(self):
94
        self.assertEqual(repr(range(1)), 'range(0, 1)')
95 96 97
        self.assertEqual(repr(range(1, 2)), 'range(1, 2)')
        self.assertEqual(repr(range(1, 2, 3)), 'range(1, 2, 3)')

98 99 100
    def test_pickling(self):
        testcases = [(13,), (0, 11), (-22, 10), (20, 3, -1),
                     (13, 21, 3), (-2, 2, 2)]
101
        for proto in range(pickle.HIGHEST_PROTOCOL + 1):
102 103 104 105 106
            for t in testcases:
                r = range(*t)
                self.assertEquals(list(pickle.loads(pickle.dumps(r, proto))),
                                  list(r))

107 108 109 110 111 112 113
    def test_odd_bug(self):
        # This used to raise a "SystemError: NULL result without error"
        # because the range validation step was eating the exception
        # before NULL was returned.
        with self.assertRaises(TypeError):
            range([], 1, -1)

114 115 116
    def test_types(self):
        # Non-integer objects *equal* to any of the range's items are supposed
        # to be contained in the range.
117 118 119
        self.assertIn(1.0, range(3))
        self.assertIn(True, range(3))
        self.assertIn(1+0j, range(3))
120 121 122

        class C1:
            def __eq__(self, other): return True
123
        self.assertIn(C1(), range(3))
124 125 126 127 128

        # Objects are never coerced into other types for comparison.
        class C2:
            def __int__(self): return 1
            def __index__(self): return 1
129
        self.assertNotIn(C2(), range(3))
130
        # ..except if explicitly told so.
131
        self.assertIn(int(C2()), range(3))
132

133 134 135 136
        # Check that the range.__contains__ optimization is only
        # used for ints, not for instances of subclasses of int.
        class C3(int):
            def __eq__(self, other): return True
137 138
        self.assertIn(C3(11), range(10))
        self.assertIn(C3(11), list(range(10)))
139 140 141

    def test_strided_limits(self):
        r = range(0, 101, 2)
142
        self.assertIn(0, r)
143
        self.assertNotIn(1, r)
144
        self.assertIn(2, r)
145
        self.assertNotIn(99, r)
146
        self.assertIn(100, r)
147
        self.assertNotIn(101, r)
148 149

        r = range(0, -20, -1)
150 151 152
        self.assertIn(0, r)
        self.assertIn(-1, r)
        self.assertIn(-19, r)
153
        self.assertNotIn(-20, r)
154 155

        r = range(0, -20, -2)
156
        self.assertIn(-18, r)
157 158
        self.assertNotIn(-19, r)
        self.assertNotIn(-20, r)
159 160 161

    def test_empty(self):
        r = range(0)
162 163
        self.assertNotIn(0, r)
        self.assertNotIn(1, r)
164 165

        r = range(0, -10)
166 167 168
        self.assertNotIn(0, r)
        self.assertNotIn(-1, r)
        self.assertNotIn(1, r)
169

170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193
    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)

Neal Norwitz's avatar
Neal Norwitz committed
194
def test_main():
195
    test.support.run_unittest(RangeTest)
Neal Norwitz's avatar
Neal Norwitz committed
196 197 198

if __name__ == "__main__":
    test_main()