blob: 1d62352f171ee7d788f6112644595a1b06a900ac [file] [log] [blame]
Raymond Hettingerd2305502003-01-16 12:02:35 +00001import unittest
2from test import test_support
Raymond Hettingera9f18dc2003-01-16 13:02:25 +00003from bisect import bisect_right, bisect_left, insort_left, insort_right, insort, bisect
Raymond Hettinger0c410272004-01-05 10:13:35 +00004from UserList import UserList
Tim Peters36cdad12000-12-29 02:06:45 +00005
Raymond Hettingerd2305502003-01-16 12:02:35 +00006class TestBisect(unittest.TestCase):
Tim Peters36cdad12000-12-29 02:06:45 +00007
Raymond Hettingerd2305502003-01-16 12:02:35 +00008 precomputedCases = [
9 (bisect_right, [], 1, 0),
10 (bisect_right, [1], 0, 0),
11 (bisect_right, [1], 1, 1),
12 (bisect_right, [1], 2, 1),
13 (bisect_right, [1, 1], 0, 0),
14 (bisect_right, [1, 1], 1, 2),
15 (bisect_right, [1, 1], 2, 2),
16 (bisect_right, [1, 1, 1], 0, 0),
17 (bisect_right, [1, 1, 1], 1, 3),
18 (bisect_right, [1, 1, 1], 2, 3),
19 (bisect_right, [1, 1, 1, 1], 0, 0),
20 (bisect_right, [1, 1, 1, 1], 1, 4),
21 (bisect_right, [1, 1, 1, 1], 2, 4),
22 (bisect_right, [1, 2], 0, 0),
23 (bisect_right, [1, 2], 1, 1),
24 (bisect_right, [1, 2], 1.5, 1),
25 (bisect_right, [1, 2], 2, 2),
26 (bisect_right, [1, 2], 3, 2),
27 (bisect_right, [1, 1, 2, 2], 0, 0),
28 (bisect_right, [1, 1, 2, 2], 1, 2),
29 (bisect_right, [1, 1, 2, 2], 1.5, 2),
30 (bisect_right, [1, 1, 2, 2], 2, 4),
31 (bisect_right, [1, 1, 2, 2], 3, 4),
32 (bisect_right, [1, 2, 3], 0, 0),
33 (bisect_right, [1, 2, 3], 1, 1),
34 (bisect_right, [1, 2, 3], 1.5, 1),
35 (bisect_right, [1, 2, 3], 2, 2),
36 (bisect_right, [1, 2, 3], 2.5, 2),
37 (bisect_right, [1, 2, 3], 3, 3),
38 (bisect_right, [1, 2, 3], 4, 3),
39 (bisect_right, [1, 2, 2, 3, 3, 3, 4, 4, 4, 4], 0, 0),
40 (bisect_right, [1, 2, 2, 3, 3, 3, 4, 4, 4, 4], 1, 1),
41 (bisect_right, [1, 2, 2, 3, 3, 3, 4, 4, 4, 4], 1.5, 1),
42 (bisect_right, [1, 2, 2, 3, 3, 3, 4, 4, 4, 4], 2, 3),
43 (bisect_right, [1, 2, 2, 3, 3, 3, 4, 4, 4, 4], 2.5, 3),
44 (bisect_right, [1, 2, 2, 3, 3, 3, 4, 4, 4, 4], 3, 6),
45 (bisect_right, [1, 2, 2, 3, 3, 3, 4, 4, 4, 4], 3.5, 6),
46 (bisect_right, [1, 2, 2, 3, 3, 3, 4, 4, 4, 4], 4, 10),
47 (bisect_right, [1, 2, 2, 3, 3, 3, 4, 4, 4, 4], 5, 10),
Tim Peters36cdad12000-12-29 02:06:45 +000048
Raymond Hettingerd2305502003-01-16 12:02:35 +000049 (bisect_left, [], 1, 0),
50 (bisect_left, [1], 0, 0),
51 (bisect_left, [1], 1, 0),
52 (bisect_left, [1], 2, 1),
53 (bisect_left, [1, 1], 0, 0),
54 (bisect_left, [1, 1], 1, 0),
55 (bisect_left, [1, 1], 2, 2),
56 (bisect_left, [1, 1, 1], 0, 0),
57 (bisect_left, [1, 1, 1], 1, 0),
58 (bisect_left, [1, 1, 1], 2, 3),
59 (bisect_left, [1, 1, 1, 1], 0, 0),
60 (bisect_left, [1, 1, 1, 1], 1, 0),
61 (bisect_left, [1, 1, 1, 1], 2, 4),
62 (bisect_left, [1, 2], 0, 0),
63 (bisect_left, [1, 2], 1, 0),
64 (bisect_left, [1, 2], 1.5, 1),
65 (bisect_left, [1, 2], 2, 1),
66 (bisect_left, [1, 2], 3, 2),
67 (bisect_left, [1, 1, 2, 2], 0, 0),
68 (bisect_left, [1, 1, 2, 2], 1, 0),
69 (bisect_left, [1, 1, 2, 2], 1.5, 2),
70 (bisect_left, [1, 1, 2, 2], 2, 2),
71 (bisect_left, [1, 1, 2, 2], 3, 4),
72 (bisect_left, [1, 2, 3], 0, 0),
73 (bisect_left, [1, 2, 3], 1, 0),
74 (bisect_left, [1, 2, 3], 1.5, 1),
75 (bisect_left, [1, 2, 3], 2, 1),
76 (bisect_left, [1, 2, 3], 2.5, 2),
77 (bisect_left, [1, 2, 3], 3, 2),
78 (bisect_left, [1, 2, 3], 4, 3),
79 (bisect_left, [1, 2, 2, 3, 3, 3, 4, 4, 4, 4], 0, 0),
80 (bisect_left, [1, 2, 2, 3, 3, 3, 4, 4, 4, 4], 1, 0),
81 (bisect_left, [1, 2, 2, 3, 3, 3, 4, 4, 4, 4], 1.5, 1),
82 (bisect_left, [1, 2, 2, 3, 3, 3, 4, 4, 4, 4], 2, 1),
83 (bisect_left, [1, 2, 2, 3, 3, 3, 4, 4, 4, 4], 2.5, 3),
84 (bisect_left, [1, 2, 2, 3, 3, 3, 4, 4, 4, 4], 3, 3),
85 (bisect_left, [1, 2, 2, 3, 3, 3, 4, 4, 4, 4], 3.5, 6),
86 (bisect_left, [1, 2, 2, 3, 3, 3, 4, 4, 4, 4], 4, 6),
87 (bisect_left, [1, 2, 2, 3, 3, 3, 4, 4, 4, 4], 5, 10)
88 ]
Tim Peters36cdad12000-12-29 02:06:45 +000089
Raymond Hettingerd2305502003-01-16 12:02:35 +000090 def test_precomputed(self):
Raymond Hettinger6aa1c3f2003-01-16 14:00:15 +000091 for func, data, elem, expected in self.precomputedCases:
92 self.assertEqual(func(data, elem), expected)
Raymond Hettinger0c410272004-01-05 10:13:35 +000093 self.assertEqual(func(UserList(data), elem), expected)
Raymond Hettingerd2305502003-01-16 12:02:35 +000094
Raymond Hettinger6aa1c3f2003-01-16 14:00:15 +000095 def test_random(self, n=25):
Raymond Hettinger44223752003-01-16 12:31:36 +000096 from random import randrange
97 for i in xrange(n):
98 data = [randrange(0, n, 2) for j in xrange(i)]
99 data.sort()
Raymond Hettinger6aa1c3f2003-01-16 14:00:15 +0000100 elem = randrange(-1, n+1)
Raymond Hettinger44223752003-01-16 12:31:36 +0000101 ip = bisect_left(data, elem)
102 if ip < len(data):
103 self.failUnless(elem <= data[ip])
104 if ip > 0:
105 self.failUnless(data[ip-1] < elem)
106 ip = bisect_right(data, elem)
107 if ip < len(data):
108 self.failUnless(elem < data[ip])
109 if ip > 0:
110 self.failUnless(data[ip-1] <= elem)
111
Raymond Hettingera9f18dc2003-01-16 13:02:25 +0000112 def test_optionalSlicing(self):
Raymond Hettinger6aa1c3f2003-01-16 14:00:15 +0000113 for func, data, elem, expected in self.precomputedCases:
114 for lo in xrange(4):
115 lo = min(len(data), lo)
116 for hi in xrange(3,8):
117 hi = min(len(data), hi)
118 ip = func(data, elem, lo, hi)
119 self.failUnless(lo <= ip <= hi)
120 if func is bisect_left and ip < hi:
121 self.failUnless(elem <= data[ip])
122 if func is bisect_left and ip > lo:
123 self.failUnless(data[ip-1] < elem)
124 if func is bisect_right and ip < hi:
125 self.failUnless(elem < data[ip])
126 if func is bisect_right and ip > lo:
127 self.failUnless(data[ip-1] <= elem)
128 self.assertEqual(ip, max(lo, min(hi, expected)))
Raymond Hettingera9f18dc2003-01-16 13:02:25 +0000129
130 def test_backcompatibility(self):
131 self.assertEqual(bisect, bisect_right)
132
Raymond Hettingercc9a9512005-10-05 11:39:12 +0000133 def test_keyword_args(self):
134 data = [10, 20, 30, 40, 50]
135 self.assertEqual(bisect_left(a=data, x=25, lo=1, hi=3), 2)
136 self.assertEqual(bisect_right(a=data, x=25, lo=1, hi=3), 2)
137 self.assertEqual(bisect(a=data, x=25, lo=1, hi=3), 2)
138 insort_left(a=data, x=25, lo=1, hi=3)
139 insort_right(a=data, x=25, lo=1, hi=3)
140 insort(a=data, x=25, lo=1, hi=3)
141 self.assertEqual(data, [10, 20, 25, 25, 25, 30, 40, 50])
142
Raymond Hettingerd2305502003-01-16 12:02:35 +0000143#==============================================================================
144
145class TestInsort(unittest.TestCase):
146
Raymond Hettinger0c410272004-01-05 10:13:35 +0000147 def test_vsBuiltinSort(self, n=500):
Raymond Hettingerd2305502003-01-16 12:02:35 +0000148 from random import choice
Raymond Hettinger0c410272004-01-05 10:13:35 +0000149 for insorted in (list(), UserList()):
150 for i in xrange(n):
151 digit = choice("0123456789")
152 if digit in "02468":
153 f = insort_left
154 else:
155 f = insort_right
156 f(insorted, digit)
157 self.assertEqual(sorted(insorted), insorted)
Raymond Hettingerd2305502003-01-16 12:02:35 +0000158
Raymond Hettingera9f18dc2003-01-16 13:02:25 +0000159 def test_backcompatibility(self):
160 self.assertEqual(insort, insort_right)
161
Raymond Hettingerd2305502003-01-16 12:02:35 +0000162#==============================================================================
163
Raymond Hettinger63251782004-09-27 22:48:40 +0000164
165class LenOnly:
166 "Dummy sequence class defining __len__ but not __getitem__."
167 def __len__(self):
168 return 10
169
170class GetOnly:
171 "Dummy sequence class defining __getitem__ but not __len__."
172 def __getitem__(self, ndx):
173 return 10
174
175class CmpErr:
176 "Dummy element that always raises an error during comparison"
Guido van Rossum47b9ff62006-08-24 00:41:19 +0000177 def __lt__(self, other):
Raymond Hettinger63251782004-09-27 22:48:40 +0000178 raise ZeroDivisionError
Guido van Rossum47b9ff62006-08-24 00:41:19 +0000179 __gt__ = __lt__
180 __le__ = __lt__
181 __ge__ = __lt__
182 __eq__ = __lt__
183 __ne__ = __lt__
Raymond Hettinger63251782004-09-27 22:48:40 +0000184
185class TestErrorHandling(unittest.TestCase):
186
187 def test_non_sequence(self):
188 for f in (bisect_left, bisect_right, insort_left, insort_right):
189 self.assertRaises(TypeError, f, 10, 10)
190
191 def test_len_only(self):
192 for f in (bisect_left, bisect_right, insort_left, insort_right):
Thomas Wouters1ae9afa2006-04-15 09:12:14 +0000193 self.assertRaises(TypeError, f, LenOnly(), 10)
Raymond Hettinger63251782004-09-27 22:48:40 +0000194
195 def test_get_only(self):
196 for f in (bisect_left, bisect_right, insort_left, insort_right):
Thomas Wouters1ae9afa2006-04-15 09:12:14 +0000197 self.assertRaises(TypeError, f, GetOnly(), 10)
Raymond Hettinger63251782004-09-27 22:48:40 +0000198
Raymond Hettinger630e5352004-09-27 23:11:35 +0000199 def test_cmp_err(self):
Raymond Hettinger63251782004-09-27 22:48:40 +0000200 seq = [CmpErr(), CmpErr(), CmpErr()]
201 for f in (bisect_left, bisect_right, insort_left, insort_right):
202 self.assertRaises(ZeroDivisionError, f, seq, 10)
203
204 def test_arg_parsing(self):
205 for f in (bisect_left, bisect_right, insort_left, insort_right):
206 self.assertRaises(TypeError, f, 10)
207
208#==============================================================================
209
Raymond Hettinger44223752003-01-16 12:31:36 +0000210libreftest = """
211Example from the Library Reference: Doc/lib/libbisect.tex
212
213The bisect() function is generally useful for categorizing numeric data.
214This example uses bisect() to look up a letter grade for an exam total
215(say) based on a set of ordered numeric breakpoints: 85 and up is an `A',
21675..84 is a `B', etc.
217
218 >>> grades = "FEDCBA"
219 >>> breakpoints = [30, 44, 66, 75, 85]
220 >>> from bisect import bisect
221 >>> def grade(total):
222 ... return grades[bisect(breakpoints, total)]
223 ...
224 >>> grade(66)
225 'C'
226 >>> map(grade, [33, 99, 77, 44, 12, 88])
227 ['E', 'A', 'B', 'D', 'F', 'A']
228
Raymond Hettinger44223752003-01-16 12:31:36 +0000229"""
230
Raymond Hettingerd2305502003-01-16 12:02:35 +0000231#------------------------------------------------------------------------------
232
Raymond Hettinger44223752003-01-16 12:31:36 +0000233__test__ = {'libreftest' : libreftest}
234
Raymond Hettingerd2305502003-01-16 12:02:35 +0000235def test_main(verbose=None):
236 from test import test_bisect
Raymond Hettinger63251782004-09-27 22:48:40 +0000237 from types import BuiltinFunctionType
238 import sys
239
240 test_classes = [TestBisect, TestInsort]
241 if isinstance(bisect_left, BuiltinFunctionType):
242 test_classes.append(TestErrorHandling)
243
244 test_support.run_unittest(*test_classes)
Raymond Hettinger44223752003-01-16 12:31:36 +0000245 test_support.run_doctest(test_bisect, verbose)
Raymond Hettingerd2305502003-01-16 12:02:35 +0000246
Raymond Hettinger63251782004-09-27 22:48:40 +0000247 # verify reference counting
248 if verbose and hasattr(sys, "gettotalrefcount"):
249 import gc
250 counts = [None] * 5
251 for i in xrange(len(counts)):
252 test_support.run_unittest(*test_classes)
253 gc.collect()
254 counts[i] = sys.gettotalrefcount()
Guido van Rossumbe19ed72007-02-09 05:37:30 +0000255 print(counts)
Raymond Hettinger63251782004-09-27 22:48:40 +0000256
Raymond Hettingerd2305502003-01-16 12:02:35 +0000257if __name__ == "__main__":
258 test_main(verbose=True)