from test.test_support import verbose import random nerrors = 0 def check(tag, expected, raw, compare=None): global nerrors if verbose: print " checking", tag orig = raw[:] # save input in case of error if compare: raw.sort(compare) else: raw.sort() if len(expected) != len(raw): print "error in", tag print "length mismatch;", len(expected), len(raw) print expected print orig print raw nerrors += 1 return for i, good in enumerate(expected): maybe = raw[i] if good is not maybe: print "error in", tag print "out of order at index", i, good, maybe print expected print orig print raw nerrors += 1 return # Try a variety of sizes at and around powers of 2, and at powers of 10. sizes = [0] for power in range(1, 10): n = 2 ** power sizes.extend(range(n-1, n+2)) sizes.extend([10, 100, 1000]) class Complains(object): maybe_complain = True def __init__(self, i): self.i = i def __lt__(self, other): if Complains.maybe_complain and random.random() < 0.001: if verbose: print " complaining at", self, other raise RuntimeError return self.i < other.i def __repr__(self): return "Complains(%d)" % self.i class Stable(object): def __init__(self, key, i): self.key = key self.index = i def __cmp__(self, other): return cmp(self.key, other.key) def __repr__(self): return "Stable(%d, %d)" % (self.key, self.index) for n in sizes: x = range(n) if verbose: print "Testing size", n s = x[:] check("identity", x, s) s = x[:] s.reverse() check("reversed", x, s) s = x[:] random.shuffle(s) check("random permutation", x, s) y = x[:] y.reverse() s = x[:] check("reversed via function", y, s, lambda a, b: cmp(b, a)) if verbose: print " Checking against an insane comparison function." print " If the implementation isn't careful, this may segfault." s = x[:] s.sort(lambda a, b: int(random.random() * 3) - 1) check("an insane function left some permutation", x, s) x = [Complains(i) for i in x] s = x[:] random.shuffle(s) Complains.maybe_complain = True it_complained = False try: s.sort() except RuntimeError: it_complained = True if it_complained: Complains.maybe_complain = False check("exception during sort left some permutation", x, s) s = [Stable(random.randrange(10), i) for i in xrange(n)] augmented = [(e, e.index) for e in s] augmented.sort() # forced stable because ties broken by index x = [e for e, i in augmented] # a stable sort of s check("stability", x, s) def bug453523(): global nerrors from random import random # If this fails, the most likely outcome is a core dump. if verbose: print "Testing bug 453523 -- list.sort() crasher." class C: def __lt__(self, other): if L and random() < 0.75: pop() else: push(3) return random() < 0.5 L = [C() for i in range(50)] pop = L.pop push = L.append try: L.sort() except ValueError: pass else: print " Mutation during list.sort() wasn't caught." nerrors += 1 bug453523() if nerrors: print "Test failed", nerrors elif verbose: print "Test passed -- no errors."