blob: a7afe73d1c4a88c0a317e788a45d5cd75d2f5665 [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
Neal Norwitza98e7692005-11-24 21:58:51 +0000114 x = [Complains(i) for i in x]
115 s = x[:]
116 random.shuffle(s)
117 Complains.maybe_complain = True
118 it_complained = False
119 try:
120 s.sort()
121 except RuntimeError:
122 it_complained = True
123 if it_complained:
124 Complains.maybe_complain = False
125 check("exception during sort left some permutation", x, s)
Tim Peters2d8b7652002-08-01 02:23:06 +0000126
Guido van Rossum805365e2007-05-07 22:24:25 +0000127 s = [Stable(random.randrange(10), i) for i in range(n)]
Neal Norwitza98e7692005-11-24 21:58:51 +0000128 augmented = [(e, e.index) for e in s]
129 augmented.sort() # forced stable because ties broken by index
130 x = [e for e, i in augmented] # a stable sort of s
131 check("stability", x, s)
Tim Petersb9099c32002-11-12 22:08:10 +0000132
Raymond Hettinger42b1ba32003-10-16 03:41:09 +0000133#==============================================================================
Tim Petersb9099c32002-11-12 22:08:10 +0000134
Raymond Hettinger42b1ba32003-10-16 03:41:09 +0000135class TestBugs(unittest.TestCase):
Tim Petersb9099c32002-11-12 22:08:10 +0000136
Raymond Hettinger42b1ba32003-10-16 03:41:09 +0000137 def test_bug453523(self):
138 # bug 453523 -- list.sort() crasher.
139 # If this fails, the most likely outcome is a core dump.
140 # Mutations during a list sort should raise a ValueError.
Tim Petersb9099c32002-11-12 22:08:10 +0000141
Raymond Hettinger42b1ba32003-10-16 03:41:09 +0000142 class C:
143 def __lt__(self, other):
144 if L and random.random() < 0.75:
145 L.pop()
146 else:
147 L.append(3)
148 return random.random() < 0.5
Skip Montanaro4abd5f02003-01-02 20:51:08 +0000149
Raymond Hettinger42b1ba32003-10-16 03:41:09 +0000150 L = [C() for i in range(50)]
151 self.assertRaises(ValueError, L.sort)
Skip Montanaro4abd5f02003-01-02 20:51:08 +0000152
Armin Rigo93677f02004-07-29 12:40:23 +0000153 def test_undetected_mutation(self):
154 # Python 2.4a1 did not always detect mutation
155 memorywaster = []
156 for i in range(20):
157 def mutating_cmp(x, y):
158 L.append(3)
159 L.pop()
Mark Dickinsona56c4672009-01-27 18:17:45 +0000160 return (x > y) - (x < y)
Armin Rigo93677f02004-07-29 12:40:23 +0000161 L = [1,2]
Raymond Hettinger70b64fc2008-01-30 20:15:17 +0000162 self.assertRaises(ValueError, L.sort, key=CmpToKey(mutating_cmp))
Armin Rigo93677f02004-07-29 12:40:23 +0000163 def mutating_cmp(x, y):
164 L.append(3)
165 del L[:]
Mark Dickinsona56c4672009-01-27 18:17:45 +0000166 return (x > y) - (x < y)
Raymond Hettinger70b64fc2008-01-30 20:15:17 +0000167 self.assertRaises(ValueError, L.sort, key=CmpToKey(mutating_cmp))
Armin Rigo93677f02004-07-29 12:40:23 +0000168 memorywaster = [memorywaster]
169
Raymond Hettinger42b1ba32003-10-16 03:41:09 +0000170#==============================================================================
Skip Montanaro4abd5f02003-01-02 20:51:08 +0000171
Raymond Hettinger42b1ba32003-10-16 03:41:09 +0000172class TestDecorateSortUndecorate(unittest.TestCase):
173
174 def test_decorated(self):
175 data = 'The quick Brown fox Jumped over The lazy Dog'.split()
176 copy = data[:]
177 random.shuffle(data)
178 data.sort(key=str.lower)
Mark Dickinsona56c4672009-01-27 18:17:45 +0000179 def my_cmp(x, y):
180 xlower, ylower = x.lower(), y.lower()
181 return (xlower > ylower) - (xlower < ylower)
182 copy.sort(key=CmpToKey(my_cmp))
Raymond Hettinger42b1ba32003-10-16 03:41:09 +0000183
184 def test_baddecorator(self):
185 data = 'The quick Brown fox Jumped over The lazy Dog'.split()
Raymond Hettinger70b64fc2008-01-30 20:15:17 +0000186 self.assertRaises(TypeError, data.sort, key=lambda x,y: 0)
Raymond Hettinger42b1ba32003-10-16 03:41:09 +0000187
188 def test_stability(self):
Guido van Rossum805365e2007-05-07 22:24:25 +0000189 data = [(random.randrange(100), i) for i in range(200)]
Raymond Hettinger42b1ba32003-10-16 03:41:09 +0000190 copy = data[:]
Guido van Rossum1bc535d2007-05-15 18:46:22 +0000191 data.sort(key=lambda t: t[0]) # sort on the random first field
Raymond Hettinger42b1ba32003-10-16 03:41:09 +0000192 copy.sort() # sort using both fields
193 self.assertEqual(data, copy) # should get the same result
194
Raymond Hettinger37e13632003-11-28 21:43:02 +0000195 def test_key_with_exception(self):
196 # Verify that the wrapper has been removed
Guido van Rossum805365e2007-05-07 22:24:25 +0000197 data = list(range(-2, 2))
Raymond Hettinger37e13632003-11-28 21:43:02 +0000198 dup = data[:]
Raymond Hettinger70b64fc2008-01-30 20:15:17 +0000199 self.assertRaises(ZeroDivisionError, data.sort, key=lambda x: 1/x)
Raymond Hettinger37e13632003-11-28 21:43:02 +0000200 self.assertEqual(data, dup)
201
Michael W. Hudson1df0f652003-12-04 11:25:46 +0000202 def test_key_with_mutation(self):
Guido van Rossum805365e2007-05-07 22:24:25 +0000203 data = list(range(10))
Michael W. Hudson1df0f652003-12-04 11:25:46 +0000204 def k(x):
205 del data[:]
206 data[:] = range(20)
207 return x
208 self.assertRaises(ValueError, data.sort, key=k)
209
210 def test_key_with_mutating_del(self):
Guido van Rossum805365e2007-05-07 22:24:25 +0000211 data = list(range(10))
Michael W. Hudson1df0f652003-12-04 11:25:46 +0000212 class SortKiller(object):
213 def __init__(self, x):
214 pass
215 def __del__(self):
216 del data[:]
217 data[:] = range(20)
Guido van Rossum47b9ff62006-08-24 00:41:19 +0000218 def __lt__(self, other):
219 return id(self) < id(other)
Michael W. Hudson1df0f652003-12-04 11:25:46 +0000220 self.assertRaises(ValueError, data.sort, key=SortKiller)
221
222 def test_key_with_mutating_del_and_exception(self):
Guido van Rossum805365e2007-05-07 22:24:25 +0000223 data = list(range(10))
Michael W. Hudson1df0f652003-12-04 11:25:46 +0000224 ## dup = data[:]
225 class SortKiller(object):
226 def __init__(self, x):
227 if x > 2:
228 raise RuntimeError
229 def __del__(self):
230 del data[:]
Guido van Rossum805365e2007-05-07 22:24:25 +0000231 data[:] = list(range(20))
Michael W. Hudson1df0f652003-12-04 11:25:46 +0000232 self.assertRaises(RuntimeError, data.sort, key=SortKiller)
233 ## major honking subtlety: we *can't* do:
234 ##
235 ## self.assertEqual(data, dup)
236 ##
237 ## because there is a reference to a SortKiller in the
238 ## traceback and by the time it dies we're outside the call to
239 ## .sort() and so the list protection gimmicks are out of
240 ## date (this cost some brain cells to figure out...).
241
Raymond Hettinger42b1ba32003-10-16 03:41:09 +0000242 def test_reverse(self):
Guido van Rossum805365e2007-05-07 22:24:25 +0000243 data = list(range(100))
Raymond Hettinger42b1ba32003-10-16 03:41:09 +0000244 random.shuffle(data)
245 data.sort(reverse=True)
Guido van Rossum805365e2007-05-07 22:24:25 +0000246 self.assertEqual(data, list(range(99,-1,-1)))
Raymond Hettinger42b1ba32003-10-16 03:41:09 +0000247
248 def test_reverse_stability(self):
Guido van Rossum805365e2007-05-07 22:24:25 +0000249 data = [(random.randrange(100), i) for i in range(200)]
Raymond Hettinger42b1ba32003-10-16 03:41:09 +0000250 copy1 = data[:]
251 copy2 = data[:]
Mark Dickinsona56c4672009-01-27 18:17:45 +0000252 def my_cmp(x, y):
253 x0, y0 = x[0], y[0]
254 return (x0 > y0) - (x0 < y0)
255 def my_cmp_reversed(x, y):
256 x0, y0 = x[0], y[0]
257 return (y0 > x0) - (y0 < x0)
258 data.sort(key=CmpToKey(my_cmp), reverse=True)
259 copy1.sort(key=CmpToKey(my_cmp_reversed))
Raymond Hettinger42b1ba32003-10-16 03:41:09 +0000260 self.assertEqual(data, copy1)
261 copy2.sort(key=lambda x: x[0], reverse=True)
262 self.assertEqual(data, copy2)
263
264#==============================================================================
265
266def test_main(verbose=None):
267 test_classes = (
Neal Norwitza98e7692005-11-24 21:58:51 +0000268 TestBase,
Raymond Hettinger42b1ba32003-10-16 03:41:09 +0000269 TestDecorateSortUndecorate,
270 TestBugs,
271 )
272
Benjamin Petersonee8712c2008-05-20 21:35:26 +0000273 support.run_unittest(*test_classes)
Raymond Hettinger42b1ba32003-10-16 03:41:09 +0000274
275 # verify reference counting
276 if verbose and hasattr(sys, "gettotalrefcount"):
277 import gc
278 counts = [None] * 5
Guido van Rossum805365e2007-05-07 22:24:25 +0000279 for i in range(len(counts)):
Benjamin Petersonee8712c2008-05-20 21:35:26 +0000280 support.run_unittest(*test_classes)
Raymond Hettinger42b1ba32003-10-16 03:41:09 +0000281 gc.collect()
282 counts[i] = sys.gettotalrefcount()
Guido van Rossumbe19ed72007-02-09 05:37:30 +0000283 print(counts)
Raymond Hettinger42b1ba32003-10-16 03:41:09 +0000284
285if __name__ == "__main__":
286 test_main(verbose=True)