blob: 8b108d59a3c154b47c0849c012d225b335b35933 [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[:]
105 check("reversed via function", y, s, lambda a, b: cmp(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()
160 return cmp(x, y)
161 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[:]
166 return cmp(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)
Raymond Hettinger70b64fc2008-01-30 20:15:17 +0000179 copy.sort(key=CmpToKey(lambda x,y: cmp(x.lower(), y.lower())))
Raymond Hettinger42b1ba32003-10-16 03:41:09 +0000180
181 def test_baddecorator(self):
182 data = 'The quick Brown fox Jumped over The lazy Dog'.split()
Raymond Hettinger70b64fc2008-01-30 20:15:17 +0000183 self.assertRaises(TypeError, data.sort, key=lambda x,y: 0)
Raymond Hettinger42b1ba32003-10-16 03:41:09 +0000184
185 def test_stability(self):
Guido van Rossum805365e2007-05-07 22:24:25 +0000186 data = [(random.randrange(100), i) for i in range(200)]
Raymond Hettinger42b1ba32003-10-16 03:41:09 +0000187 copy = data[:]
Guido van Rossum1bc535d2007-05-15 18:46:22 +0000188 data.sort(key=lambda t: t[0]) # sort on the random first field
Raymond Hettinger42b1ba32003-10-16 03:41:09 +0000189 copy.sort() # sort using both fields
190 self.assertEqual(data, copy) # should get the same result
191
Raymond Hettinger37e13632003-11-28 21:43:02 +0000192 def test_key_with_exception(self):
193 # Verify that the wrapper has been removed
Guido van Rossum805365e2007-05-07 22:24:25 +0000194 data = list(range(-2, 2))
Raymond Hettinger37e13632003-11-28 21:43:02 +0000195 dup = data[:]
Raymond Hettinger70b64fc2008-01-30 20:15:17 +0000196 self.assertRaises(ZeroDivisionError, data.sort, key=lambda x: 1/x)
Raymond Hettinger37e13632003-11-28 21:43:02 +0000197 self.assertEqual(data, dup)
198
Michael W. Hudson1df0f652003-12-04 11:25:46 +0000199 def test_key_with_mutation(self):
Guido van Rossum805365e2007-05-07 22:24:25 +0000200 data = list(range(10))
Michael W. Hudson1df0f652003-12-04 11:25:46 +0000201 def k(x):
202 del data[:]
203 data[:] = range(20)
204 return x
205 self.assertRaises(ValueError, data.sort, key=k)
206
207 def test_key_with_mutating_del(self):
Guido van Rossum805365e2007-05-07 22:24:25 +0000208 data = list(range(10))
Michael W. Hudson1df0f652003-12-04 11:25:46 +0000209 class SortKiller(object):
210 def __init__(self, x):
211 pass
212 def __del__(self):
213 del data[:]
214 data[:] = range(20)
Guido van Rossum47b9ff62006-08-24 00:41:19 +0000215 def __lt__(self, other):
216 return id(self) < id(other)
Michael W. Hudson1df0f652003-12-04 11:25:46 +0000217 self.assertRaises(ValueError, data.sort, key=SortKiller)
218
219 def test_key_with_mutating_del_and_exception(self):
Guido van Rossum805365e2007-05-07 22:24:25 +0000220 data = list(range(10))
Michael W. Hudson1df0f652003-12-04 11:25:46 +0000221 ## dup = data[:]
222 class SortKiller(object):
223 def __init__(self, x):
224 if x > 2:
225 raise RuntimeError
226 def __del__(self):
227 del data[:]
Guido van Rossum805365e2007-05-07 22:24:25 +0000228 data[:] = list(range(20))
Michael W. Hudson1df0f652003-12-04 11:25:46 +0000229 self.assertRaises(RuntimeError, data.sort, key=SortKiller)
230 ## major honking subtlety: we *can't* do:
231 ##
232 ## self.assertEqual(data, dup)
233 ##
234 ## because there is a reference to a SortKiller in the
235 ## traceback and by the time it dies we're outside the call to
236 ## .sort() and so the list protection gimmicks are out of
237 ## date (this cost some brain cells to figure out...).
238
Raymond Hettinger42b1ba32003-10-16 03:41:09 +0000239 def test_reverse(self):
Guido van Rossum805365e2007-05-07 22:24:25 +0000240 data = list(range(100))
Raymond Hettinger42b1ba32003-10-16 03:41:09 +0000241 random.shuffle(data)
242 data.sort(reverse=True)
Guido van Rossum805365e2007-05-07 22:24:25 +0000243 self.assertEqual(data, list(range(99,-1,-1)))
Raymond Hettinger42b1ba32003-10-16 03:41:09 +0000244
245 def test_reverse_stability(self):
Guido van Rossum805365e2007-05-07 22:24:25 +0000246 data = [(random.randrange(100), i) for i in range(200)]
Raymond Hettinger42b1ba32003-10-16 03:41:09 +0000247 copy1 = data[:]
248 copy2 = data[:]
Raymond Hettinger70b64fc2008-01-30 20:15:17 +0000249 data.sort(key=CmpToKey(lambda x,y: cmp(x[0],y[0])), reverse=True)
250 copy1.sort(key=CmpToKey(lambda x,y: cmp(y[0],x[0])))
Raymond Hettinger42b1ba32003-10-16 03:41:09 +0000251 self.assertEqual(data, copy1)
252 copy2.sort(key=lambda x: x[0], reverse=True)
253 self.assertEqual(data, copy2)
254
255#==============================================================================
256
257def test_main(verbose=None):
258 test_classes = (
Neal Norwitza98e7692005-11-24 21:58:51 +0000259 TestBase,
Raymond Hettinger42b1ba32003-10-16 03:41:09 +0000260 TestDecorateSortUndecorate,
261 TestBugs,
262 )
263
Benjamin Petersonee8712c2008-05-20 21:35:26 +0000264 support.run_unittest(*test_classes)
Raymond Hettinger42b1ba32003-10-16 03:41:09 +0000265
266 # verify reference counting
267 if verbose and hasattr(sys, "gettotalrefcount"):
268 import gc
269 counts = [None] * 5
Guido van Rossum805365e2007-05-07 22:24:25 +0000270 for i in range(len(counts)):
Benjamin Petersonee8712c2008-05-20 21:35:26 +0000271 support.run_unittest(*test_classes)
Raymond Hettinger42b1ba32003-10-16 03:41:09 +0000272 gc.collect()
273 counts[i] = sys.gettotalrefcount()
Guido van Rossumbe19ed72007-02-09 05:37:30 +0000274 print(counts)
Raymond Hettinger42b1ba32003-10-16 03:41:09 +0000275
276if __name__ == "__main__":
277 test_main(verbose=True)