blob: 98ccab5c3930a6d3c1575cefd1130328f61640a6 [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 unittest
Éric Araujo41bade92011-07-26 15:13:47 +02004from functools import cmp_to_key
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 +00009
Tim Peters2d8b7652002-08-01 02:23:06 +000010def check(tag, expected, raw, compare=None):
11 global nerrors
12
13 if verbose:
Guido van Rossumbe19ed72007-02-09 05:37:30 +000014 print(" checking", tag)
Tim Peters2d8b7652002-08-01 02:23:06 +000015
16 orig = raw[:] # save input in case of error
17 if compare:
Éric Araujo41bade92011-07-26 15:13:47 +020018 raw.sort(key=cmp_to_key(compare))
Tim Peters2d8b7652002-08-01 02:23:06 +000019 else:
20 raw.sort()
21
22 if len(expected) != len(raw):
Guido van Rossumbe19ed72007-02-09 05:37:30 +000023 print("error in", tag)
24 print("length mismatch;", len(expected), len(raw))
25 print(expected)
26 print(orig)
27 print(raw)
Tim Peters2d8b7652002-08-01 02:23:06 +000028 nerrors += 1
29 return
30
31 for i, good in enumerate(expected):
32 maybe = raw[i]
33 if good is not maybe:
Guido van Rossumbe19ed72007-02-09 05:37:30 +000034 print("error in", tag)
35 print("out of order at index", i, good, maybe)
36 print(expected)
37 print(orig)
38 print(raw)
Tim Peters2d8b7652002-08-01 02:23:06 +000039 nerrors += 1
40 return
41
Neal Norwitza98e7692005-11-24 21:58:51 +000042class TestBase(unittest.TestCase):
43 def testStressfully(self):
44 # Try a variety of sizes at and around powers of 2, and at powers of 10.
45 sizes = [0]
46 for power in range(1, 10):
47 n = 2 ** power
48 sizes.extend(range(n-1, n+2))
49 sizes.extend([10, 100, 1000])
Tim Peters2d8b7652002-08-01 02:23:06 +000050
Neal Norwitza98e7692005-11-24 21:58:51 +000051 class Complains(object):
52 maybe_complain = True
Tim Peters2d8b7652002-08-01 02:23:06 +000053
Neal Norwitza98e7692005-11-24 21:58:51 +000054 def __init__(self, i):
55 self.i = i
Tim Peters2d8b7652002-08-01 02:23:06 +000056
Neal Norwitza98e7692005-11-24 21:58:51 +000057 def __lt__(self, other):
58 if Complains.maybe_complain and random.random() < 0.001:
59 if verbose:
Guido van Rossumbe19ed72007-02-09 05:37:30 +000060 print(" complaining at", self, other)
Neal Norwitza98e7692005-11-24 21:58:51 +000061 raise RuntimeError
62 return self.i < other.i
63
64 def __repr__(self):
65 return "Complains(%d)" % self.i
66
67 class Stable(object):
68 def __init__(self, key, i):
69 self.key = key
70 self.index = i
71
Guido van Rossum47b9ff62006-08-24 00:41:19 +000072 def __lt__(self, other):
73 return self.key < other.key
Neal Norwitza98e7692005-11-24 21:58:51 +000074
75 def __repr__(self):
76 return "Stable(%d, %d)" % (self.key, self.index)
77
78 for n in sizes:
Guido van Rossum805365e2007-05-07 22:24:25 +000079 x = list(range(n))
Tim Peters2d8b7652002-08-01 02:23:06 +000080 if verbose:
Guido van Rossumbe19ed72007-02-09 05:37:30 +000081 print("Testing size", n)
Tim Peters2d8b7652002-08-01 02:23:06 +000082
Neal Norwitza98e7692005-11-24 21:58:51 +000083 s = x[:]
84 check("identity", x, s)
Tim Peters2d8b7652002-08-01 02:23:06 +000085
Neal Norwitza98e7692005-11-24 21:58:51 +000086 s = x[:]
87 s.reverse()
88 check("reversed", x, s)
Tim Peters2d8b7652002-08-01 02:23:06 +000089
Neal Norwitza98e7692005-11-24 21:58:51 +000090 s = x[:]
91 random.shuffle(s)
92 check("random permutation", x, s)
Tim Peters2d8b7652002-08-01 02:23:06 +000093
Neal Norwitza98e7692005-11-24 21:58:51 +000094 y = x[:]
95 y.reverse()
96 s = x[:]
Mark Dickinsona56c4672009-01-27 18:17:45 +000097 check("reversed via function", y, s, lambda a, b: (b>a)-(b<a))
Tim Peters2d8b7652002-08-01 02:23:06 +000098
Neal Norwitza98e7692005-11-24 21:58:51 +000099 if verbose:
Guido van Rossumbe19ed72007-02-09 05:37:30 +0000100 print(" Checking against an insane comparison function.")
101 print(" If the implementation isn't careful, this may segfault.")
Neal Norwitza98e7692005-11-24 21:58:51 +0000102 s = x[:]
Éric Araujo41bade92011-07-26 15:13:47 +0200103 s.sort(key=cmp_to_key(lambda a, b: int(random.random() * 3) - 1))
Neal Norwitza98e7692005-11-24 21:58:51 +0000104 check("an insane function left some permutation", x, s)
Tim Peters2d8b7652002-08-01 02:23:06 +0000105
Daniel Stutzbacheda70b82011-05-04 12:46:28 -0700106 if len(x) >= 2:
107 def bad_key(x):
108 raise RuntimeError
109 s = x[:]
110 self.assertRaises(RuntimeError, s.sort, key=bad_key)
111
Neal Norwitza98e7692005-11-24 21:58:51 +0000112 x = [Complains(i) for i in x]
113 s = x[:]
114 random.shuffle(s)
115 Complains.maybe_complain = True
116 it_complained = False
117 try:
118 s.sort()
119 except RuntimeError:
120 it_complained = True
121 if it_complained:
122 Complains.maybe_complain = False
123 check("exception during sort left some permutation", x, s)
Tim Peters2d8b7652002-08-01 02:23:06 +0000124
Guido van Rossum805365e2007-05-07 22:24:25 +0000125 s = [Stable(random.randrange(10), i) for i in range(n)]
Neal Norwitza98e7692005-11-24 21:58:51 +0000126 augmented = [(e, e.index) for e in s]
127 augmented.sort() # forced stable because ties broken by index
128 x = [e for e, i in augmented] # a stable sort of s
129 check("stability", x, s)
Tim Petersb9099c32002-11-12 22:08:10 +0000130
Raymond Hettinger42b1ba32003-10-16 03:41:09 +0000131#==============================================================================
Tim Petersb9099c32002-11-12 22:08:10 +0000132
Raymond Hettinger42b1ba32003-10-16 03:41:09 +0000133class TestBugs(unittest.TestCase):
Tim Petersb9099c32002-11-12 22:08:10 +0000134
Raymond Hettinger42b1ba32003-10-16 03:41:09 +0000135 def test_bug453523(self):
136 # bug 453523 -- list.sort() crasher.
137 # If this fails, the most likely outcome is a core dump.
138 # Mutations during a list sort should raise a ValueError.
Tim Petersb9099c32002-11-12 22:08:10 +0000139
Raymond Hettinger42b1ba32003-10-16 03:41:09 +0000140 class C:
141 def __lt__(self, other):
142 if L and random.random() < 0.75:
143 L.pop()
144 else:
145 L.append(3)
146 return random.random() < 0.5
Skip Montanaro4abd5f02003-01-02 20:51:08 +0000147
Raymond Hettinger42b1ba32003-10-16 03:41:09 +0000148 L = [C() for i in range(50)]
149 self.assertRaises(ValueError, L.sort)
Skip Montanaro4abd5f02003-01-02 20:51:08 +0000150
Armin Rigo93677f02004-07-29 12:40:23 +0000151 def test_undetected_mutation(self):
152 # Python 2.4a1 did not always detect mutation
153 memorywaster = []
154 for i in range(20):
155 def mutating_cmp(x, y):
156 L.append(3)
157 L.pop()
Mark Dickinsona56c4672009-01-27 18:17:45 +0000158 return (x > y) - (x < y)
Armin Rigo93677f02004-07-29 12:40:23 +0000159 L = [1,2]
Éric Araujo41bade92011-07-26 15:13:47 +0200160 self.assertRaises(ValueError, L.sort, key=cmp_to_key(mutating_cmp))
Armin Rigo93677f02004-07-29 12:40:23 +0000161 def mutating_cmp(x, y):
162 L.append(3)
163 del L[:]
Mark Dickinsona56c4672009-01-27 18:17:45 +0000164 return (x > y) - (x < y)
Éric Araujo41bade92011-07-26 15:13:47 +0200165 self.assertRaises(ValueError, L.sort, key=cmp_to_key(mutating_cmp))
Armin Rigo93677f02004-07-29 12:40:23 +0000166 memorywaster = [memorywaster]
167
Raymond Hettinger42b1ba32003-10-16 03:41:09 +0000168#==============================================================================
Skip Montanaro4abd5f02003-01-02 20:51:08 +0000169
Raymond Hettinger42b1ba32003-10-16 03:41:09 +0000170class TestDecorateSortUndecorate(unittest.TestCase):
171
172 def test_decorated(self):
173 data = 'The quick Brown fox Jumped over The lazy Dog'.split()
174 copy = data[:]
175 random.shuffle(data)
176 data.sort(key=str.lower)
Mark Dickinsona56c4672009-01-27 18:17:45 +0000177 def my_cmp(x, y):
178 xlower, ylower = x.lower(), y.lower()
179 return (xlower > ylower) - (xlower < ylower)
Éric Araujo41bade92011-07-26 15:13:47 +0200180 copy.sort(key=cmp_to_key(my_cmp))
Raymond Hettinger42b1ba32003-10-16 03:41:09 +0000181
182 def test_baddecorator(self):
183 data = 'The quick Brown fox Jumped over The lazy Dog'.split()
Raymond Hettinger70b64fc2008-01-30 20:15:17 +0000184 self.assertRaises(TypeError, data.sort, key=lambda x,y: 0)
Raymond Hettinger42b1ba32003-10-16 03:41:09 +0000185
186 def test_stability(self):
Guido van Rossum805365e2007-05-07 22:24:25 +0000187 data = [(random.randrange(100), i) for i in range(200)]
Raymond Hettinger42b1ba32003-10-16 03:41:09 +0000188 copy = data[:]
Guido van Rossum1bc535d2007-05-15 18:46:22 +0000189 data.sort(key=lambda t: t[0]) # sort on the random first field
Raymond Hettinger42b1ba32003-10-16 03:41:09 +0000190 copy.sort() # sort using both fields
191 self.assertEqual(data, copy) # should get the same result
192
Raymond Hettinger37e13632003-11-28 21:43:02 +0000193 def test_key_with_exception(self):
194 # Verify that the wrapper has been removed
Guido van Rossum805365e2007-05-07 22:24:25 +0000195 data = list(range(-2, 2))
Raymond Hettinger37e13632003-11-28 21:43:02 +0000196 dup = data[:]
Raymond Hettinger70b64fc2008-01-30 20:15:17 +0000197 self.assertRaises(ZeroDivisionError, data.sort, key=lambda x: 1/x)
Raymond Hettinger37e13632003-11-28 21:43:02 +0000198 self.assertEqual(data, dup)
199
Michael W. Hudson1df0f652003-12-04 11:25:46 +0000200 def test_key_with_mutation(self):
Guido van Rossum805365e2007-05-07 22:24:25 +0000201 data = list(range(10))
Michael W. Hudson1df0f652003-12-04 11:25:46 +0000202 def k(x):
203 del data[:]
204 data[:] = range(20)
205 return x
206 self.assertRaises(ValueError, data.sort, key=k)
207
208 def test_key_with_mutating_del(self):
Guido van Rossum805365e2007-05-07 22:24:25 +0000209 data = list(range(10))
Michael W. Hudson1df0f652003-12-04 11:25:46 +0000210 class SortKiller(object):
211 def __init__(self, x):
212 pass
213 def __del__(self):
214 del data[:]
215 data[:] = range(20)
Guido van Rossum47b9ff62006-08-24 00:41:19 +0000216 def __lt__(self, other):
217 return id(self) < id(other)
Michael W. Hudson1df0f652003-12-04 11:25:46 +0000218 self.assertRaises(ValueError, data.sort, key=SortKiller)
219
220 def test_key_with_mutating_del_and_exception(self):
Guido van Rossum805365e2007-05-07 22:24:25 +0000221 data = list(range(10))
Michael W. Hudson1df0f652003-12-04 11:25:46 +0000222 ## dup = data[:]
223 class SortKiller(object):
224 def __init__(self, x):
225 if x > 2:
226 raise RuntimeError
227 def __del__(self):
228 del data[:]
Guido van Rossum805365e2007-05-07 22:24:25 +0000229 data[:] = list(range(20))
Michael W. Hudson1df0f652003-12-04 11:25:46 +0000230 self.assertRaises(RuntimeError, data.sort, key=SortKiller)
231 ## major honking subtlety: we *can't* do:
232 ##
233 ## self.assertEqual(data, dup)
234 ##
235 ## because there is a reference to a SortKiller in the
236 ## traceback and by the time it dies we're outside the call to
237 ## .sort() and so the list protection gimmicks are out of
238 ## date (this cost some brain cells to figure out...).
239
Raymond Hettinger42b1ba32003-10-16 03:41:09 +0000240 def test_reverse(self):
Guido van Rossum805365e2007-05-07 22:24:25 +0000241 data = list(range(100))
Raymond Hettinger42b1ba32003-10-16 03:41:09 +0000242 random.shuffle(data)
243 data.sort(reverse=True)
Guido van Rossum805365e2007-05-07 22:24:25 +0000244 self.assertEqual(data, list(range(99,-1,-1)))
Raymond Hettinger42b1ba32003-10-16 03:41:09 +0000245
246 def test_reverse_stability(self):
Guido van Rossum805365e2007-05-07 22:24:25 +0000247 data = [(random.randrange(100), i) for i in range(200)]
Raymond Hettinger42b1ba32003-10-16 03:41:09 +0000248 copy1 = data[:]
249 copy2 = data[:]
Mark Dickinsona56c4672009-01-27 18:17:45 +0000250 def my_cmp(x, y):
251 x0, y0 = x[0], y[0]
252 return (x0 > y0) - (x0 < y0)
253 def my_cmp_reversed(x, y):
254 x0, y0 = x[0], y[0]
255 return (y0 > x0) - (y0 < x0)
Éric Araujo41bade92011-07-26 15:13:47 +0200256 data.sort(key=cmp_to_key(my_cmp), reverse=True)
257 copy1.sort(key=cmp_to_key(my_cmp_reversed))
Raymond Hettinger42b1ba32003-10-16 03:41:09 +0000258 self.assertEqual(data, copy1)
259 copy2.sort(key=lambda x: x[0], reverse=True)
260 self.assertEqual(data, copy2)
261
262#==============================================================================
263
Raymond Hettinger42b1ba32003-10-16 03:41:09 +0000264if __name__ == "__main__":
Zachary Ware38c707e2015-04-13 15:00:43 -0500265 unittest.main()