move sections
[python/dscho.git] / Lib / test / test_bisect.py
blob934ba8c7a10bde1e5342c59a58ba776bb8ae78d1
1 import sys
2 import unittest
3 from test import test_support
4 from UserList import UserList
6 # We do a bit of trickery here to be able to test both the C implementation
7 # and the Python implementation of the module.
9 # Make it impossible to import the C implementation anymore.
10 sys.modules['_bisect'] = 0
11 # We must also handle the case that bisect was imported before.
12 if 'bisect' in sys.modules:
13 del sys.modules['bisect']
15 # Now we can import the module and get the pure Python implementation.
16 import bisect as py_bisect
18 # Restore everything to normal.
19 del sys.modules['_bisect']
20 del sys.modules['bisect']
22 # This is now the module with the C implementation.
23 import bisect as c_bisect
26 class TestBisect(unittest.TestCase):
27 module = None
29 def setUp(self):
30 self.precomputedCases = [
31 (self.module.bisect_right, [], 1, 0),
32 (self.module.bisect_right, [1], 0, 0),
33 (self.module.bisect_right, [1], 1, 1),
34 (self.module.bisect_right, [1], 2, 1),
35 (self.module.bisect_right, [1, 1], 0, 0),
36 (self.module.bisect_right, [1, 1], 1, 2),
37 (self.module.bisect_right, [1, 1], 2, 2),
38 (self.module.bisect_right, [1, 1, 1], 0, 0),
39 (self.module.bisect_right, [1, 1, 1], 1, 3),
40 (self.module.bisect_right, [1, 1, 1], 2, 3),
41 (self.module.bisect_right, [1, 1, 1, 1], 0, 0),
42 (self.module.bisect_right, [1, 1, 1, 1], 1, 4),
43 (self.module.bisect_right, [1, 1, 1, 1], 2, 4),
44 (self.module.bisect_right, [1, 2], 0, 0),
45 (self.module.bisect_right, [1, 2], 1, 1),
46 (self.module.bisect_right, [1, 2], 1.5, 1),
47 (self.module.bisect_right, [1, 2], 2, 2),
48 (self.module.bisect_right, [1, 2], 3, 2),
49 (self.module.bisect_right, [1, 1, 2, 2], 0, 0),
50 (self.module.bisect_right, [1, 1, 2, 2], 1, 2),
51 (self.module.bisect_right, [1, 1, 2, 2], 1.5, 2),
52 (self.module.bisect_right, [1, 1, 2, 2], 2, 4),
53 (self.module.bisect_right, [1, 1, 2, 2], 3, 4),
54 (self.module.bisect_right, [1, 2, 3], 0, 0),
55 (self.module.bisect_right, [1, 2, 3], 1, 1),
56 (self.module.bisect_right, [1, 2, 3], 1.5, 1),
57 (self.module.bisect_right, [1, 2, 3], 2, 2),
58 (self.module.bisect_right, [1, 2, 3], 2.5, 2),
59 (self.module.bisect_right, [1, 2, 3], 3, 3),
60 (self.module.bisect_right, [1, 2, 3], 4, 3),
61 (self.module.bisect_right, [1, 2, 2, 3, 3, 3, 4, 4, 4, 4], 0, 0),
62 (self.module.bisect_right, [1, 2, 2, 3, 3, 3, 4, 4, 4, 4], 1, 1),
63 (self.module.bisect_right, [1, 2, 2, 3, 3, 3, 4, 4, 4, 4], 1.5, 1),
64 (self.module.bisect_right, [1, 2, 2, 3, 3, 3, 4, 4, 4, 4], 2, 3),
65 (self.module.bisect_right, [1, 2, 2, 3, 3, 3, 4, 4, 4, 4], 2.5, 3),
66 (self.module.bisect_right, [1, 2, 2, 3, 3, 3, 4, 4, 4, 4], 3, 6),
67 (self.module.bisect_right, [1, 2, 2, 3, 3, 3, 4, 4, 4, 4], 3.5, 6),
68 (self.module.bisect_right, [1, 2, 2, 3, 3, 3, 4, 4, 4, 4], 4, 10),
69 (self.module.bisect_right, [1, 2, 2, 3, 3, 3, 4, 4, 4, 4], 5, 10),
71 (self.module.bisect_left, [], 1, 0),
72 (self.module.bisect_left, [1], 0, 0),
73 (self.module.bisect_left, [1], 1, 0),
74 (self.module.bisect_left, [1], 2, 1),
75 (self.module.bisect_left, [1, 1], 0, 0),
76 (self.module.bisect_left, [1, 1], 1, 0),
77 (self.module.bisect_left, [1, 1], 2, 2),
78 (self.module.bisect_left, [1, 1, 1], 0, 0),
79 (self.module.bisect_left, [1, 1, 1], 1, 0),
80 (self.module.bisect_left, [1, 1, 1], 2, 3),
81 (self.module.bisect_left, [1, 1, 1, 1], 0, 0),
82 (self.module.bisect_left, [1, 1, 1, 1], 1, 0),
83 (self.module.bisect_left, [1, 1, 1, 1], 2, 4),
84 (self.module.bisect_left, [1, 2], 0, 0),
85 (self.module.bisect_left, [1, 2], 1, 0),
86 (self.module.bisect_left, [1, 2], 1.5, 1),
87 (self.module.bisect_left, [1, 2], 2, 1),
88 (self.module.bisect_left, [1, 2], 3, 2),
89 (self.module.bisect_left, [1, 1, 2, 2], 0, 0),
90 (self.module.bisect_left, [1, 1, 2, 2], 1, 0),
91 (self.module.bisect_left, [1, 1, 2, 2], 1.5, 2),
92 (self.module.bisect_left, [1, 1, 2, 2], 2, 2),
93 (self.module.bisect_left, [1, 1, 2, 2], 3, 4),
94 (self.module.bisect_left, [1, 2, 3], 0, 0),
95 (self.module.bisect_left, [1, 2, 3], 1, 0),
96 (self.module.bisect_left, [1, 2, 3], 1.5, 1),
97 (self.module.bisect_left, [1, 2, 3], 2, 1),
98 (self.module.bisect_left, [1, 2, 3], 2.5, 2),
99 (self.module.bisect_left, [1, 2, 3], 3, 2),
100 (self.module.bisect_left, [1, 2, 3], 4, 3),
101 (self.module.bisect_left, [1, 2, 2, 3, 3, 3, 4, 4, 4, 4], 0, 0),
102 (self.module.bisect_left, [1, 2, 2, 3, 3, 3, 4, 4, 4, 4], 1, 0),
103 (self.module.bisect_left, [1, 2, 2, 3, 3, 3, 4, 4, 4, 4], 1.5, 1),
104 (self.module.bisect_left, [1, 2, 2, 3, 3, 3, 4, 4, 4, 4], 2, 1),
105 (self.module.bisect_left, [1, 2, 2, 3, 3, 3, 4, 4, 4, 4], 2.5, 3),
106 (self.module.bisect_left, [1, 2, 2, 3, 3, 3, 4, 4, 4, 4], 3, 3),
107 (self.module.bisect_left, [1, 2, 2, 3, 3, 3, 4, 4, 4, 4], 3.5, 6),
108 (self.module.bisect_left, [1, 2, 2, 3, 3, 3, 4, 4, 4, 4], 4, 6),
109 (self.module.bisect_left, [1, 2, 2, 3, 3, 3, 4, 4, 4, 4], 5, 10)
112 def test_precomputed(self):
113 for func, data, elem, expected in self.precomputedCases:
114 self.assertEqual(func(data, elem), expected)
115 self.assertEqual(func(UserList(data), elem), expected)
117 def test_negative_lo(self):
118 # Issue 3301
119 mod = self.module
120 self.assertRaises(ValueError, mod.bisect_left, [1, 2, 3], 5, -1, 3),
121 self.assertRaises(ValueError, mod.bisect_right, [1, 2, 3], 5, -1, 3),
122 self.assertRaises(ValueError, mod.insort_left, [1, 2, 3], 5, -1, 3),
123 self.assertRaises(ValueError, mod.insort_right, [1, 2, 3], 5, -1, 3),
125 def test_random(self, n=25):
126 from random import randrange
127 for i in xrange(n):
128 data = [randrange(0, n, 2) for j in xrange(i)]
129 data.sort()
130 elem = randrange(-1, n+1)
131 ip = self.module.bisect_left(data, elem)
132 if ip < len(data):
133 self.assertTrue(elem <= data[ip])
134 if ip > 0:
135 self.assertTrue(data[ip-1] < elem)
136 ip = self.module.bisect_right(data, elem)
137 if ip < len(data):
138 self.assertTrue(elem < data[ip])
139 if ip > 0:
140 self.assertTrue(data[ip-1] <= elem)
142 def test_optionalSlicing(self):
143 for func, data, elem, expected in self.precomputedCases:
144 for lo in xrange(4):
145 lo = min(len(data), lo)
146 for hi in xrange(3,8):
147 hi = min(len(data), hi)
148 ip = func(data, elem, lo, hi)
149 self.assertTrue(lo <= ip <= hi)
150 if func is self.module.bisect_left and ip < hi:
151 self.assertTrue(elem <= data[ip])
152 if func is self.module.bisect_left and ip > lo:
153 self.assertTrue(data[ip-1] < elem)
154 if func is self.module.bisect_right and ip < hi:
155 self.assertTrue(elem < data[ip])
156 if func is self.module.bisect_right and ip > lo:
157 self.assertTrue(data[ip-1] <= elem)
158 self.assertEqual(ip, max(lo, min(hi, expected)))
160 def test_backcompatibility(self):
161 self.assertEqual(self.module.bisect, self.module.bisect_right)
163 def test_keyword_args(self):
164 data = [10, 20, 30, 40, 50]
165 self.assertEqual(self.module.bisect_left(a=data, x=25, lo=1, hi=3), 2)
166 self.assertEqual(self.module.bisect_right(a=data, x=25, lo=1, hi=3), 2)
167 self.assertEqual(self.module.bisect(a=data, x=25, lo=1, hi=3), 2)
168 self.module.insort_left(a=data, x=25, lo=1, hi=3)
169 self.module.insort_right(a=data, x=25, lo=1, hi=3)
170 self.module.insort(a=data, x=25, lo=1, hi=3)
171 self.assertEqual(data, [10, 20, 25, 25, 25, 30, 40, 50])
173 class TestBisectPython(TestBisect):
174 module = py_bisect
176 class TestBisectC(TestBisect):
177 module = c_bisect
179 #==============================================================================
181 class TestInsort(unittest.TestCase):
182 module = None
184 def test_vsBuiltinSort(self, n=500):
185 from random import choice
186 for insorted in (list(), UserList()):
187 for i in xrange(n):
188 digit = choice("0123456789")
189 if digit in "02468":
190 f = self.module.insort_left
191 else:
192 f = self.module.insort_right
193 f(insorted, digit)
194 self.assertEqual(sorted(insorted), insorted)
196 def test_backcompatibility(self):
197 self.assertEqual(self.module.insort, self.module.insort_right)
199 def test_listDerived(self):
200 class List(list):
201 data = []
202 def insert(self, index, item):
203 self.data.insert(index, item)
205 lst = List()
206 self.module.insort_left(lst, 10)
207 self.module.insort_right(lst, 5)
208 self.assertEqual([5, 10], lst.data)
210 class TestInsortPython(TestInsort):
211 module = py_bisect
213 class TestInsortC(TestInsort):
214 module = c_bisect
216 #==============================================================================
219 class LenOnly:
220 "Dummy sequence class defining __len__ but not __getitem__."
221 def __len__(self):
222 return 10
224 class GetOnly:
225 "Dummy sequence class defining __getitem__ but not __len__."
226 def __getitem__(self, ndx):
227 return 10
229 class CmpErr:
230 "Dummy element that always raises an error during comparison"
231 def __cmp__(self, other):
232 raise ZeroDivisionError
234 class TestErrorHandling(unittest.TestCase):
235 module = None
237 def test_non_sequence(self):
238 for f in (self.module.bisect_left, self.module.bisect_right,
239 self.module.insort_left, self.module.insort_right):
240 self.assertRaises(TypeError, f, 10, 10)
242 def test_len_only(self):
243 for f in (self.module.bisect_left, self.module.bisect_right,
244 self.module.insort_left, self.module.insort_right):
245 self.assertRaises(AttributeError, f, LenOnly(), 10)
247 def test_get_only(self):
248 for f in (self.module.bisect_left, self.module.bisect_right,
249 self.module.insort_left, self.module.insort_right):
250 self.assertRaises(AttributeError, f, GetOnly(), 10)
252 def test_cmp_err(self):
253 seq = [CmpErr(), CmpErr(), CmpErr()]
254 for f in (self.module.bisect_left, self.module.bisect_right,
255 self.module.insort_left, self.module.insort_right):
256 self.assertRaises(ZeroDivisionError, f, seq, 10)
258 def test_arg_parsing(self):
259 for f in (self.module.bisect_left, self.module.bisect_right,
260 self.module.insort_left, self.module.insort_right):
261 self.assertRaises(TypeError, f, 10)
263 class TestErrorHandlingPython(TestErrorHandling):
264 module = py_bisect
266 class TestErrorHandlingC(TestErrorHandling):
267 module = c_bisect
269 #==============================================================================
271 libreftest = """
272 Example from the Library Reference: Doc/library/bisect.rst
274 The bisect() function is generally useful for categorizing numeric data.
275 This example uses bisect() to look up a letter grade for an exam total
276 (say) based on a set of ordered numeric breakpoints: 85 and up is an `A',
277 75..84 is a `B', etc.
279 >>> grades = "FEDCBA"
280 >>> breakpoints = [30, 44, 66, 75, 85]
281 >>> from bisect import bisect
282 >>> def grade(total):
283 ... return grades[bisect(breakpoints, total)]
285 >>> grade(66)
287 >>> map(grade, [33, 99, 77, 44, 12, 88])
288 ['E', 'A', 'B', 'D', 'F', 'A']
292 #------------------------------------------------------------------------------
294 __test__ = {'libreftest' : libreftest}
296 def test_main(verbose=None):
297 from test import test_bisect
299 test_classes = [TestBisectPython, TestBisectC,
300 TestInsortPython, TestInsortC,
301 TestErrorHandlingPython, TestErrorHandlingC]
303 test_support.run_unittest(*test_classes)
304 test_support.run_doctest(test_bisect, verbose)
306 # verify reference counting
307 if verbose and hasattr(sys, "gettotalrefcount"):
308 import gc
309 counts = [None] * 5
310 for i in xrange(len(counts)):
311 test_support.run_unittest(*test_classes)
312 gc.collect()
313 counts[i] = sys.gettotalrefcount()
314 print counts
316 if __name__ == "__main__":
317 test_main(verbose=True)