blob: 987f33cb6135a930d0559c2caa20992dc4b7c22b [file] [log] [blame]
Christian Heimesd3eb5a152008-02-24 00:38:49 +00001import sys
Raymond Hettingerd2305502003-01-16 12:02:35 +00002import unittest
Benjamin Petersonee8712c2008-05-20 21:35:26 +00003from test import support
Raymond Hettinger53dbe392008-02-12 20:03:09 +00004from collections import UserList
Tim Peters36cdad12000-12-29 02:06:45 +00005
Christian Heimesd3eb5a152008-02-24 00:38:49 +00006# We do a bit of trickery here to be able to test both the C implementation
7# and the Python implementation of the module.
8
9# Make it impossible to import the C implementation anymore.
10sys.modules['_bisect'] = 0
11# We must also handle the case that bisect was imported before.
12if 'bisect' in sys.modules:
13 del sys.modules['bisect']
14
15# Now we can import the module and get the pure Python implementation.
16import bisect as py_bisect
17
18# Restore everything to normal.
19del sys.modules['_bisect']
20del sys.modules['bisect']
21
22# This is now the module with the C implementation.
23import bisect as c_bisect
24
25
Raymond Hettingerd2305502003-01-16 12:02:35 +000026class TestBisect(unittest.TestCase):
Christian Heimesd3eb5a152008-02-24 00:38:49 +000027 module = None
Tim Peters36cdad12000-12-29 02:06:45 +000028
Christian Heimesd3eb5a152008-02-24 00:38:49 +000029 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),
Tim Peters36cdad12000-12-29 02:06:45 +000070
Christian Heimesd3eb5a152008-02-24 00:38:49 +000071 (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)
110 ]
Tim Peters36cdad12000-12-29 02:06:45 +0000111
Raymond Hettingerd2305502003-01-16 12:02:35 +0000112 def test_precomputed(self):
Raymond Hettinger6aa1c3f2003-01-16 14:00:15 +0000113 for func, data, elem, expected in self.precomputedCases:
114 self.assertEqual(func(data, elem), expected)
Raymond Hettinger0c410272004-01-05 10:13:35 +0000115 self.assertEqual(func(UserList(data), elem), expected)
Raymond Hettingerd2305502003-01-16 12:02:35 +0000116
Georg Brandl2ee470f2008-07-16 12:55:28 +0000117 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),
124
Raymond Hettinger6aa1c3f2003-01-16 14:00:15 +0000125 def test_random(self, n=25):
Raymond Hettinger44223752003-01-16 12:31:36 +0000126 from random import randrange
Guido van Rossum805365e2007-05-07 22:24:25 +0000127 for i in range(n):
128 data = [randrange(0, n, 2) for j in range(i)]
Raymond Hettinger44223752003-01-16 12:31:36 +0000129 data.sort()
Raymond Hettinger6aa1c3f2003-01-16 14:00:15 +0000130 elem = randrange(-1, n+1)
Christian Heimesd3eb5a152008-02-24 00:38:49 +0000131 ip = self.module.bisect_left(data, elem)
Raymond Hettinger44223752003-01-16 12:31:36 +0000132 if ip < len(data):
133 self.failUnless(elem <= data[ip])
134 if ip > 0:
135 self.failUnless(data[ip-1] < elem)
Christian Heimesd3eb5a152008-02-24 00:38:49 +0000136 ip = self.module.bisect_right(data, elem)
Raymond Hettinger44223752003-01-16 12:31:36 +0000137 if ip < len(data):
138 self.failUnless(elem < data[ip])
139 if ip > 0:
140 self.failUnless(data[ip-1] <= elem)
141
Raymond Hettingera9f18dc2003-01-16 13:02:25 +0000142 def test_optionalSlicing(self):
Raymond Hettinger6aa1c3f2003-01-16 14:00:15 +0000143 for func, data, elem, expected in self.precomputedCases:
Guido van Rossum805365e2007-05-07 22:24:25 +0000144 for lo in range(4):
Raymond Hettinger6aa1c3f2003-01-16 14:00:15 +0000145 lo = min(len(data), lo)
Guido van Rossum805365e2007-05-07 22:24:25 +0000146 for hi in range(3,8):
Raymond Hettinger6aa1c3f2003-01-16 14:00:15 +0000147 hi = min(len(data), hi)
148 ip = func(data, elem, lo, hi)
149 self.failUnless(lo <= ip <= hi)
Christian Heimesd3eb5a152008-02-24 00:38:49 +0000150 if func is self.module.bisect_left and ip < hi:
Raymond Hettinger6aa1c3f2003-01-16 14:00:15 +0000151 self.failUnless(elem <= data[ip])
Christian Heimesd3eb5a152008-02-24 00:38:49 +0000152 if func is self.module.bisect_left and ip > lo:
Raymond Hettinger6aa1c3f2003-01-16 14:00:15 +0000153 self.failUnless(data[ip-1] < elem)
Christian Heimesd3eb5a152008-02-24 00:38:49 +0000154 if func is self.module.bisect_right and ip < hi:
Raymond Hettinger6aa1c3f2003-01-16 14:00:15 +0000155 self.failUnless(elem < data[ip])
Christian Heimesd3eb5a152008-02-24 00:38:49 +0000156 if func is self.module.bisect_right and ip > lo:
Raymond Hettinger6aa1c3f2003-01-16 14:00:15 +0000157 self.failUnless(data[ip-1] <= elem)
158 self.assertEqual(ip, max(lo, min(hi, expected)))
Raymond Hettingera9f18dc2003-01-16 13:02:25 +0000159
160 def test_backcompatibility(self):
Christian Heimesd3eb5a152008-02-24 00:38:49 +0000161 self.assertEqual(self.module.bisect, self.module.bisect_right)
Raymond Hettingera9f18dc2003-01-16 13:02:25 +0000162
Raymond Hettingercc9a9512005-10-05 11:39:12 +0000163 def test_keyword_args(self):
164 data = [10, 20, 30, 40, 50]
Christian Heimesd3eb5a152008-02-24 00:38:49 +0000165 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)
Raymond Hettingercc9a9512005-10-05 11:39:12 +0000171 self.assertEqual(data, [10, 20, 25, 25, 25, 30, 40, 50])
172
Christian Heimesd3eb5a152008-02-24 00:38:49 +0000173class TestBisectPython(TestBisect):
174 module = py_bisect
175
176class TestBisectC(TestBisect):
177 module = c_bisect
178
Raymond Hettingerd2305502003-01-16 12:02:35 +0000179#==============================================================================
180
181class TestInsort(unittest.TestCase):
Christian Heimesd3eb5a152008-02-24 00:38:49 +0000182 module = None
Raymond Hettingerd2305502003-01-16 12:02:35 +0000183
Raymond Hettinger0c410272004-01-05 10:13:35 +0000184 def test_vsBuiltinSort(self, n=500):
Raymond Hettingerd2305502003-01-16 12:02:35 +0000185 from random import choice
Raymond Hettinger0c410272004-01-05 10:13:35 +0000186 for insorted in (list(), UserList()):
Guido van Rossum805365e2007-05-07 22:24:25 +0000187 for i in range(n):
Raymond Hettinger0c410272004-01-05 10:13:35 +0000188 digit = choice("0123456789")
189 if digit in "02468":
Christian Heimesd3eb5a152008-02-24 00:38:49 +0000190 f = self.module.insort_left
Raymond Hettinger0c410272004-01-05 10:13:35 +0000191 else:
Christian Heimesd3eb5a152008-02-24 00:38:49 +0000192 f = self.module.insort_right
Raymond Hettinger0c410272004-01-05 10:13:35 +0000193 f(insorted, digit)
194 self.assertEqual(sorted(insorted), insorted)
Raymond Hettingerd2305502003-01-16 12:02:35 +0000195
Raymond Hettingera9f18dc2003-01-16 13:02:25 +0000196 def test_backcompatibility(self):
Christian Heimesd3eb5a152008-02-24 00:38:49 +0000197 self.assertEqual(self.module.insort, self.module.insort_right)
198
199class TestInsortPython(TestInsort):
200 module = py_bisect
201
202class TestInsortC(TestInsort):
203 module = c_bisect
Raymond Hettingera9f18dc2003-01-16 13:02:25 +0000204
Raymond Hettingerd2305502003-01-16 12:02:35 +0000205#==============================================================================
206
Raymond Hettinger63251782004-09-27 22:48:40 +0000207
208class LenOnly:
209 "Dummy sequence class defining __len__ but not __getitem__."
210 def __len__(self):
211 return 10
212
213class GetOnly:
214 "Dummy sequence class defining __getitem__ but not __len__."
215 def __getitem__(self, ndx):
216 return 10
217
218class CmpErr:
219 "Dummy element that always raises an error during comparison"
Guido van Rossum47b9ff62006-08-24 00:41:19 +0000220 def __lt__(self, other):
Raymond Hettinger63251782004-09-27 22:48:40 +0000221 raise ZeroDivisionError
Guido van Rossum47b9ff62006-08-24 00:41:19 +0000222 __gt__ = __lt__
223 __le__ = __lt__
224 __ge__ = __lt__
225 __eq__ = __lt__
226 __ne__ = __lt__
Raymond Hettinger63251782004-09-27 22:48:40 +0000227
228class TestErrorHandling(unittest.TestCase):
Christian Heimesd3eb5a152008-02-24 00:38:49 +0000229 module = None
Raymond Hettinger63251782004-09-27 22:48:40 +0000230
231 def test_non_sequence(self):
Christian Heimesd3eb5a152008-02-24 00:38:49 +0000232 for f in (self.module.bisect_left, self.module.bisect_right,
233 self.module.insort_left, self.module.insort_right):
Raymond Hettinger63251782004-09-27 22:48:40 +0000234 self.assertRaises(TypeError, f, 10, 10)
235
236 def test_len_only(self):
Christian Heimesd3eb5a152008-02-24 00:38:49 +0000237 for f in (self.module.bisect_left, self.module.bisect_right,
238 self.module.insort_left, self.module.insort_right):
Thomas Wouters1ae9afa2006-04-15 09:12:14 +0000239 self.assertRaises(TypeError, f, LenOnly(), 10)
Raymond Hettinger63251782004-09-27 22:48:40 +0000240
241 def test_get_only(self):
Christian Heimesd3eb5a152008-02-24 00:38:49 +0000242 for f in (self.module.bisect_left, self.module.bisect_right,
243 self.module.insort_left, self.module.insort_right):
Thomas Wouters1ae9afa2006-04-15 09:12:14 +0000244 self.assertRaises(TypeError, f, GetOnly(), 10)
Raymond Hettinger63251782004-09-27 22:48:40 +0000245
Raymond Hettinger630e5352004-09-27 23:11:35 +0000246 def test_cmp_err(self):
Raymond Hettinger63251782004-09-27 22:48:40 +0000247 seq = [CmpErr(), CmpErr(), CmpErr()]
Christian Heimesd3eb5a152008-02-24 00:38:49 +0000248 for f in (self.module.bisect_left, self.module.bisect_right,
249 self.module.insort_left, self.module.insort_right):
Raymond Hettinger63251782004-09-27 22:48:40 +0000250 self.assertRaises(ZeroDivisionError, f, seq, 10)
251
252 def test_arg_parsing(self):
Christian Heimesd3eb5a152008-02-24 00:38:49 +0000253 for f in (self.module.bisect_left, self.module.bisect_right,
254 self.module.insort_left, self.module.insort_right):
Raymond Hettinger63251782004-09-27 22:48:40 +0000255 self.assertRaises(TypeError, f, 10)
256
Christian Heimesd3eb5a152008-02-24 00:38:49 +0000257class TestErrorHandlingPython(TestErrorHandling):
258 module = py_bisect
259
260class TestErrorHandlingC(TestErrorHandling):
261 module = c_bisect
262
Raymond Hettinger63251782004-09-27 22:48:40 +0000263#==============================================================================
264
Raymond Hettinger44223752003-01-16 12:31:36 +0000265libreftest = """
Christian Heimesd3eb5a152008-02-24 00:38:49 +0000266Example from the Library Reference: Doc/library/bisect.rst
Raymond Hettinger44223752003-01-16 12:31:36 +0000267
268The bisect() function is generally useful for categorizing numeric data.
269This example uses bisect() to look up a letter grade for an exam total
270(say) based on a set of ordered numeric breakpoints: 85 and up is an `A',
27175..84 is a `B', etc.
272
273 >>> grades = "FEDCBA"
274 >>> breakpoints = [30, 44, 66, 75, 85]
275 >>> from bisect import bisect
276 >>> def grade(total):
277 ... return grades[bisect(breakpoints, total)]
278 ...
279 >>> grade(66)
280 'C'
Guido van Rossumc1f779c2007-07-03 08:25:58 +0000281 >>> list(map(grade, [33, 99, 77, 44, 12, 88]))
Raymond Hettinger44223752003-01-16 12:31:36 +0000282 ['E', 'A', 'B', 'D', 'F', 'A']
283
Raymond Hettinger44223752003-01-16 12:31:36 +0000284"""
285
Raymond Hettingerd2305502003-01-16 12:02:35 +0000286#------------------------------------------------------------------------------
287
Raymond Hettinger44223752003-01-16 12:31:36 +0000288__test__ = {'libreftest' : libreftest}
289
Raymond Hettingerd2305502003-01-16 12:02:35 +0000290def test_main(verbose=None):
291 from test import test_bisect
Raymond Hettinger63251782004-09-27 22:48:40 +0000292
Christian Heimesd3eb5a152008-02-24 00:38:49 +0000293 test_classes = [TestBisectPython, TestBisectC,
294 TestInsortPython, TestInsortC,
295 TestErrorHandlingPython, TestErrorHandlingC]
Raymond Hettinger63251782004-09-27 22:48:40 +0000296
Benjamin Petersonee8712c2008-05-20 21:35:26 +0000297 support.run_unittest(*test_classes)
298 support.run_doctest(test_bisect, verbose)
Raymond Hettingerd2305502003-01-16 12:02:35 +0000299
Raymond Hettinger63251782004-09-27 22:48:40 +0000300 # verify reference counting
301 if verbose and hasattr(sys, "gettotalrefcount"):
302 import gc
303 counts = [None] * 5
Guido van Rossum805365e2007-05-07 22:24:25 +0000304 for i in range(len(counts)):
Benjamin Petersonee8712c2008-05-20 21:35:26 +0000305 support.run_unittest(*test_classes)
Raymond Hettinger63251782004-09-27 22:48:40 +0000306 gc.collect()
307 counts[i] = sys.gettotalrefcount()
Guido van Rossumbe19ed72007-02-09 05:37:30 +0000308 print(counts)
Raymond Hettinger63251782004-09-27 22:48:40 +0000309
Raymond Hettingerd2305502003-01-16 12:02:35 +0000310if __name__ == "__main__":
311 test_main(verbose=True)