blob: 55503b57a80ed0b27b17d6bab23bc7537de26892 [file] [log] [blame]
Benjamin Petersonee8712c2008-05-20 21:35:26 +00001from test import support
Tim Peters2d8b7652002-08-01 02:23:06 +00002import random
Neal Norwitza98e7692005-11-24 21:58:51 +00003import sys
4import unittest
Tim Peters2d8b7652002-08-01 02:23:06 +00005
Benjamin Petersonee8712c2008-05-20 21:35:26 +00006verbose = support.verbose
Tim Peters2d8b7652002-08-01 02:23:06 +00007nerrors = 0
8
Raymond Hettinger70b64fc2008-01-30 20:15:17 +00009def CmpToKey(mycmp):
10 'Convert a cmp= function into a key= function'
11 class K(object):
12 def __init__(self, obj):
13 self.obj = obj
14 def __lt__(self, other):
15 return mycmp(self.obj, other.obj) == -1
16 return K
17
Tim Peters2d8b7652002-08-01 02:23:06 +000018def check(tag, expected, raw, compare=None):
19 global nerrors
20
21 if verbose:
Guido van Rossumbe19ed72007-02-09 05:37:30 +000022 print(" checking", tag)
Tim Peters2d8b7652002-08-01 02:23:06 +000023
24 orig = raw[:] # save input in case of error
25 if compare:
Raymond Hettinger70b64fc2008-01-30 20:15:17 +000026 raw.sort(key=CmpToKey(compare))
Tim Peters2d8b7652002-08-01 02:23:06 +000027 else:
28 raw.sort()
29
30 if len(expected) != len(raw):
Guido van Rossumbe19ed72007-02-09 05:37:30 +000031 print("error in", tag)
32 print("length mismatch;", len(expected), len(raw))
33 print(expected)
34 print(orig)
35 print(raw)
Tim Peters2d8b7652002-08-01 02:23:06 +000036 nerrors += 1
37 return
38
39 for i, good in enumerate(expected):
40 maybe = raw[i]
41 if good is not maybe:
Guido van Rossumbe19ed72007-02-09 05:37:30 +000042 print("error in", tag)
43 print("out of order at index", i, good, maybe)
44 print(expected)
45 print(orig)
46 print(raw)
Tim Peters2d8b7652002-08-01 02:23:06 +000047 nerrors += 1
48 return
49
Neal Norwitza98e7692005-11-24 21:58:51 +000050class TestBase(unittest.TestCase):
51 def testStressfully(self):
52 # Try a variety of sizes at and around powers of 2, and at powers of 10.
53 sizes = [0]
54 for power in range(1, 10):
55 n = 2 ** power
56 sizes.extend(range(n-1, n+2))
57 sizes.extend([10, 100, 1000])
Tim Peters2d8b7652002-08-01 02:23:06 +000058
Neal Norwitza98e7692005-11-24 21:58:51 +000059 class Complains(object):
60 maybe_complain = True
Tim Peters2d8b7652002-08-01 02:23:06 +000061
Neal Norwitza98e7692005-11-24 21:58:51 +000062 def __init__(self, i):
63 self.i = i
Tim Peters2d8b7652002-08-01 02:23:06 +000064
Neal Norwitza98e7692005-11-24 21:58:51 +000065 def __lt__(self, other):
66 if Complains.maybe_complain and random.random() < 0.001:
67 if verbose:
Guido van Rossumbe19ed72007-02-09 05:37:30 +000068 print(" complaining at", self, other)
Neal Norwitza98e7692005-11-24 21:58:51 +000069 raise RuntimeError
70 return self.i < other.i
71
72 def __repr__(self):
73 return "Complains(%d)" % self.i
74
75 class Stable(object):
76 def __init__(self, key, i):
77 self.key = key
78 self.index = i
79
Guido van Rossum47b9ff62006-08-24 00:41:19 +000080 def __lt__(self, other):
81 return self.key < other.key
Neal Norwitza98e7692005-11-24 21:58:51 +000082
83 def __repr__(self):
84 return "Stable(%d, %d)" % (self.key, self.index)
85
86 for n in sizes:
Guido van Rossum805365e2007-05-07 22:24:25 +000087 x = list(range(n))
Tim Peters2d8b7652002-08-01 02:23:06 +000088 if verbose:
Guido van Rossumbe19ed72007-02-09 05:37:30 +000089 print("Testing size", n)
Tim Peters2d8b7652002-08-01 02:23:06 +000090
Neal Norwitza98e7692005-11-24 21:58:51 +000091 s = x[:]
92 check("identity", x, s)
Tim Peters2d8b7652002-08-01 02:23:06 +000093
Neal Norwitza98e7692005-11-24 21:58:51 +000094 s = x[:]
95 s.reverse()
96 check("reversed", x, s)
Tim Peters2d8b7652002-08-01 02:23:06 +000097
Neal Norwitza98e7692005-11-24 21:58:51 +000098 s = x[:]
99 random.shuffle(s)
100 check("random permutation", x, s)
Tim Peters2d8b7652002-08-01 02:23:06 +0000101
Neal Norwitza98e7692005-11-24 21:58:51 +0000102 y = x[:]
103 y.reverse()
104 s = x[:]
Mark Dickinsona56c4672009-01-27 18:17:45 +0000105 check("reversed via function", y, s, lambda a, b: (b>a)-(b<a))
Tim Peters2d8b7652002-08-01 02:23:06 +0000106
Neal Norwitza98e7692005-11-24 21:58:51 +0000107 if verbose:
Guido van Rossumbe19ed72007-02-09 05:37:30 +0000108 print(" Checking against an insane comparison function.")
109 print(" If the implementation isn't careful, this may segfault.")
Neal Norwitza98e7692005-11-24 21:58:51 +0000110 s = x[:]
Raymond Hettinger70b64fc2008-01-30 20:15:17 +0000111 s.sort(key=CmpToKey(lambda a, b: int(random.random() * 3) - 1))
Neal Norwitza98e7692005-11-24 21:58:51 +0000112 check("an insane function left some permutation", x, s)
Tim Peters2d8b7652002-08-01 02:23:06 +0000113
Daniel Stutzbacheda70b82011-05-04 12:46:28 -0700114 if len(x) >= 2:
115 def bad_key(x):
116 raise RuntimeError
117 s = x[:]
118 self.assertRaises(RuntimeError, s.sort, key=bad_key)
119
Neal Norwitza98e7692005-11-24 21:58:51 +0000120 x = [Complains(i) for i in x]
121 s = x[:]
122 random.shuffle(s)
123 Complains.maybe_complain = True
124 it_complained = False
125 try:
126 s.sort()
127 except RuntimeError:
128 it_complained = True
129 if it_complained:
130 Complains.maybe_complain = False
131 check("exception during sort left some permutation", x, s)
Tim Peters2d8b7652002-08-01 02:23:06 +0000132
Guido van Rossum805365e2007-05-07 22:24:25 +0000133 s = [Stable(random.randrange(10), i) for i in range(n)]
Neal Norwitza98e7692005-11-24 21:58:51 +0000134 augmented = [(e, e.index) for e in s]
135 augmented.sort() # forced stable because ties broken by index
136 x = [e for e, i in augmented] # a stable sort of s
137 check("stability", x, s)
Tim Petersb9099c32002-11-12 22:08:10 +0000138
Raymond Hettinger42b1ba32003-10-16 03:41:09 +0000139#==============================================================================
Tim Petersb9099c32002-11-12 22:08:10 +0000140
Raymond Hettinger42b1ba32003-10-16 03:41:09 +0000141class TestBugs(unittest.TestCase):
Tim Petersb9099c32002-11-12 22:08:10 +0000142
Raymond Hettinger42b1ba32003-10-16 03:41:09 +0000143 def test_bug453523(self):
144 # bug 453523 -- list.sort() crasher.
145 # If this fails, the most likely outcome is a core dump.
146 # Mutations during a list sort should raise a ValueError.
Tim Petersb9099c32002-11-12 22:08:10 +0000147
Raymond Hettinger42b1ba32003-10-16 03:41:09 +0000148 class C:
149 def __lt__(self, other):
150 if L and random.random() < 0.75:
151 L.pop()
152 else:
153 L.append(3)
154 return random.random() < 0.5
Skip Montanaro4abd5f02003-01-02 20:51:08 +0000155
Raymond Hettinger42b1ba32003-10-16 03:41:09 +0000156 L = [C() for i in range(50)]
157 self.assertRaises(ValueError, L.sort)
Skip Montanaro4abd5f02003-01-02 20:51:08 +0000158
Armin Rigo93677f02004-07-29 12:40:23 +0000159 def test_undetected_mutation(self):
160 # Python 2.4a1 did not always detect mutation
161 memorywaster = []
162 for i in range(20):
163 def mutating_cmp(x, y):
164 L.append(3)
165 L.pop()
Mark Dickinsona56c4672009-01-27 18:17:45 +0000166 return (x > y) - (x < y)
Armin Rigo93677f02004-07-29 12:40:23 +0000167 L = [1,2]
Raymond Hettinger70b64fc2008-01-30 20:15:17 +0000168 self.assertRaises(ValueError, L.sort, key=CmpToKey(mutating_cmp))
Armin Rigo93677f02004-07-29 12:40:23 +0000169 def mutating_cmp(x, y):
170 L.append(3)
171 del L[:]
Mark Dickinsona56c4672009-01-27 18:17:45 +0000172 return (x > y) - (x < y)
Raymond Hettinger70b64fc2008-01-30 20:15:17 +0000173 self.assertRaises(ValueError, L.sort, key=CmpToKey(mutating_cmp))
Armin Rigo93677f02004-07-29 12:40:23 +0000174 memorywaster = [memorywaster]
175
Raymond Hettinger42b1ba32003-10-16 03:41:09 +0000176#==============================================================================
Skip Montanaro4abd5f02003-01-02 20:51:08 +0000177
Raymond Hettinger42b1ba32003-10-16 03:41:09 +0000178class TestDecorateSortUndecorate(unittest.TestCase):
179
180 def test_decorated(self):
181 data = 'The quick Brown fox Jumped over The lazy Dog'.split()
182 copy = data[:]
183 random.shuffle(data)
184 data.sort(key=str.lower)
Mark Dickinsona56c4672009-01-27 18:17:45 +0000185 def my_cmp(x, y):
186 xlower, ylower = x.lower(), y.lower()
187 return (xlower > ylower) - (xlower < ylower)
188 copy.sort(key=CmpToKey(my_cmp))
Raymond Hettinger42b1ba32003-10-16 03:41:09 +0000189
190 def test_baddecorator(self):
191 data = 'The quick Brown fox Jumped over The lazy Dog'.split()
Raymond Hettinger70b64fc2008-01-30 20:15:17 +0000192 self.assertRaises(TypeError, data.sort, key=lambda x,y: 0)
Raymond Hettinger42b1ba32003-10-16 03:41:09 +0000193
194 def test_stability(self):
Guido van Rossum805365e2007-05-07 22:24:25 +0000195 data = [(random.randrange(100), i) for i in range(200)]
Raymond Hettinger42b1ba32003-10-16 03:41:09 +0000196 copy = data[:]
Guido van Rossum1bc535d2007-05-15 18:46:22 +0000197 data.sort(key=lambda t: t[0]) # sort on the random first field
Raymond Hettinger42b1ba32003-10-16 03:41:09 +0000198 copy.sort() # sort using both fields
199 self.assertEqual(data, copy) # should get the same result
200
Raymond Hettinger37e13632003-11-28 21:43:02 +0000201 def test_key_with_exception(self):
202 # Verify that the wrapper has been removed
Guido van Rossum805365e2007-05-07 22:24:25 +0000203 data = list(range(-2, 2))
Raymond Hettinger37e13632003-11-28 21:43:02 +0000204 dup = data[:]
Raymond Hettinger70b64fc2008-01-30 20:15:17 +0000205 self.assertRaises(ZeroDivisionError, data.sort, key=lambda x: 1/x)
Raymond Hettinger37e13632003-11-28 21:43:02 +0000206 self.assertEqual(data, dup)
207
Michael W. Hudson1df0f652003-12-04 11:25:46 +0000208 def test_key_with_mutation(self):
Guido van Rossum805365e2007-05-07 22:24:25 +0000209 data = list(range(10))
Michael W. Hudson1df0f652003-12-04 11:25:46 +0000210 def k(x):
211 del data[:]
212 data[:] = range(20)
213 return x
214 self.assertRaises(ValueError, data.sort, key=k)
215
216 def test_key_with_mutating_del(self):
Guido van Rossum805365e2007-05-07 22:24:25 +0000217 data = list(range(10))
Michael W. Hudson1df0f652003-12-04 11:25:46 +0000218 class SortKiller(object):
219 def __init__(self, x):
220 pass
221 def __del__(self):
222 del data[:]
223 data[:] = range(20)
Guido van Rossum47b9ff62006-08-24 00:41:19 +0000224 def __lt__(self, other):
225 return id(self) < id(other)
Michael W. Hudson1df0f652003-12-04 11:25:46 +0000226 self.assertRaises(ValueError, data.sort, key=SortKiller)
227
228 def test_key_with_mutating_del_and_exception(self):
Guido van Rossum805365e2007-05-07 22:24:25 +0000229 data = list(range(10))
Michael W. Hudson1df0f652003-12-04 11:25:46 +0000230 ## dup = data[:]
231 class SortKiller(object):
232 def __init__(self, x):
233 if x > 2:
234 raise RuntimeError
235 def __del__(self):
236 del data[:]
Guido van Rossum805365e2007-05-07 22:24:25 +0000237 data[:] = list(range(20))
Michael W. Hudson1df0f652003-12-04 11:25:46 +0000238 self.assertRaises(RuntimeError, data.sort, key=SortKiller)
239 ## major honking subtlety: we *can't* do:
240 ##
241 ## self.assertEqual(data, dup)
242 ##
243 ## because there is a reference to a SortKiller in the
244 ## traceback and by the time it dies we're outside the call to
245 ## .sort() and so the list protection gimmicks are out of
246 ## date (this cost some brain cells to figure out...).
247
Raymond Hettinger42b1ba32003-10-16 03:41:09 +0000248 def test_reverse(self):
Guido van Rossum805365e2007-05-07 22:24:25 +0000249 data = list(range(100))
Raymond Hettinger42b1ba32003-10-16 03:41:09 +0000250 random.shuffle(data)
251 data.sort(reverse=True)
Guido van Rossum805365e2007-05-07 22:24:25 +0000252 self.assertEqual(data, list(range(99,-1,-1)))
Raymond Hettinger42b1ba32003-10-16 03:41:09 +0000253
254 def test_reverse_stability(self):
Guido van Rossum805365e2007-05-07 22:24:25 +0000255 data = [(random.randrange(100), i) for i in range(200)]
Raymond Hettinger42b1ba32003-10-16 03:41:09 +0000256 copy1 = data[:]
257 copy2 = data[:]
Mark Dickinsona56c4672009-01-27 18:17:45 +0000258 def my_cmp(x, y):
259 x0, y0 = x[0], y[0]
260 return (x0 > y0) - (x0 < y0)
261 def my_cmp_reversed(x, y):
262 x0, y0 = x[0], y[0]
263 return (y0 > x0) - (y0 < x0)
264 data.sort(key=CmpToKey(my_cmp), reverse=True)
265 copy1.sort(key=CmpToKey(my_cmp_reversed))
Raymond Hettinger42b1ba32003-10-16 03:41:09 +0000266 self.assertEqual(data, copy1)
267 copy2.sort(key=lambda x: x[0], reverse=True)
268 self.assertEqual(data, copy2)
269
270#==============================================================================
271
272def test_main(verbose=None):
273 test_classes = (
Neal Norwitza98e7692005-11-24 21:58:51 +0000274 TestBase,
Raymond Hettinger42b1ba32003-10-16 03:41:09 +0000275 TestDecorateSortUndecorate,
276 TestBugs,
277 )
278
Benjamin Petersonee8712c2008-05-20 21:35:26 +0000279 support.run_unittest(*test_classes)
Raymond Hettinger42b1ba32003-10-16 03:41:09 +0000280
281 # verify reference counting
282 if verbose and hasattr(sys, "gettotalrefcount"):
283 import gc
284 counts = [None] * 5
Guido van Rossum805365e2007-05-07 22:24:25 +0000285 for i in range(len(counts)):
Benjamin Petersonee8712c2008-05-20 21:35:26 +0000286 support.run_unittest(*test_classes)
Raymond Hettinger42b1ba32003-10-16 03:41:09 +0000287 gc.collect()
288 counts[i] = sys.gettotalrefcount()
Guido van Rossumbe19ed72007-02-09 05:37:30 +0000289 print(counts)
Raymond Hettinger42b1ba32003-10-16 03:41:09 +0000290
291if __name__ == "__main__":
292 test_main(verbose=True)