"Test the functionality of Python classes implementing operators."



import unittest



from test import test_support



testmeths = [



# Binary operations

    "add",

    "radd",

    "sub",

    "rsub",

    "mul",

    "rmul",

    "div",

    "rdiv",

    "mod",

    "rmod",

    "divmod",

    "rdivmod",

    "pow",

    "rpow",

    "rshift",

    "rrshift",

    "lshift",

    "rlshift",

    "and",

    "rand",

    "or",

    "ror",

    "xor",

    "rxor",



# List/dict operations

    "contains",

    "getitem",

    "getslice",

    "setitem",

    "setslice",

    "delitem",

    "delslice",



# Unary operations

    "neg",

    "pos",

    "abs",



# generic operations

    "init",

    ]



# These need to return something other than None

#    "coerce",

#    "hash",

#    "str",

#    "repr",

#    "int",

#    "long",

#    "float",

#    "oct",

#    "hex",



# These are separate because they can influence the test of other methods.

#    "getattr",

#    "setattr",

#    "delattr",



callLst = []

def trackCall(f):

    def track(*args, **kwargs):

        callLst.append((f.__name__, args))

        return f(*args, **kwargs)

    return track



class AllTests:

    trackCall = trackCall



    @trackCall

    def __coerce__(self, *args):

        return (self,) + args



    @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 __float__(self, *args):

        return 1.0



    @trackCall

    def __long__(self, *args):

        return 1L



    @trackCall

    def __oct__(self, *args):

        return '01'



    @trackCall

    def __hex__(self, *args):

        return '0x1'



    @trackCall

    def __cmp__(self, *args):

        return 0



# Synthesize all the other AllTests methods from the names in testmeths.



method_template = """\

@trackCall

def __%(method)s__(self, *args):

    pass

"""



for method in testmeths:

    exec method_template % locals() in AllTests.__dict__



del method, method_template



