# Copyright 2007 Google, Inc. All Rights Reserved.
# Licensed to PSF under a Contributor Agreement.

"""Unit tests for abc.py."""

import unittest, weakref
from test import test_support

import abc
from inspect import isabstract


class TestABC(unittest.TestCase):

    def test_abstractmethod_basics(self):
        @abc.abstractmethod
        def foo(self): pass
        self.assertTrue(foo.__isabstractmethod__)
        def bar(self): pass
        self.assertFalse(hasattr(bar, "__isabstractmethod__"))

    def test_abstractproperty_basics(self):
        @abc.abstractproperty
        def foo(self): pass
        self.assertTrue(foo.__isabstractmethod__)
        def bar(self): pass
        self.assertFalse(hasattr(bar, "__isabstractmethod__"))

        class C:
            __metaclass__ = abc.ABCMeta
            @abc.abstractproperty
            def foo(self): return 3
        class D(C):
            @property
            def foo(self): return super(D, self).foo
        self.assertEqual(D().foo, 3)

    def test_abstractmethod_integration(self):
        for abstractthing in [abc.abstractmethod, abc.abstractproperty]:
            class C:
                __metaclass__ = abc.ABCMeta
                @abstractthing
                def foo(self): pass  # abstract
                def bar(self): pass  # concrete
            self.assertEqual(C.__abstractmethods__, set(["foo"]))
            self.assertRaises(TypeError, C)  # because foo is abstract
            self.assertTrue(isabstract(C))
            class D(C):
                def bar(self): pass  # concrete override of concrete
            self.assertEqual(D.__abstractmethods__, set(["foo"]))
            self.assertRaises(TypeError, D)  # because foo is still abstract
            self.assertTrue(isabstract(D))
            class E(D):
                def foo(self): pass
            self.assertEqual(E.__abstractmethods__, set())
            E()  # now foo is concrete, too
            self.assertFalse(isabstract(E))
            class F(E):
                @abstractthing
                def bar(self): pass  # abstract override of concrete
            self.assertEqual(F.__abstractmethods__, set(["bar"]))
            self.assertRaises(TypeError, F)  # because bar is abstract now
            self.assertTrue(isabstract(F))

    def test_subclass_oldstyle_class(self):
        class A:
            __metaclass__ = abc.ABCMeta
        class OldstyleClass:
            pass
        self.assertFalse(issubclass(OldstyleClass, A))
        self.assertFalse(issubclass(A, OldstyleClass))

    def test_isinstance_class(self):
        class A:
            __metaclass__ = abc.ABCMeta
        class OldstyleClass:
            pass
        self.assertFalse(isinstance(OldstyleClass, A))
        self.assertTrue(isinstance(OldstyleClass, type(OldstyleClass)))
        self.assertFalse(isinstance(A, OldstyleClass))
        # This raises a recursion depth error, but is low-priority:
        # self.assertTrue(isinstance(A, abc.ABCMeta))

    def test_registration_basics(self):
        class A:
            __metaclass__ = abc.ABCMeta
        class B(object):
            pass
        b = B()
        self.assertFalse(issubclass(B, A))
        self.assertFalse(issubclass(B, (A,)))
        self.assertNotIsInstance(b, A)
        self.assertNotIsInstance(b, (A,))
        A.register(B)
        self.assertTrue(issubclass(B, A))
        self.assertTrue(issubclass(B, (A,)))
        self.assertIsInstance(b, A)
        self.assertIsInstance(b, (A,))
        class C(B):
            pass
        c = C()
        self.assertTrue(issubclass(C, A))
        self.assertTrue(issubclass(C, (A,)))
        self.assertIsInstance(c, A)
        self.assertIsInstance(c, (A,))

    def test_isinstance_invalidation(self):
        class A:
            __metaclass__ = abc.ABCMeta
        class B(object):
            pass
        b = B()
        self.assertFalse(isinstance(b, A))
        self.assertFalse(isinstance(b, (A,)))
        A.register(B)
        self.assertTrue(isinstance(b, A))
        self.assertTrue(isinstance(b, (A,)))

    def test_registration_builtins(self):
        class A:
            __metaclass__ = abc.ABCMeta
        A.register(int)
        self.assertIsInstance(42, A)
        self.assertIsInstance(42, (A,))
        self.assertTrue(issubclass(int, A))
        self.assertTrue(issubclass(int, (A,)))
        class B(A):
            pass
        B.register(basestring)
        self.assertIsInstance("", A)
        self.assertIsInstance("", (A,))
        self.assertTrue(issubclass(str, A))
        self.assertTrue(issubclass(str, (A,)))

    def test_registration_edge_cases(self):
        class A:
            __metaclass__ = abc.ABCMeta
        A.register(A)  # should pass silently
        class A1(A):
            pass
        self.assertRaises(RuntimeError, A1.register, A)  # cycles not allowed
        class B(object):
            pass
        A1.register(B)  # ok
        A1.register(B)  # should pass silently
        class C(A):
            pass
        A.register(C)  # should pass silently
        self.assertRaises(RuntimeError, C.register, A)  # cycles not allowed
        C.register(B)  # ok

    def test_register_non_class(self):
        class A(object):
            __metaclass__ = abc.ABCMeta
        self.assertRaisesRegexp(TypeError, "Can only register classes",
                                A.register, 4)

    def test_registration_transitiveness(self):
        class A:
            __metaclass__ = abc.ABCMeta
        self.assertTrue(issubclass(A, A))
        self.assertTrue(issubclass(A, (A,)))
        class B:
            __metaclass__ = abc.ABCMeta
        self.assertFalse(issubclass(A, B))
        self.assertFalse(issubclass(A, (B,)))
        self.assertFalse(issubclass(B, A))
        self.assertFalse(issubclass(B, (A,)))
        class C:
            __metaclass__ = abc.ABCMeta
        A.register(B)
        class B1(B):
            pass
        self.assertTrue(issubclass(B1, A))
        self.assertTrue(issubclass(B1, (A,)))
        class C1(C):
            pass
        B1.register(C1)
        self.assertFalse(issubclass(C, B))
        self.assertFalse(issubclass(C, (B,)))
        self.assertFalse(issubclass(C, B1))
        self.assertFalse(issubclass(C, (B1,)))
        self.assertTrue(issubclass(C1, A))
        self.assertTrue(issubclass(C1, (A,)))
        self.assertTrue(issubclass(C1, B))
        self.assertTrue(issubclass(C1, (B,)))
        self.assertTrue(issubclass(C1, B1))
        self.assertTrue(issubclass(C1, (B1,)))
        C1.register(int)
        class MyInt(int):
            pass
        self.assertTrue(issubclass(MyInt, A))
        self.assertTrue(issubclass(MyInt, (A,)))
        self.assertIsInstance(42, A)
        self.assertIsInstance(42, (A,))

    def test_all_new_methods_are_called(self):
        class A:
            __metaclass__ = abc.ABCMeta
        class B(object):
            counter = 0
            def __new__(cls):
                B.counter += 1
                return super(B, cls).__new__(cls)
        class C(A, B):
            pass
        self.assertEqual(B.counter, 0)
        C()
        self.assertEqual(B.counter, 1)

    def test_cache_leak(self):
        # See issue #2521.
        class A(object):
            __metaclass__ = abc.ABCMeta
            @abc.abstractmethod
            def f(self):
                pass
        class C(A):
            def f(self):
                A.f(self)
        r = weakref.ref(C)
        # Trigger cache.
        C().f()
        del C
        test_support.gc_collect()
        self.assertEqual(r(), None)

def test_main():
    test_support.run_unittest(TestABC)


if __name__ == "__main__":
    unittest.main()
