# Augmented assignment test.

from test.test_support import run_unittest, check_py3k_warnings
import unittest


class AugAssignTest(unittest.TestCase):
    def testBasic(self):
        x = 2
        x += 1
        x *= 2
        x **= 2
        x -= 8
        x //= 5
        x %= 3
        x &= 2
        x |= 5
        x ^= 1
        x /= 2
        if 1/2 == 0:
            # classic division
            self.assertEqual(x, 3)
        else:
            # new-style division (with -Qnew)
            self.assertEqual(x, 3.0)

    def test_with_unpacking(self):
        self.assertRaises(SyntaxError, compile, "x, b += 3", "<test>", "exec")

    def testInList(self):
        x = [2]
        x[0] += 1
        x[0] *= 2
        x[0] **= 2
        x[0] -= 8
        x[0] //= 5
        x[0] %= 3
        x[0] &= 2
        x[0] |= 5
        x[0] ^= 1
        x[0] /= 2
        if 1/2 == 0:
            self.assertEqual(x[0], 3)
        else:
            self.assertEqual(x[0], 3.0)

    def testInDict(self):
        x = {0: 2}
        x[0] += 1
        x[0] *= 2
        x[0] **= 2
        x[0] -= 8
        x[0] //= 5
        x[0] %= 3
        x[0] &= 2
        x[0] |= 5
        x[0] ^= 1
        x[0] /= 2
        if 1/2 == 0:
            self.assertEqual(x[0], 3)
        else:
            self.assertEqual(x[0], 3.0)

    def testSequences(self):
        x = [1,2]
        x += [3,4]
        x *= 2

        self.assertEqual(x, [1, 2, 3, 4, 1, 2, 3, 4])

        x = [1, 2, 3]
        y = x
        x[1:2] *= 2
        y[1:2] += [1]

        self.assertEqual(x, [1, 2, 1, 2, 3])
        self.assertTrue(x is y)

    def testCustomMethods1(self):

        class aug_test:
            def __init__(self, value):
                self.val = value
            def __radd__(self, val):
                return self.val + val
            def __add__(self, val):
                return aug_test(self.val + val)

        class aug_test2(aug_test):
            def __iadd__(self, val):
                self.val = self.val + val
                return self

        class aug_test3(aug_test):
            def __iadd__(self, val):
                return aug_test3(self.val + val)

        x = aug_test(1)
        y = x
        x += 10

        self.assertIsInstance(x, aug_test)
        self.assertTrue(y is not x)
        self.assertEqual(x.val, 11)

        x = aug_test2(2)
        y = x
        x += 10

        self.assertTrue(y is x)
        self.assertEqual(x.val, 12)

        x = aug_test3(3)
        y = x
        x += 10

        self.assertIsInstance(x, aug_test3)
        self.assertTrue(y is not x)
        self.assertEqual(x.val, 13)


    def testCustomMethods2(test_self):
        output = []

        class testall:
            def __add__(self, val):
                output.append("__add__ called")
            def __radd__(self, val):
                output.append("__radd__ called")
            def __iadd__(self, val):
                output.append("__iadd__ called")
                return self

            def __sub__(self, val):
                output.append("__sub__ called")
            def __rsub__(self, val):
                output.append("__rsub__ called")
            def __isub__(self, val):
                output.append("__isub__ called")
                return self

            def __mul__(self, val):
                output.append("__mul__ called")
            def __rmul__(self, val):
                output.append("__rmul__ called")
            def __imul__(self, val):
                output.append("__imul__ called")
                return self

            def __div__(self, val):
                output.append("__div__ called")
            def __rdiv__(self, val):
                output.append("__rdiv__ called")
            def __idiv__(self, val):
                output.append("__idiv__ called")
                return self

            def __floordiv__(self, val):
                output.append("__floordiv__ called")
                return self
            def __ifloordiv__(self, val):
                output.append("__ifloordiv__ called")
                return self
            def __rfloordiv__(self, val):
                output.append("__rfloordiv__ called")
                return self

            def __truediv__(self, val):
                output.append("__truediv__ called")
                return self
            def __itruediv__(self, val):
                output.append("__itruediv__ called")
                return self

            def __mod__(self, val):
                output.append("__mod__ called")
            def __rmod__(self, val):
                output.append("__rmod__ called")
            def __imod__(self, val):
                output.append("__imod__ called")
                return self

            def __pow__(self, val):
                output.append("__pow__ called")
            def __rpow__(self, val):
                output.append("__rpow__ called")
            def __ipow__(self, val):
                output.append("__ipow__ called")
                return self

            def __or__(self, val):
                output.append("__or__ called")
            def __ror__(self, val):
                output.append("__ror__ called")
            def __ior__(self, val):
                output.append("__ior__ called")
                return self

            def __and__(self, val):
                output.append("__and__ called")
            def __rand__(self, val):
                output.append("__rand__ called")
            def __iand__(self, val):
                output.append("__iand__ called")
                return self

            def __xor__(self, val):
                output.append("__xor__ called")
            def __rxor__(self, val):
                output.append("__rxor__ called")
            def __ixor__(self, val):
                output.append("__ixor__ called")
                return self

            def __rshift__(self, val):
                output.append("__rshift__ called")
            def __rrshift__(self, val):
                output.append("__rrshift__ called")
            def __irshift__(self, val):
                output.append("__irshift__ called")
                return self

            def __lshift__(self, val):
                output.append("__lshift__ called")
            def __rlshift__(self, val):
                output.append("__rlshift__ called")
            def __ilshift__(self, val):
                output.append("__ilshift__ called")
                return self

        x = testall()
        x + 1
        1 + x
        x += 1

        x - 1
        1 - x
        x -= 1

        x * 1
        1 * x
        x *= 1

        if 1/2 == 0:
            x / 1
            1 / x
            x /= 1
        else:
            # True division is in effect, so "/" doesn't map to __div__ etc;
            # but the canned expected-output file requires that those get called.
            x.__div__(1)
            x.__rdiv__(1)
            x.__idiv__(1)

        x // 1
        1 // x
        x //= 1

        x % 1
        1 % x
        x %= 1

        x ** 1
        1 ** x
        x **= 1

        x | 1
        1 | x
        x |= 1

        x & 1
        1 & x
        x &= 1

        x ^ 1
        1 ^ x
        x ^= 1

        x >> 1
        1 >> x
        x >>= 1

        x << 1
        1 << x
        x <<= 1

        test_self.assertEqual(output, '''\
__add__ called
__radd__ called
__iadd__ called
__sub__ called
__rsub__ called
__isub__ called
__mul__ called
__rmul__ called
__imul__ called
__div__ called
__rdiv__ called
__idiv__ called
__floordiv__ called
__rfloordiv__ called
__ifloordiv__ called
__mod__ called
__rmod__ called
__imod__ called
__pow__ called
__rpow__ called
__ipow__ called
__or__ called
__ror__ called
__ior__ called
__and__ called
__rand__ called
__iand__ called
__xor__ called
__rxor__ called
__ixor__ called
__rshift__ called
__rrshift__ called
__irshift__ called
__lshift__ called
__rlshift__ called
__ilshift__ called
'''.splitlines())

def test_main():
    with check_py3k_warnings(("classic int division", DeprecationWarning)):
        run_unittest(AugAssignTest)

if __name__ == '__main__':
    test_main()
