diff options
Diffstat (limited to 'Lib/test/test_class.py')
| -rw-r--r-- | Lib/test/test_class.py | 811 | 
1 files changed, 507 insertions, 304 deletions
diff --git a/Lib/test/test_class.py b/Lib/test/test_class.py index 003b4a5..bde63a8 100644 --- a/Lib/test/test_class.py +++ b/Lib/test/test_class.py @@ -1,6 +1,9 @@  "Test the functionality of Python classes implementing operators." -from test.test_support import TestFailed +import unittest +import sys + +from test import test_support  testmeths = [ @@ -53,340 +56,540 @@ testmeths = [  #    "str",  #    "repr",  #    "int", -#    "long",  #    "float", -#    "oct", -#    "hex",  # These are separate because they can influence the test of other methods.  #    "getattr",  #    "setattr",  #    "delattr", -class AllTests: -    def __hash__(self, *args): -        print("__hash__:", args) -        return hash(id(self)) - -    def __str__(self, *args): -        print("__str__:", args) -        return "AllTests" - -    def __repr__(self, *args): -        print("__repr__:", args) -        return "AllTests" - -    def __int__(self, *args): -        print("__int__:", args) -        return 1 - -    def __index__(self, *args): -        print("__index__:", args) -        return 1 - -    def __float__(self, *args): -        print("__float__:", args) -        return 1.0 - -    def __cmp__(self, *args): -        print("__cmp__:", args) -        return 0 - -    def __eq__(self, *args): -        print("__eq__:", args) -        return True - -    def __ne__(self, *args): -        print("__ne__:", args) -        return False - -    def __lt__(self, *args): -        print("__lt__:", args) -        return False - -    def __le__(self, *args): -        print("__le__:", args) -        return True - -    def __gt__(self, *args): -        print("__gt__:", args) -        return False - -    def __ge__(self, *args): -        print("__ge__:", args) -        return True - -    def __del__(self, *args): -        print("__del__:", args) +callLst = [] +def trackCall(f): +    def track(*args, **kwargs): +        callLst.append((f.__name__, args)) +        return f(*args, **kwargs) +    return track + +statictests = """ +@trackCall +def __hash__(self, *args): +    return hash(id(self)) + +@trackCall +def __str__(self, *args): +    return "AllTests" + +@trackCall +def __repr__(self, *args): +    return "AllTests" + +@trackCall +def __int__(self, *args): +    return 1 + +@trackCall +def __index__(self, *args): +    return 1 + +@trackCall +def __float__(self, *args): +    return 1.0 + +@trackCall +def __cmp__(self, *args): +    return 0 + +@trackCall +def __eq__(self, *args): +    return True + +@trackCall +def __ne__(self, *args): +    return False + +@trackCall +def __lt__(self, *args): +    return False + +@trackCall +def __le__(self, *args): +    return True + +@trackCall +def __gt__(self, *args): +    return False + +@trackCall +def __ge__(self, *args): +    return True +""" -# Synthesize AllTests methods from the names in testmeths. +# Synthesize all the other AllTests methods from the names in testmeths.  method_template = """\ -def __%(method)s__(self, *args): -    print("__%(method)s__:", args) +@trackCall +def __%s__(self, *args): +    pass  """  d = {} +exec(statictests, globals(), d)  for method in testmeths: -    exec(method_template % locals(), d) -for k in d: -    setattr(AllTests, k, d[k]) -del d, k -del method, method_template - -# this also tests __init__ of course. -testme = AllTests() - -# Binary operations - -testme + 1 -1 + testme - -testme - 1 -1 - testme - -testme * 1 -1 * testme - -testme / 1 -1 / testme - -testme % 1 -1 % testme +    exec(method_template % method, globals(), d) +AllTests = type("AllTests", (object,), d) +del d, statictests, method, method_template -divmod(testme,1) -divmod(1, testme) +class ClassTests(unittest.TestCase): +    def setUp(self): +        callLst[:] = [] -testme ** 1 -1 ** testme +    def assertCallStack(self, expected_calls): +        actualCallList = callLst[:]  # need to copy because the comparison below will add +                                     # additional calls to callLst +        if expected_calls != actualCallList: +            self.fail("Expected call list:\n  %s\ndoes not match actual call list\n  %s" % +                      (expected_calls, actualCallList)) -testme >> 1 -1 >> testme +    def testInit(self): +        foo = AllTests() +        self.assertCallStack([("__init__", (foo,))]) -testme << 1 -1 << testme +    def testBinaryOps(self): +        testme = AllTests() +        # Binary operations -testme & 1 -1 & testme +        callLst[:] = [] +        testme + 1 +        self.assertCallStack([("__add__", (testme, 1))]) -testme | 1 -1 | testme +        callLst[:] = [] +        1 + testme +        self.assertCallStack([("__radd__", (testme, 1))]) -testme ^ 1 -1 ^ testme +        callLst[:] = [] +        testme - 1 +        self.assertCallStack([("__sub__", (testme, 1))]) +        callLst[:] = [] +        1 - testme +        self.assertCallStack([("__rsub__", (testme, 1))]) -# List/dict operations - -class Empty: pass - -try: -    1 in Empty() -    print('failed, should have raised TypeError') -except TypeError: -    pass - -1 in testme - -testme[1] -testme[1] = 1 -del testme[1] - -testme[:42] -testme[:42] = "The Answer" -del testme[:42] +        callLst[:] = [] +        testme * 1 +        self.assertCallStack([("__mul__", (testme, 1))]) -testme[2:1024:10] -testme[2:1024:10] = "A lot" -del testme[2:1024:10] +        callLst[:] = [] +        1 * testme +        self.assertCallStack([("__rmul__", (testme, 1))]) -testme[:42, ..., :24:, 24, 100] -testme[:42, ..., :24:, 24, 100] = "Strange" -del testme[:42, ..., :24:, 24, 100] +        if 1/2 == 0: +            callLst[:] = [] +            testme / 1 +            self.assertCallStack([("__div__", (testme, 1))]) -# Now remove the slice hooks to see if converting normal slices to slice -# object works. +            callLst[:] = [] +            1 / testme +            self.assertCallStack([("__rdiv__", (testme, 1))]) -del AllTests.__getslice__ -del AllTests.__setslice__ -del AllTests.__delslice__ - -import sys -if sys.platform[:4] != 'java': -    testme[:42] -    testme[:42] = "The Answer" -    del testme[:42] -else: -    # This works under Jython, but the actual slice values are -    # different. -    print("__getitem__: (slice(0, 42, None),)") -    print("__setitem__: (slice(0, 42, None), 'The Answer')") -    print("__delitem__: (slice(0, 42, None),)") - -# Unary operations - --testme -+testme -abs(testme) -int(testme) -int(testme) -float(testme) -oct(testme) - -# And the rest... - -hash(testme) -repr(testme) -str(testme) - -testme == 1 -testme < 1 -testme > 1 -testme != 1 -1 == testme -1 < testme -1 > testme -1 != testme - -# This test has to be last (duh.) - -del testme -if sys.platform[:4] == 'java': -    import java -    java.lang.System.gc() - -# Interfering tests - -class ExtraTests: -    def __getattr__(self, *args): -        print("__getattr__:", args) -        return "SomeVal" - -    def __setattr__(self, *args): -        print("__setattr__:", args) - -    def __delattr__(self, *args): -        print("__delattr__:", args) - -testme = ExtraTests() -testme.spam -testme.eggs = "spam, spam, spam and ham" -del testme.cardinal - - -# return values of some method are type-checked -class BadTypeClass: -    def __int__(self): -        return None -    __float__ = __int__ -    __str__ = __int__ -    __repr__ = __int__ - -def check_exc(stmt, exception): -    """Raise TestFailed if executing 'stmt' does not raise 'exception' -    """ -    try: -        exec(stmt) -    except exception: -        pass -    else: -        raise TestFailed, "%s should raise %s" % (stmt, exception) - -check_exc("int(BadTypeClass())", TypeError) -check_exc("float(BadTypeClass())", TypeError) -check_exc("str(BadTypeClass())", TypeError) -check_exc("repr(BadTypeClass())", TypeError) -check_exc("oct(BadTypeClass())", TypeError) -check_exc("hex(BadTypeClass())", TypeError) - -# Test correct errors from hash() on objects with comparisons but no __hash__ - -class C0: -    pass +        callLst[:] = [] +        testme % 1 +        self.assertCallStack([("__mod__", (testme, 1))]) -hash(C0()) # This should work; the next two should raise TypeError +        callLst[:] = [] +        1 % testme +        self.assertCallStack([("__rmod__", (testme, 1))]) -class C1: -    def __cmp__(self, other): return 0 -check_exc("hash(C1())", TypeError) +        callLst[:] = [] +        divmod(testme,1) +        self.assertCallStack([("__divmod__", (testme, 1))]) -class C2: -    def __eq__(self, other): return 1 +        callLst[:] = [] +        divmod(1, testme) +        self.assertCallStack([("__rdivmod__", (testme, 1))]) -check_exc("hash(C2())", TypeError) - -# Test for SF bug 532646 - -class A: -    pass -A.__call__ = A() -a = A() -try: -    a() # This should not segfault -except RuntimeError: -    pass -else: -    raise TestFailed, "how could this not have overflowed the stack?" - - -# Tests for exceptions raised in instance_getattr2(). - -def booh(self): -    raise AttributeError, "booh" - -class A: -    a = property(booh) -try: -    A().a # Raised AttributeError: A instance has no attribute 'a' -except AttributeError as x: -    if str(x) != "booh": -        print("attribute error for A().a got masked:", str(x)) - -class E: -    __eq__ = property(booh) -E() == E() # In debug mode, caused a C-level assert() to fail - -class I: -    __init__ = property(booh) -try: -    I() # In debug mode, printed XXX undetected error and raises AttributeError -except AttributeError as x: -    pass -else: -    print("attribute error for I.__init__ got masked") - - -# Test comparison and hash of methods -class A: -    def __init__(self, x): -        self.x = x -    def f(self): -        pass -    def g(self): -        pass -    def __eq__(self, other): -        return self.x == other.x -    def __hash__(self): -        return self.x -class B(A): -    pass +        callLst[:] = [] +        testme ** 1 +        self.assertCallStack([("__pow__", (testme, 1))]) -a1 = A(1) -a2 = A(2) -assert a1.f == a1.f -assert a1.f != a2.f -assert a1.f != a1.g -assert a1.f == A(1).f -assert hash(a1.f) == hash(a1.f) -assert hash(a1.f) == hash(A(1).f) - -assert A.f != a1.f -assert A.f != A.g -assert B.f == A.f -assert hash(B.f) == hash(A.f) - -# the following triggers a SystemError in 2.4 -a = A(hash(A.f.im_func)^(-1)) -hash(a.f) +        callLst[:] = [] +        1 ** testme +        self.assertCallStack([("__rpow__", (testme, 1))]) + +        callLst[:] = [] +        testme >> 1 +        self.assertCallStack([("__rshift__", (testme, 1))]) + +        callLst[:] = [] +        1 >> testme +        self.assertCallStack([("__rrshift__", (testme, 1))]) + +        callLst[:] = [] +        testme << 1 +        self.assertCallStack([("__lshift__", (testme, 1))]) + +        callLst[:] = [] +        1 << testme +        self.assertCallStack([("__rlshift__", (testme, 1))]) + +        callLst[:] = [] +        testme & 1 +        self.assertCallStack([("__and__", (testme, 1))]) + +        callLst[:] = [] +        1 & testme +        self.assertCallStack([("__rand__", (testme, 1))]) + +        callLst[:] = [] +        testme | 1 +        self.assertCallStack([("__or__", (testme, 1))]) + +        callLst[:] = [] +        1 | testme +        self.assertCallStack([("__ror__", (testme, 1))]) + +        callLst[:] = [] +        testme ^ 1 +        self.assertCallStack([("__xor__", (testme, 1))]) + +        callLst[:] = [] +        1 ^ testme +        self.assertCallStack([("__rxor__", (testme, 1))]) + +    def testListAndDictOps(self): +        testme = AllTests() + +        # List/dict operations + +        class Empty: pass + +        try: +            1 in Empty() +            self.fail('failed, should have raised TypeError') +        except TypeError: +            pass + +        callLst[:] = [] +        1 in testme +        self.assertCallStack([('__contains__', (testme, 1))]) + +        callLst[:] = [] +        testme[1] +        self.assertCallStack([('__getitem__', (testme, 1))]) + +        callLst[:] = [] +        testme[1] = 1 +        self.assertCallStack([('__setitem__', (testme, 1, 1))]) + +        callLst[:] = [] +        del testme[1] +        self.assertCallStack([('__delitem__', (testme, 1))]) + +        callLst[:] = [] +        testme[:42] +        self.assertCallStack([('__getslice__', (testme, 0, 42))]) + +        callLst[:] = [] +        testme[:42] = "The Answer" +        self.assertCallStack([('__setslice__', (testme, 0, 42, "The Answer"))]) + +        callLst[:] = [] +        del testme[:42] +        self.assertCallStack([('__delslice__', (testme, 0, 42))]) + +        callLst[:] = [] +        testme[2:1024:10] +        self.assertCallStack([('__getitem__', (testme, slice(2, 1024, 10)))]) + +        callLst[:] = [] +        testme[2:1024:10] = "A lot" +        self.assertCallStack([('__setitem__', (testme, slice(2, 1024, 10), +                                                                    "A lot"))]) +        callLst[:] = [] +        del testme[2:1024:10] +        self.assertCallStack([('__delitem__', (testme, slice(2, 1024, 10)))]) + +        callLst[:] = [] +        testme[:42, ..., :24:, 24, 100] +        self.assertCallStack([('__getitem__', (testme, (slice(None, 42, None), +                                                        Ellipsis, +                                                        slice(None, 24, None), +                                                        24, 100)))]) +        callLst[:] = [] +        testme[:42, ..., :24:, 24, 100] = "Strange" +        self.assertCallStack([('__setitem__', (testme, (slice(None, 42, None), +                                                        Ellipsis, +                                                        slice(None, 24, None), +                                                        24, 100), "Strange"))]) +        callLst[:] = [] +        del testme[:42, ..., :24:, 24, 100] +        self.assertCallStack([('__delitem__', (testme, (slice(None, 42, None), +                                                        Ellipsis, +                                                        slice(None, 24, None), +                                                        24, 100)))]) + +        # Now remove the slice hooks to see if converting normal slices to +        #  slice object works. + +        getslice = AllTests.__getslice__ +        del AllTests.__getslice__ +        setslice = AllTests.__setslice__ +        del AllTests.__setslice__ +        delslice = AllTests.__delslice__ +        del AllTests.__delslice__ + +        # XXX when using new-style classes the slice testme[:42] produces +        #  slice(None, 42, None) instead of slice(0, 42, None). py3k will have +        #  to change this test. +        callLst[:] = [] +        testme[0:42] +        self.assertCallStack([('__getitem__', (testme, slice(0, 42, None)))]) + +        callLst[:] = [] +        testme[:42] = "The Answer" +        self.assertCallStack([('__setitem__', (testme, slice(None, 42, None), +                                                                "The Answer"))]) +        callLst[:] = [] +        del testme[0:42] +        self.assertCallStack([('__delitem__', (testme, slice(0, 42, None)))]) + +        # Restore the slice methods, or the tests will fail with regrtest -R. +        AllTests.__getslice__ = getslice +        AllTests.__setslice__ = setslice +        AllTests.__delslice__ = delslice + + +    def testUnaryOps(self): +        testme = AllTests() + +        callLst[:] = [] +        -testme +        self.assertCallStack([('__neg__', (testme,))]) +        callLst[:] = [] +        +testme +        self.assertCallStack([('__pos__', (testme,))]) +        callLst[:] = [] +        abs(testme) +        self.assertCallStack([('__abs__', (testme,))]) +        callLst[:] = [] +        int(testme) +        self.assertCallStack([('__int__', (testme,))]) +        callLst[:] = [] +        float(testme) +        self.assertCallStack([('__float__', (testme,))]) +        callLst[:] = [] +        oct(testme) +        self.assertCallStack([('__index__', (testme,))]) +        callLst[:] = [] +        hex(testme) +        self.assertCallStack([('__index__', (testme,))]) + + +    def testMisc(self): +        testme = AllTests() + +        callLst[:] = [] +        hash(testme) +        self.assertCallStack([('__hash__', (testme,))]) + +        callLst[:] = [] +        repr(testme) +        self.assertCallStack([('__repr__', (testme,))]) + +        callLst[:] = [] +        str(testme) +        self.assertCallStack([('__str__', (testme,))]) + +        callLst[:] = [] +        testme == 1 +        self.assertCallStack([('__eq__', (testme, 1))]) + +        callLst[:] = [] +        testme < 1 +        self.assertCallStack([('__lt__', (testme, 1))]) + +        callLst[:] = [] +        testme > 1 +        self.assertCallStack([('__gt__', (testme, 1))]) + +        callLst[:] = [] +        testme != 1 +        self.assertCallStack([('__ne__', (testme, 1))]) + +        callLst[:] = [] +        1 == testme +        self.assertCallStack([('__eq__', (1, testme))]) + +        callLst[:] = [] +        1 < testme +        self.assertCallStack([('__gt__', (1, testme))]) + +        callLst[:] = [] +        1 > testme +        self.assertCallStack([('__lt__', (1, testme))]) + +        callLst[:] = [] +        1 != testme +        self.assertCallStack([('__ne__', (1, testme))]) + + +    def testGetSetAndDel(self): +        # Interfering tests +        class ExtraTests(AllTests): +            @trackCall +            def __getattr__(self, *args): +                return "SomeVal" + +            @trackCall +            def __setattr__(self, *args): +                pass + +            @trackCall +            def __delattr__(self, *args): +                pass + +        testme = ExtraTests() + +        callLst[:] = [] +        testme.spam +        self.assertCallStack([('__getattr__', (testme, "spam"))]) + +        callLst[:] = [] +        testme.eggs = "spam, spam, spam and ham" +        self.assertCallStack([('__setattr__', (testme, "eggs", +                                               "spam, spam, spam and ham"))]) + +        callLst[:] = [] +        del testme.cardinal +        self.assertCallStack([('__delattr__', (testme, "cardinal"))]) + +    def testDel(self): +        x = [] + +        class DelTest: +            def __del__(self): +                x.append("crab people, crab people") +        testme = DelTest() +        del testme +        import gc +        gc.collect() +        self.assertEquals(["crab people, crab people"], x) + +    def testBadTypeReturned(self): +        # return values of some method are type-checked +        class BadTypeClass: +            def __int__(self): +                return None +            __float__ = __int__ +            __str__ = __int__ +            __repr__ = __int__ +            __oct__ = __int__ +            __hex__ = __int__ + +        for f in [int, float, str, repr, oct, hex]: +            self.assertRaises(TypeError, f, BadTypeClass()) + +    def testHashStuff(self): +        # Test correct errors from hash() on objects with comparisons but +        #  no __hash__ + +        class C0: +            pass + +        hash(C0()) # This should work; the next two should raise TypeError + +        class C1: +            def __cmp__(self, other): return 0 + +        self.assertRaises(TypeError, hash, C1()) + +        class C2: +            def __eq__(self, other): return 1 + +        self.assertRaises(TypeError, hash, C2()) + + +    def testSFBug532646(self): +        # Test for SF bug 532646 + +        class A: +            pass +        A.__call__ = A() +        a = A() + +        try: +            a() # This should not segfault +        except RuntimeError: +            pass +        else: +            self.fail("Failed to raise RuntimeError") + +    def testForExceptionsRaisedInInstanceGetattr2(self): +        # Tests for exceptions raised in instance_getattr2(). + +        def booh(self): +            raise AttributeError("booh") + +        class A: +            a = property(booh) +        try: +            A().a # Raised AttributeError: A instance has no attribute 'a' +        except AttributeError as x: +            if str(x) != "booh": +                self.fail("attribute error for A().a got masked: %s" % x) + +        class E: +            __eq__ = property(booh) +        E() == E() # In debug mode, caused a C-level assert() to fail + +        class I: +            __init__ = property(booh) +        try: +            # In debug mode, printed XXX undetected error and +            #  raises AttributeError +            I() +        except AttributeError as x: +            pass +        else: +            self.fail("attribute error for I.__init__ got masked") + +    def testHashComparisonOfMethods(self): +        # Test comparison and hash of methods +        class A: +            def __init__(self, x): +                self.x = x +            def f(self): +                pass +            def g(self): +                pass +            def __eq__(self, other): +                return self.x == other.x +            def __hash__(self): +                return self.x +        class B(A): +            pass + +        a1 = A(1) +        a2 = A(2) +        self.assertEquals(a1.f, a1.f) +        self.assertNotEquals(a1.f, a2.f) +        self.assertNotEquals(a1.f, a1.g) +        self.assertEquals(a1.f, A(1).f) +        self.assertEquals(hash(a1.f), hash(a1.f)) +        self.assertEquals(hash(a1.f), hash(A(1).f)) + +        self.assertNotEquals(A.f, a1.f) +        self.assertNotEquals(A.f, A.g) +        self.assertEquals(B.f, A.f) +        self.assertEquals(hash(B.f), hash(A.f)) + +        # the following triggers a SystemError in 2.4 +        a = A(hash(A.f.im_func)^(-1)) +        hash(a.f) + +def test_main(): +    test_support.run_unittest(ClassTests) + +if __name__=='__main__': +    test_main()  | 
