blob: 8f6af64470232dfc84e5a0fd762a4f2152db57a4 [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
Éric Araujo41bade92011-07-26 15:13:47 +02005from functools import cmp_to_key
Tim Peters2d8b7652002-08-01 02:23:06 +00006
Benjamin Petersonee8712c2008-05-20 21:35:26 +00007verbose = support.verbose
Tim Peters2d8b7652002-08-01 02:23:06 +00008nerrors = 0
9
Raymond Hettinger70b64fc2008-01-30 20:15:17 +000010
Tim Peters2d8b7652002-08-01 02:23:06 +000011def check(tag, expected, raw, compare=None):
12 global nerrors
13
14 if verbose:
Guido van Rossumbe19ed72007-02-09 05:37:30 +000015 print(" checking", tag)
Tim Peters2d8b7652002-08-01 02:23:06 +000016
17 orig = raw[:] # save input in case of error
18 if compare:
Éric Araujo41bade92011-07-26 15:13:47 +020019 raw.sort(key=cmp_to_key(compare))
Tim Peters2d8b7652002-08-01 02:23:06 +000020 else:
21 raw.sort()
22
23 if len(expected) != len(raw):
Guido van Rossumbe19ed72007-02-09 05:37:30 +000024 print("error in", tag)
25 print("length mismatch;", len(expected), len(raw))
26 print(expected)
27 print(orig)
28 print(raw)
Tim Peters2d8b7652002-08-01 02:23:06 +000029 nerrors += 1
30 return
31
32 for i, good in enumerate(expected):
33 maybe = raw[i]
34 if good is not maybe:
Guido van Rossumbe19ed72007-02-09 05:37:30 +000035 print("error in", tag)
36 print("out of order at index", i, good, maybe)
37 print(expected)
38 print(orig)
39 print(raw)
Tim Peters2d8b7652002-08-01 02:23:06 +000040 nerrors += 1
41 return
42
Neal Norwitza98e7692005-11-24 21:58:51 +000043class TestBase(unittest.TestCase):
44 def testStressfully(self):
45 # Try a variety of sizes at and around powers of 2, and at powers of 10.
46 sizes = [0]
47 for power in range(1, 10):
48 n = 2 ** power
49 sizes.extend(range(n-1, n+2))
50 sizes.extend([10, 100, 1000])
Tim Peters2d8b7652002-08-01 02:23:06 +000051
Neal Norwitza98e7692005-11-24 21:58:51 +000052 class Complains(object):
53 maybe_complain = True
Tim Peters2d8b7652002-08-01 02:23:06 +000054
Neal Norwitza98e7692005-11-24 21:58:51 +000055 def __init__(self, i):
56 self.i = i
Tim Peters2d8b7652002-08-01 02:23:06 +000057
Neal Norwitza98e7692005-11-24 21:58:51 +000058 def __lt__(self, other):
59 if Complains.maybe_complain and random.random() < 0.001:
60 if verbose:
Guido van Rossumbe19ed72007-02-09 05:37:30 +000061 print(" complaining at", self, other)
Neal Norwitza98e7692005-11-24 21:58:51 +000062 raise RuntimeError
63 return self.i < other.i
64
65 def __repr__(self):
66 return "Complains(%d)" % self.i
67
68 class Stable(object):
69 def __init__(self, key, i):
70 self.key = key
71 self.index = i
72
Guido van Rossum47b9ff62006-08-24 00:41:19 +000073 def __lt__(self, other):
74 return self.key < other.key
Neal Norwitza98e7692005-11-24 21:58:51 +000075
76 def __repr__(self):
77 return "Stable(%d, %d)" % (self.key, self.index)
78
79 for n in sizes:
Guido van Rossum805365e2007-05-07 22:24:25 +000080 x = list(range(n))
Tim Peters2d8b7652002-08-01 02:23:06 +000081 if verbose:
Guido van Rossumbe19ed72007-02-09 05:37:30 +000082 print("Testing size", n)
Tim Peters2d8b7652002-08-01 02:23:06 +000083
Neal Norwitza98e7692005-11-24 21:58:51 +000084 s = x[:]
85 check("identity", x, s)
Tim Peters2d8b7652002-08-01 02:23:06 +000086
Neal Norwitza98e7692005-11-24 21:58:51 +000087 s = x[:]
88 s.reverse()
89 check("reversed", x, s)
Tim Peters2d8b7652002-08-01 02:23:06 +000090
Neal Norwitza98e7692005-11-24 21:58:51 +000091 s = x[:]
92 random.shuffle(s)
93 check("random permutation", x, s)
Tim Peters2d8b7652002-08-01 02:23:06 +000094
Neal Norwitza98e7692005-11-24 21:58:51 +000095 y = x[:]
96 y.reverse()
97 s = x[:]
Mark Dickinsona56c4672009-01-27 18:17:45 +000098 check("reversed via function", y, s, lambda a, b: (b>a)-(b<a))
Tim Peters2d8b7652002-08-01 02:23:06 +000099
Neal Norwitza98e7692005-11-24 21:58:51 +0000100 if verbose:
Guido van Rossumbe19ed72007-02-09 05:37:30 +0000101 print(" Checking against an insane comparison function.")
102 print(" If the implementation isn't careful, this may segfault.")
Neal Norwitza98e7692005-11-24 21:58:51 +0000103 s = x[:]
Éric Araujo41bade92011-07-26 15:13:47 +0200104 s.sort(key=cmp_to_key(lambda a, b: int(random.random() * 3) - 1))
Neal Norwitza98e7692005-11-24 21:58:51 +0000105 check("an insane function left some permutation", x, s)
Tim Peters2d8b7652002-08-01 02:23:06 +0000106
Daniel Stutzbacheda70b82011-05-04 12:46:28 -0700107 if len(x) >= 2:
108 def bad_key(x):
109 raise RuntimeError
110 s = x[:]
111 self.assertRaises(RuntimeError, s.sort, key=bad_key)
112
Neal Norwitza98e7692005-11-24 21:58:51 +0000113 x = [Complains(i) for i in x]
114 s = x[:]
115 random.shuffle(s)
116 Complains.maybe_complain = True
117 it_complained = False
118 try:
119 s.sort()
120 except RuntimeError:
121 it_complained = True
122 if it_complained:
123 Complains.maybe_complain = False
124 check("exception during sort left some permutation", x, s)
Tim Peters2d8b7652002-08-01 02:23:06 +0000125
Guido van Rossum805365e2007-05-07 22:24:25 +0000126 s = [Stable(random.randrange(10), i) for i in range(n)]
Neal Norwitza98e7692005-11-24 21:58:51 +0000127 augmented = [(e, e.index) for e in s]
128 augmented.sort() # forced stable because ties broken by index
129 x = [e for e, i in augmented] # a stable sort of s
130 check("stability", x, s)
Tim Petersb9099c32002-11-12 22:08:10 +0000131
Raymond Hettinger42b1ba32003-10-16 03:41:09 +0000132#==============================================================================
Tim Petersb9099c32002-11-12 22:08:10 +0000133
Raymond Hettinger42b1ba32003-10-16 03:41:09 +0000134class TestBugs(unittest.TestCase):
Tim Petersb9099c32002-11-12 22:08:10 +0000135
Raymond Hettinger42b1ba32003-10-16 03:41:09 +0000136 def test_bug453523(self):
137 # bug 453523 -- list.sort() crasher.
138 # If this fails, the most likely outcome is a core dump.
139 # Mutations during a list sort should raise a ValueError.
Tim Petersb9099c32002-11-12 22:08:10 +0000140
Raymond Hettinger42b1ba32003-10-16 03:41:09 +0000141 class C:
142 def __lt__(self, other):
143 if L and random.random() < 0.75:
144 L.pop()
145 else:
146 L.append(3)
147 return random.random() < 0.5
Skip Montanaro4abd5f02003-01-02 20:51:08 +0000148
Raymond Hettinger42b1ba32003-10-16 03:41:09 +0000149 L = [C() for i in range(50)]
150 self.assertRaises(ValueError, L.sort)
Skip Montanaro4abd5f02003-01-02 20:51:08 +0000151
Armin Rigo93677f02004-07-29 12:40:23 +0000152 def test_undetected_mutation(self):
153 # Python 2.4a1 did not always detect mutation
154 memorywaster = []
155 for i in range(20):
156 def mutating_cmp(x, y):
157 L.append(3)
158 L.pop()
Mark Dickinsona56c4672009-01-27 18:17:45 +0000159 return (x > y) - (x < y)
Armin Rigo93677f02004-07-29 12:40:23 +0000160 L = [1,2]
Éric Araujo41bade92011-07-26 15:13:47 +0200161 self.assertRaises(ValueError, L.sort, key=cmp_to_key(mutating_cmp))
Armin Rigo93677f02004-07-29 12:40:23 +0000162 def mutating_cmp(x, y):
163 L.append(3)
164 del L[:]
Mark Dickinsona56c4672009-01-27 18:17:45 +0000165 return (x > y) - (x < y)
Éric Araujo41bade92011-07-26 15:13:47 +0200166 self.assertRaises(ValueError, L.sort, key=cmp_to_key(mutating_cmp))
Armin Rigo93677f02004-07-29 12:40:23 +0000167 memorywaster = [memorywaster]
168
Raymond Hettinger42b1ba32003-10-16 03:41:09 +0000169#==============================================================================
Skip Montanaro4abd5f02003-01-02 20:51:08 +0000170
Raymond Hettinger42b1ba32003-10-16 03:41:09 +0000171class TestDecorateSortUndecorate(unittest.TestCase):
172
173 def test_decorated(self):
174 data = 'The quick Brown fox Jumped over The lazy Dog'.split()
175 copy = data[:]
176 random.shuffle(data)
177 data.sort(key=str.lower)
Mark Dickinsona56c4672009-01-27 18:17:45 +0000178 def my_cmp(x, y):
179 xlower, ylower = x.lower(), y.lower()
180 return (xlower > ylower) - (xlower < ylower)
Éric Araujo41bade92011-07-26 15:13:47 +0200181 copy.sort(key=cmp_to_key(my_cmp))
Raymond Hettinger42b1ba32003-10-16 03:41:09 +0000182
183 def test_baddecorator(self):
184 data = 'The quick Brown fox Jumped over The lazy Dog'.split()
Raymond Hettinger70b64fc2008-01-30 20:15:17 +0000185 self.assertRaises(TypeError, data.sort, key=lambda x,y: 0)
Raymond Hettinger42b1ba32003-10-16 03:41:09 +0000186
187 def test_stability(self):
Guido van Rossum805365e2007-05-07 22:24:25 +0000188 data = [(random.randrange(100), i) for i in range(200)]
Raymond Hettinger42b1ba32003-10-16 03:41:09 +0000189 copy = data[:]
Guido van Rossum1bc535d2007-05-15 18:46:22 +0000190 data.sort(key=lambda t: t[0]) # sort on the random first field
Raymond Hettinger42b1ba32003-10-16 03:41:09 +0000191 copy.sort() # sort using both fields
192 self.assertEqual(data, copy) # should get the same result
193
Raymond Hettinger37e13632003-11-28 21:43:02 +0000194 def test_key_with_exception(self):
195 # Verify that the wrapper has been removed
Guido van Rossum805365e2007-05-07 22:24:25 +0000196 data = list(range(-2, 2))
Raymond Hettinger37e13632003-11-28 21:43:02 +0000197 dup = data[:]
Raymond Hettinger70b64fc2008-01-30 20:15:17 +0000198 self.assertRaises(ZeroDivisionError, data.sort, key=lambda x: 1/x)
Raymond Hettinger37e13632003-11-28 21:43:02 +0000199 self.assertEqual(data, dup)
200
Michael W. Hudson1df0f652003-12-04 11:25:46 +0000201 def test_key_with_mutation(self):
Guido van Rossum805365e2007-05-07 22:24:25 +0000202 data = list(range(10))
Michael W. Hudson1df0f652003-12-04 11:25:46 +0000203 def k(x):
204 del data[:]
205 data[:] = range(20)
206 return x
207 self.assertRaises(ValueError, data.sort, key=k)
208
209 def test_key_with_mutating_del(self):
Guido van Rossum805365e2007-05-07 22:24:25 +0000210 data = list(range(10))
Michael W. Hudson1df0f652003-12-04 11:25:46 +0000211 class SortKiller(object):
212 def __init__(self, x):
213 pass
214 def __del__(self):
215 del data[:]
216 data[:] = range(20)
Guido van Rossum47b9ff62006-08-24 00:41:19 +0000217 def __lt__(self, other):
218 return id(self) < id(other)
Michael W. Hudson1df0f652003-12-04 11:25:46 +0000219 self.assertRaises(ValueError, data.sort, key=SortKiller)
220
221 def test_key_with_mutating_del_and_exception(self):
Guido van Rossum805365e2007-05-07 22:24:25 +0000222 data = list(range(10))
Michael W. Hudson1df0f652003-12-04 11:25:46 +0000223 ## dup = data[:]
224 class SortKiller(object):
225 def __init__(self, x):
226 if x > 2:
227 raise RuntimeError
228 def __del__(self):
229 del data[:]
Guido van Rossum805365e2007-05-07 22:24:25 +0000230 data[:] = list(range(20))
Michael W. Hudson1df0f652003-12-04 11:25:46 +0000231 self.assertRaises(RuntimeError, data.sort, key=SortKiller)
232 ## major honking subtlety: we *can't* do:
233 ##
234 ## self.assertEqual(data, dup)
235 ##
236 ## because there is a reference to a SortKiller in the
237 ## traceback and by the time it dies we're outside the call to
238 ## .sort() and so the list protection gimmicks are out of
239 ## date (this cost some brain cells to figure out...).
240
Raymond Hettinger42b1ba32003-10-16 03:41:09 +0000241 def test_reverse(self):
Guido van Rossum805365e2007-05-07 22:24:25 +0000242 data = list(range(100))
Raymond Hettinger42b1ba32003-10-16 03:41:09 +0000243 random.shuffle(data)
244 data.sort(reverse=True)
Guido van Rossum805365e2007-05-07 22:24:25 +0000245 self.assertEqual(data, list(range(99,-1,-1)))
Raymond Hettinger42b1ba32003-10-16 03:41:09 +0000246
247 def test_reverse_stability(self):
Guido van Rossum805365e2007-05-07 22:24:25 +0000248 data = [(random.randrange(100), i) for i in range(200)]
Raymond Hettinger42b1ba32003-10-16 03:41:09 +0000249 copy1 = data[:]
250 copy2 = data[:]
Mark Dickinsona56c4672009-01-27 18:17:45 +0000251 def my_cmp(x, y):
252 x0, y0 = x[0], y[0]
253 return (x0 > y0) - (x0 < y0)
254 def my_cmp_reversed(x, y):
255 x0, y0 = x[0], y[0]
256 return (y0 > x0) - (y0 < x0)
Éric Araujo41bade92011-07-26 15:13:47 +0200257 data.sort(key=cmp_to_key(my_cmp), reverse=True)
258 copy1.sort(key=cmp_to_key(my_cmp_reversed))
Raymond Hettinger42b1ba32003-10-16 03:41:09 +0000259 self.assertEqual(data, copy1)
260 copy2.sort(key=lambda x: x[0], reverse=True)
261 self.assertEqual(data, copy2)
262
263#==============================================================================
264
265def test_main(verbose=None):
266 test_classes = (
Neal Norwitza98e7692005-11-24 21:58:51 +0000267 TestBase,
Raymond Hettinger42b1ba32003-10-16 03:41:09 +0000268 TestDecorateSortUndecorate,
269 TestBugs,
270 )
271
Benjamin Petersonee8712c2008-05-20 21:35:26 +0000272 support.run_unittest(*test_classes)
Raymond Hettinger42b1ba32003-10-16 03:41:09 +0000273
274 # verify reference counting
275 if verbose and hasattr(sys, "gettotalrefcount"):
276 import gc
277 counts = [None] * 5
Guido van Rossum805365e2007-05-07 22:24:25 +0000278 for i in range(len(counts)):
Benjamin Petersonee8712c2008-05-20 21:35:26 +0000279 support.run_unittest(*test_classes)
Raymond Hettinger42b1ba32003-10-16 03:41:09 +0000280 gc.collect()
281 counts[i] = sys.gettotalrefcount()
Guido van Rossumbe19ed72007-02-09 05:37:30 +0000282 print(counts)
Raymond Hettinger42b1ba32003-10-16 03:41:09 +0000283
284if __name__ == "__main__":
285 test_main(verbose=True)