1 from test
import test_support
6 verbose
= test_support
.verbose
9 def check(tag
, expected
, raw
, compare
=None):
13 print " checking", tag
15 orig
= raw
[:] # save input in case of error
21 if len(expected
) != len(raw
):
23 print "length mismatch;", len(expected
), len(raw
)
30 for i
, good
in enumerate(expected
):
34 print "out of order at index", i
, good
, maybe
41 class TestBase(unittest
.TestCase
):
42 def testStressfully(self
):
43 # Try a variety of sizes at and around powers of 2, and at powers of 10.
45 for power
in range(1, 10):
47 sizes
.extend(range(n
-1, n
+2))
48 sizes
.extend([10, 100, 1000])
50 class Complains(object):
53 def __init__(self
, i
):
56 def __lt__(self
, other
):
57 if Complains
.maybe_complain
and random
.random() < 0.001:
59 print " complaining at", self
, other
61 return self
.i
< other
.i
64 return "Complains(%d)" % self
.i
67 def __init__(self
, key
, i
):
71 def __cmp__(self
, other
):
72 return cmp(self
.key
, other
.key
)
73 __hash__
= None # Silence Py3k warning
76 return "Stable(%d, %d)" % (self
.key
, self
.index
)
81 print "Testing size", n
84 check("identity", x
, s
)
88 check("reversed", x
, s
)
92 check("random permutation", x
, s
)
97 check("reversed via function", y
, s
, lambda a
, b
: cmp(b
, a
))
100 print " Checking against an insane comparison function."
101 print " If the implementation isn't careful, this may segfault."
103 s
.sort(lambda a
, b
: int(random
.random() * 3) - 1)
104 check("an insane function left some permutation", x
, s
)
106 x
= [Complains(i
) for i
in x
]
109 Complains
.maybe_complain
= True
110 it_complained
= False
116 Complains
.maybe_complain
= False
117 check("exception during sort left some permutation", x
, s
)
119 s
= [Stable(random
.randrange(10), i
) for i
in xrange(n
)]
120 augmented
= [(e
, e
.index
) for e
in s
]
121 augmented
.sort() # forced stable because ties broken by index
122 x
= [e
for e
, i
in augmented
] # a stable sort of s
123 check("stability", x
, s
)
125 #==============================================================================
127 class TestBugs(unittest
.TestCase
):
129 def test_bug453523(self
):
130 # bug 453523 -- list.sort() crasher.
131 # If this fails, the most likely outcome is a core dump.
132 # Mutations during a list sort should raise a ValueError.
135 def __lt__(self
, other
):
136 if L
and random
.random() < 0.75:
140 return random
.random() < 0.5
142 L
= [C() for i
in range(50)]
143 self
.assertRaises(ValueError, L
.sort
)
145 def test_cmpNone(self
):
146 # Testing None as a comparison function.
151 self
.assertEqual(L
, range(50))
153 def test_undetected_mutation(self
):
154 # Python 2.4a1 did not always detect mutation
157 def mutating_cmp(x
, y
):
162 self
.assertRaises(ValueError, L
.sort
, mutating_cmp
)
163 def mutating_cmp(x
, y
):
167 self
.assertRaises(ValueError, L
.sort
, mutating_cmp
)
168 memorywaster
= [memorywaster
]
170 #==============================================================================
172 class TestDecorateSortUndecorate(unittest
.TestCase
):
174 def test_decorated(self
):
175 data
= 'The quick Brown fox Jumped over The lazy Dog'.split()
178 data
.sort(key
=str.lower
)
179 copy
.sort(cmp=lambda x
,y
: cmp(x
.lower(), y
.lower()))
181 def test_baddecorator(self
):
182 data
= 'The quick Brown fox Jumped over The lazy Dog'.split()
183 self
.assertRaises(TypeError, data
.sort
, None, lambda x
,y
: 0)
185 def test_stability(self
):
186 data
= [(random
.randrange(100), i
) for i
in xrange(200)]
188 data
.sort(key
=lambda x
: x
[0]) # sort on the random first field
189 copy
.sort() # sort using both fields
190 self
.assertEqual(data
, copy
) # should get the same result
192 def test_cmp_and_key_combination(self
):
193 # Verify that the wrapper has been removed
195 self
.assertEqual(type(x
), str)
196 self
.assertEqual(type(x
), str)
198 data
= 'The quick Brown fox Jumped over The lazy Dog'.split()
199 data
.sort(cmp=compare
, key
=str.lower
)
201 def test_badcmp_with_key(self
):
202 # Verify that the wrapper has been removed
203 data
= 'The quick Brown fox Jumped over The lazy Dog'.split()
204 self
.assertRaises(TypeError, data
.sort
, "bad", str.lower
)
206 def test_key_with_exception(self
):
207 # Verify that the wrapper has been removed
210 self
.assertRaises(ZeroDivisionError, data
.sort
, None, lambda x
: 1 // x
)
211 self
.assertEqual(data
, dup
)
213 def test_key_with_mutation(self
):
219 self
.assertRaises(ValueError, data
.sort
, key
=k
)
221 def test_key_with_mutating_del(self
):
223 class SortKiller(object):
224 def __init__(self
, x
):
229 self
.assertRaises(ValueError, data
.sort
, key
=SortKiller
)
231 def test_key_with_mutating_del_and_exception(self
):
234 class SortKiller(object):
235 def __init__(self
, x
):
241 self
.assertRaises(RuntimeError, data
.sort
, key
=SortKiller
)
242 ## major honking subtlety: we *can't* do:
244 ## self.assertEqual(data, dup)
246 ## because there is a reference to a SortKiller in the
247 ## traceback and by the time it dies we're outside the call to
248 ## .sort() and so the list protection gimmicks are out of
249 ## date (this cost some brain cells to figure out...).
251 def test_reverse(self
):
254 data
.sort(reverse
=True)
255 self
.assertEqual(data
, range(99,-1,-1))
256 self
.assertRaises(TypeError, data
.sort
, "wrong type")
258 def test_reverse_stability(self
):
259 data
= [(random
.randrange(100), i
) for i
in xrange(200)]
262 data
.sort(cmp=lambda x
,y
: cmp(x
[0],y
[0]), reverse
=True)
263 copy1
.sort(cmp=lambda x
,y
: cmp(y
[0],x
[0]))
264 self
.assertEqual(data
, copy1
)
265 copy2
.sort(key
=lambda x
: x
[0], reverse
=True)
266 self
.assertEqual(data
, copy2
)
268 #==============================================================================
270 def test_main(verbose
=None):
273 TestDecorateSortUndecorate
,
277 with test_support
.check_py3k_warnings(
278 ("the cmp argument is not supported", DeprecationWarning)):
279 test_support
.run_unittest(*test_classes
)
281 # verify reference counting
282 if verbose
and hasattr(sys
, "gettotalrefcount"):
285 for i
in xrange(len(counts
)):
286 test_support
.run_unittest(*test_classes
)
288 counts
[i
] = sys
.gettotalrefcount()
291 if __name__
== "__main__":
292 test_main(verbose
=True)