Rietveld Code Review Tool
Help | Bug tracker | Discussion group | Source code | Sign in
(8)

Side by Side Diff: Lib/test/test_slice.py

Issue 14794: slice.indices raises OverflowError
Patch Set: Created 7 years, 3 months ago
 Left: Base Patch Set 1: None Patch Set 2: None Patch Set 3: None Patch Set 4: None Right: Patch Set 1: None Patch Set 2: None Patch Set 3: None Patch Set 4: None
« no previous file with comments | « no previous file | Objects/sliceobject.c » ('j') | Objects/sliceobject.c » ('J')
OLDNEW
1 # tests for slice objects; in particular the indices method. 1 # tests for slice objects; in particular the indices method.
2 2
3 import unittest 3 import unittest
4 from test import support 4 from test import support
5 from pickle import loads, dumps 5 from pickle import loads, dumps
6 6
7 import itertools
8 import operator
7 import sys 9 import sys
10
11
12 def evaluate_slice_index(arg):
13 """
14 Helper function to convert a slice argument to an integer, and raise
15 TypeError with a suitable message on failure.
16
17 """
18 if hasattr(arg, '__index__'):
19 return operator.index(arg)
20 else:
21 raise TypeError(
22 "slice indices must be integers or "
23 "None or have an __index__ method")
24
25 def slice_indices(slice, length):
26 """
27 Reference implementation for the slice.indices method.
28
29 """
30 # Compute step and length as integers.
31 length = operator.index(length)
32 step = 1 if slice.step is None else evaluate_slice_index(slice.step)
33
34 # Raise ValueError for negative length or zero step.
35 if length < 0:
36 raise ValueError("length should not be negative")
37 if step == 0:
38 raise ValueError("slice step cannot be zero")
39
40 # Find lower and upper bounds for start and stop.
41 lower = -1 if step < 0 else 0
42 upper = length - 1 if step < 0 else length
43
44 # Compute start.
45 if slice.start is None:
46 start = upper if step < 0 else lower
47 else:
48 start = evaluate_slice_index(slice.start)
49 start = max(start + length, lower) if start < 0 else min(start, upper)
50
51 # Compute stop.
52 if slice.stop is None:
53 stop = lower if step < 0 else upper
54 else:
55 stop = evaluate_slice_index(slice.stop)
56 stop = max(stop + length, lower) if stop < 0 else min(stop, upper)
57
58 return start, stop, step
59
60
61 # Class providing an __index__ method. Used for testing slice.indices.
62
63 class MyIndexable(object):
64 def __init__(self, value):
65 self.value = value
66
67 def __index__(self):
68 return self.value
69
8 70
9 class SliceTest(unittest.TestCase): 71 class SliceTest(unittest.TestCase):
10 72
11 def test_constructor(self): 73 def test_constructor(self):
12 self.assertRaises(TypeError, slice) 74 self.assertRaises(TypeError, slice)
13 self.assertRaises(TypeError, slice, 1, 2, 3, 4) 75 self.assertRaises(TypeError, slice, 1, 2, 3, 4)
14 76
15 def test_repr(self): 77 def test_repr(self):
16 self.assertEqual(repr(slice(1, 2, 3)), "slice(1, 2, 3)") 78 self.assertEqual(repr(slice(1, 2, 3)), "slice(1, 2, 3)")
17 79
(...skipping 49 matching lines...)
67 self.assertEqual(s.start, 1) 129 self.assertEqual(s.start, 1)
68 self.assertEqual(s.stop, 2) 130 self.assertEqual(s.stop, 2)
69 self.assertEqual(s.step, 3) 131 self.assertEqual(s.step, 3)
70 132
71 class AnyClass: 133 class AnyClass:
72 pass 134 pass
73 135
74 obj = AnyClass() 136 obj = AnyClass()
75 s = slice(obj) 137 s = slice(obj)
76 self.assertTrue(s.stop is obj) 138 self.assertTrue(s.stop is obj)
139
140 def check_indices(self, slice, length):
141 try:
142 actual = slice.indices(length)
143 except ValueError:
144 actual = "valueerror"
145 try:
146 expected = slice_indices(slice, length)
147 except ValueError:
148 expected = "valueerror"
149 self.assertEqual(actual, expected)
150
151 if length >= 0 and slice.step != 0:
152 actual = range(*slice.indices(length))
153 expected = range(length)[slice]
154 self.assertEqual(actual, expected)
77 155
78 def test_indices(self): 156 def test_indices(self):
79 self.assertEqual(slice(None ).indices(10), (0, 10, 1)) 157 self.assertEqual(slice(None ).indices(10), (0, 10, 1))
80 self.assertEqual(slice(None, None, 2).indices(10), (0, 10, 2)) 158 self.assertEqual(slice(None, None, 2).indices(10), (0, 10, 2))
81 self.assertEqual(slice(1, None, 2).indices(10), (1, 10, 2)) 159 self.assertEqual(slice(1, None, 2).indices(10), (1, 10, 2))
82 self.assertEqual(slice(None, None, -1).indices(10), (9, -1, -1)) 160 self.assertEqual(slice(None, None, -1).indices(10), (9, -1, -1))
83 self.assertEqual(slice(None, None, -2).indices(10), (9, -1, -2)) 161 self.assertEqual(slice(None, None, -2).indices(10), (9, -1, -2))
84 self.assertEqual(slice(3, None, -2).indices(10), (3, -1, -2)) 162 self.assertEqual(slice(3, None, -2).indices(10), (3, -1, -2))
85 # issue 3004 tests 163 # issue 3004 tests
86 self.assertEqual(slice(None, -9).indices(10), (0, 1, 1)) 164 self.assertEqual(slice(None, -9).indices(10), (0, 1, 1))
(...skipping 14 matching lines...) Expand all
101 slice(None).indices(10) 179 slice(None).indices(10)
102 ) 180 )
103 self.assertEqual( 181 self.assertEqual(
104 slice(100, -100, -1).indices(10), 182 slice(100, -100, -1).indices(10),
105 slice(None, None, -1).indices(10) 183 slice(None, None, -1).indices(10)
106 ) 184 )
107 self.assertEqual(slice(-100, 100, 2).indices(10), (0, 10, 2)) 185 self.assertEqual(slice(-100, 100, 2).indices(10), (0, 10, 2))
108 186
109 self.assertEqual(list(range(10))[::sys.maxsize - 1], [0]) 187 self.assertEqual(list(range(10))[::sys.maxsize - 1], [0])
110 188
111 self.assertRaises(OverflowError, slice(None).indices, 1<<100) 189 # Check a variety of start, stop, step and length values, including
190 # values exceeding sys.maxsize (see issue #14794).
191 vals = [None, -2**100, -2**30, -53, -7, -1, 0, 1, 7, 53, 2**30, 2**100]
192 lengths = [0, 1, 7, 53, 2**30, 2**100]
193 for slice_args in itertools.product(vals, repeat=3):
194 s = slice(*slice_args)
195 for length in lengths:
196 self.check_indices(s, length)
197 self.check_indices(slice(0, 10, 1), -3)
198
199 # Negative length should raise ValueError
200 with self.assertRaises(ValueError):
201 slice(None).indices(-1)
202
203 # Zero step should raise ValueError
204 with self.assertRaises(ValueError):
205 slice(0, 10, 0).indices(5)
206
207 # Using a start, stop or step or length that can't be interpreted as an
208 # integer should give a TypeError ...
209 with self.assertRaises(TypeError):
210 slice(0.0, 10, 1).indices(5)
211 with self.assertRaises(TypeError):
212 slice(0, 10.0, 1).indices(5)
213 with self.assertRaises(TypeError):
214 slice(0, 10, 1.0).indices(5)
215 with self.assertRaises(TypeError):
216 slice(0, 10, 1).indices(5.0)
217
218 # ... but it should be fine to use a custom class that provides index.
219 self.assertEqual(slice(0, 10, 1).indices(5), (0, 5, 1))
220 self.assertEqual(slice(MyIndexable(0), 10, 1).indices(5), (0, 5, 1))
221 self.assertEqual(slice(0, MyIndexable(10), 1).indices(5), (0, 5, 1))
222 self.assertEqual(slice(0, 10, MyIndexable(1)).indices(5), (0, 5, 1))
223 self.assertEqual(slice(0, 10, 1).indices(MyIndexable(5)), (0, 5, 1))
112 224
113 def test_setslice_without_getslice(self): 225 def test_setslice_without_getslice(self):
114 tmp = [] 226 tmp = []
115 class X(object): 227 class X(object):
116 def __setitem__(self, i, k): 228 def __setitem__(self, i, k):
117 tmp.append((i, k)) 229 tmp.append((i, k))
118 230
119 x = X() 231 x = X()
120 x[1:2] = 42 232 x[1:2] = 42
121 self.assertEqual(tmp, [(slice(1, 2), 42)]) 233 self.assertEqual(tmp, [(slice(1, 2), 42)])
122 234
123 def test_pickle(self): 235 def test_pickle(self):
124 s = slice(10, 20, 3) 236 s = slice(10, 20, 3)
125 for protocol in (0,1,2): 237 for protocol in (0,1,2):