class ClassTests(unittest.TestCase):

    def setUp(self):

        callLst[:] = []



    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))



    def testInit(self):

        foo = AllTests()

        self.assertCallStack([("__init__", (foo,))])



    def testBinaryOps(self):

        testme = AllTests()

        # Binary operations



        callLst[:] = []

        testme + 1

        self.assertCallStack([("__coerce__", (testme, 1)), ("__add__", (testme, 1))])



        callLst[:] = []

        1 + testme

        self.assertCallStack([("__coerce__", (testme, 1)), ("__radd__", (testme, 1))])



        callLst[:] = []

        testme - 1

        self.assertCallStack([("__coerce__", (testme, 1)), ("__sub__", (testme, 1))])



        callLst[:] = []

        1 - testme

        self.assertCallStack([("__coerce__", (testme, 1)), ("__rsub__", (testme, 1))])



        callLst[:] = []

        testme * 1

        self.assertCallStack([("__coerce__", (testme, 1)), ("__mul__", (testme, 1))])



        callLst[:] = []

        1 * testme

        self.assertCallStack([("__coerce__", (testme, 1)), ("__rmul__", (testme, 1))])



        if 1/2 == 0:

            callLst[:] = []

            testme / 1

            self.assertCallStack([("__coerce__", (testme, 1)), ("__div__", (testme, 1))])





            callLst[:] = []

            1 / testme

            self.assertCallStack([("__coerce__", (testme, 1)), ("__rdiv__", (testme, 1))])



        callLst[:] = []

        testme % 1

        self.assertCallStack([("__coerce__", (testme, 1)), ("__mod__", (testme, 1))])



        callLst[:] = []

        1 % testme

        self.assertCallStack([("__coerce__", (testme, 1)), ("__rmod__", (testme, 1))])





        callLst[:] = []

        divmod(testme,1)

        self.assertCallStack([("__coerce__", (testme, 1)), ("__divmod__", (testme, 1))])



        callLst[:] = []

        divmod(1, testme)

        self.assertCallStack([("__coerce__", (testme, 1)), ("__rdivmod__", (testme, 1))])



        callLst[:] = []

        testme ** 1

        self.assertCallStack([("__coerce__", (testme, 1)), ("__pow__", (testme, 1))])



        callLst[:] = []

        1 ** testme

        self.assertCallStack([("__coerce__", (testme, 1)), ("__rpow__", (testme, 1))])



        callLst[:] = []

        testme >> 1

        self.assertCallStack([("__coerce__", (testme, 1)), ("__rshift__", (testme, 1))])



        callLst[:] = []

        1 >> testme

        self.assertCallStack([("__coerce__", (testme, 1)), ("__rrshift__", (testme, 1))])



        callLst[:] = []

        testme << 1

        self.assertCallStack([("__coerce__", (testme, 1)), ("__lshift__", (testme, 1))])



        callLst[:] = []

        1 << testme

        self.assertCallStack([("__coerce__", (testme, 1)), ("__rlshift__", (testme, 1))])



        callLst[:] = []

        testme & 1

        self.assertCallStack([("__coerce__", (testme, 1)), ("__and__", (testme, 1))])



        callLst[:] = []

        1 & testme

        self.assertCallStack([("__coerce__", (testme, 1)), ("__rand__", (testme, 1))])



        callLst[:] = []

        testme | 1

        self.assertCallStack([("__coerce__", (testme, 1)), ("__or__", (testme, 1))])



        callLst[:] = []

        1 | testme

        self.assertCallStack([("__coerce__", (testme, 1)), ("__ror__", (testme, 1))])



        callLst[:] = []

        testme ^ 1

        self.assertCallStack([("__coerce__", (testme, 1)), ("__xor__", (testme, 1))])



        callLst[:] = []

        1 ^ testme

        self.assertCallStack([("__coerce__", (testme, 1)), ("__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[:42]

        self.assertCallStack([('__getitem__', (testme, slice(0, 42, None)))])



        callLst[:] = []

        testme[:42] = "The Answer"

        self.assertCallStack([('__setitem__', (testme, slice(0, 42, None),

                                                                "The Answer"))])

        callLst[:] = []

        del testme[: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[:] = []

        long(testme)

        self.assertCallStack([('__long__', (testme,))])

        callLst[:] = []

        float(testme)

        self.assertCallStack([('__float__', (testme,))])

        callLst[:] = []

        oct(testme)

        self.assertCallStack([('__oct__', (testme,))])

        callLst[:] = []

        hex(testme)

        self.assertCallStack([('__hex__', (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([("__coerce__", (testme, 1)), ('__cmp__', (testme, 1))])



        callLst[:] = []

        testme < 1

        self.assertCallStack([("__coerce__", (testme, 1)), ('__cmp__', (testme, 1))])



        callLst[:] = []

        testme > 1

        self.assertCallStack([("__coerce__", (testme, 1)), ('__cmp__', (testme, 1))])



        callLst[:] = []

        testme <> 1  # XXX kill this in py3k

        self.assertCallStack([("__coerce__", (testme, 1)), ('__cmp__', (testme, 1))])



        callLst[:] = []

        testme != 1

        self.assertCallStack([("__coerce__", (testme, 1)), ('__cmp__', (testme, 1))])



        callLst[:] = []

        1 == testme

        self.assertCallStack([("__coerce__", (testme, 1)), ('__cmp__', (1, testme))])



        callLst[:] = []

        1 < testme

        self.assertCallStack([("__coerce__", (testme, 1)), ('__cmp__', (1, testme))])



        callLst[:] = []

        1 > testme

        self.assertCallStack([("__coerce__", (testme, 1)), ('__cmp__', (1, testme))])



        callLst[:] = []

        1 <> testme

        self.assertCallStack([("__coerce__", (testme, 1)), ('__cmp__', (1, testme))])



        callLst[:] = []

        1 != testme

        self.assertCallStack([("__coerce__", (testme, 1)), ('__cmp__', (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__

            __long__ = __int__

            __str__ = __int__

            __repr__ = __int__

            __oct__ = __int__

            __hex__ = __int__



        for f in [int, float, long, str, repr, oct, hex]:

            self.assertRaises(TypeError, f, BadTypeClass())



    def testMixIntsAndLongs(self):

        # mixing up ints and longs is okay

        class IntLongMixClass:

            @trackCall

            def __int__(self):

                return 42L



            @trackCall

            def __long__(self):

                return 64



        mixIntAndLong = IntLongMixClass()



        callLst[:] = []

        as_int = int(mixIntAndLong)

        self.assertEquals(type(as_int), long)

        self.assertEquals(as_int, 42L)

        self.assertCallStack([('__int__', (mixIntAndLong,))])



        callLst[:] = []

        as_long = long(mixIntAndLong)

        self.assertEquals(type(as_long), int)

        self.assertEquals(as_long, 64)

        self.assertCallStack([('__long__', (mixIntAndLong,))])



    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, 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, 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()

