1# Copyright 2007 Google, Inc. All Rights Reserved.
2# Licensed to PSF under a Contributor Agreement.
3
4"""Unit tests for abc.py."""
5
6import unittest, weakref
7from test import test_support
8
9import abc
10from inspect import isabstract
11
12
13class TestABC(unittest.TestCase):
14
15    def test_abstractmethod_basics(self):
16        @abc.abstractmethod
17        def foo(self): pass
18        self.assertTrue(foo.__isabstractmethod__)
19        def bar(self): pass
20        self.assertFalse(hasattr(bar, "__isabstractmethod__"))
21
22    def test_abstractproperty_basics(self):
23        @abc.abstractproperty
24        def foo(self): pass
25        self.assertTrue(foo.__isabstractmethod__)
26        def bar(self): pass
27        self.assertFalse(hasattr(bar, "__isabstractmethod__"))
28
29        class C:
30            __metaclass__ = abc.ABCMeta
31            @abc.abstractproperty
32            def foo(self): return 3
33        class D(C):
34            @property
35            def foo(self): return super(D, self).foo
36        self.assertEqual(D().foo, 3)
37
38    def test_abstractmethod_integration(self):
39        for abstractthing in [abc.abstractmethod, abc.abstractproperty]:
40            class C:
41                __metaclass__ = abc.ABCMeta
42                @abstractthing
43                def foo(self): pass  # abstract
44                def bar(self): pass  # concrete
45            self.assertEqual(C.__abstractmethods__, set(["foo"]))
46            self.assertRaises(TypeError, C)  # because foo is abstract
47            self.assertTrue(isabstract(C))
48            class D(C):
49                def bar(self): pass  # concrete override of concrete
50            self.assertEqual(D.__abstractmethods__, set(["foo"]))
51            self.assertRaises(TypeError, D)  # because foo is still abstract
52            self.assertTrue(isabstract(D))
53            class E(D):
54                def foo(self): pass
55            self.assertEqual(E.__abstractmethods__, set())
56            E()  # now foo is concrete, too
57            self.assertFalse(isabstract(E))
58            class F(E):
59                @abstractthing
60                def bar(self): pass  # abstract override of concrete
61            self.assertEqual(F.__abstractmethods__, set(["bar"]))
62            self.assertRaises(TypeError, F)  # because bar is abstract now
63            self.assertTrue(isabstract(F))
64
65    def test_subclass_oldstyle_class(self):
66        class A:
67            __metaclass__ = abc.ABCMeta
68        class OldstyleClass:
69            pass
70        self.assertFalse(issubclass(OldstyleClass, A))
71        self.assertFalse(issubclass(A, OldstyleClass))
72
73    def test_isinstance_class(self):
74        class A:
75            __metaclass__ = abc.ABCMeta
76        class OldstyleClass:
77            pass
78        self.assertFalse(isinstance(OldstyleClass, A))
79        self.assertTrue(isinstance(OldstyleClass, type(OldstyleClass)))
80        self.assertFalse(isinstance(A, OldstyleClass))
81        # This raises a recursion depth error, but is low-priority:
82        # self.assertTrue(isinstance(A, abc.ABCMeta))
83
84    def test_registration_basics(self):
85        class A:
86            __metaclass__ = abc.ABCMeta
87        class B(object):
88            pass
89        b = B()
90        self.assertFalse(issubclass(B, A))
91        self.assertFalse(issubclass(B, (A,)))
92        self.assertNotIsInstance(b, A)
93        self.assertNotIsInstance(b, (A,))
94        A.register(B)
95        self.assertTrue(issubclass(B, A))
96        self.assertTrue(issubclass(B, (A,)))
97        self.assertIsInstance(b, A)
98        self.assertIsInstance(b, (A,))
99        class C(B):
100            pass
101        c = C()
102        self.assertTrue(issubclass(C, A))
103        self.assertTrue(issubclass(C, (A,)))
104        self.assertIsInstance(c, A)
105        self.assertIsInstance(c, (A,))
106
107    def test_isinstance_invalidation(self):
108        class A:
109            __metaclass__ = abc.ABCMeta
110        class B(object):
111            pass
112        b = B()
113        self.assertFalse(isinstance(b, A))
114        self.assertFalse(isinstance(b, (A,)))
115        A.register(B)
116        self.assertTrue(isinstance(b, A))
117        self.assertTrue(isinstance(b, (A,)))
118
119    def test_registration_builtins(self):
120        class A:
121            __metaclass__ = abc.ABCMeta
122        A.register(int)
123        self.assertIsInstance(42, A)
124        self.assertIsInstance(42, (A,))
125        self.assertTrue(issubclass(int, A))
126        self.assertTrue(issubclass(int, (A,)))
127        class B(A):
128            pass
129        B.register(basestring)
130        self.assertIsInstance("", A)
131        self.assertIsInstance("", (A,))
132        self.assertTrue(issubclass(str, A))
133        self.assertTrue(issubclass(str, (A,)))
134
135    def test_registration_edge_cases(self):
136        class A:
137            __metaclass__ = abc.ABCMeta
138        A.register(A)  # should pass silently
139        class A1(A):
140            pass
141        self.assertRaises(RuntimeError, A1.register, A)  # cycles not allowed
142        class B(object):
143            pass
144        A1.register(B)  # ok
145        A1.register(B)  # should pass silently
146        class C(A):
147            pass
148        A.register(C)  # should pass silently
149        self.assertRaises(RuntimeError, C.register, A)  # cycles not allowed
150        C.register(B)  # ok
151
152    def test_register_non_class(self):
153        class A(object):
154            __metaclass__ = abc.ABCMeta
155        self.assertRaisesRegexp(TypeError, "Can only register classes",
156                                A.register, 4)
157
158    def test_registration_transitiveness(self):
159        class A:
160            __metaclass__ = abc.ABCMeta
161        self.assertTrue(issubclass(A, A))
162        self.assertTrue(issubclass(A, (A,)))
163        class B:
164            __metaclass__ = abc.ABCMeta
165        self.assertFalse(issubclass(A, B))
166        self.assertFalse(issubclass(A, (B,)))
167        self.assertFalse(issubclass(B, A))
168        self.assertFalse(issubclass(B, (A,)))
169        class C:
170            __metaclass__ = abc.ABCMeta
171        A.register(B)
172        class B1(B):
173            pass
174        self.assertTrue(issubclass(B1, A))
175        self.assertTrue(issubclass(B1, (A,)))
176        class C1(C):
177            pass
178        B1.register(C1)
179        self.assertFalse(issubclass(C, B))
180        self.assertFalse(issubclass(C, (B,)))
181        self.assertFalse(issubclass(C, B1))
182        self.assertFalse(issubclass(C, (B1,)))
183        self.assertTrue(issubclass(C1, A))
184        self.assertTrue(issubclass(C1, (A,)))
185        self.assertTrue(issubclass(C1, B))
186        self.assertTrue(issubclass(C1, (B,)))
187        self.assertTrue(issubclass(C1, B1))
188        self.assertTrue(issubclass(C1, (B1,)))
189        C1.register(int)
190        class MyInt(int):
191            pass
192        self.assertTrue(issubclass(MyInt, A))
193        self.assertTrue(issubclass(MyInt, (A,)))
194        self.assertIsInstance(42, A)
195        self.assertIsInstance(42, (A,))
196
197    def test_all_new_methods_are_called(self):
198        class A:
199            __metaclass__ = abc.ABCMeta
200        class B(object):
201            counter = 0
202            def __new__(cls):
203                B.counter += 1
204                return super(B, cls).__new__(cls)
205        class C(A, B):
206            pass
207        self.assertEqual(B.counter, 0)
208        C()
209        self.assertEqual(B.counter, 1)
210
211    def test_cache_leak(self):
212        # See issue #2521.
213        class A(object):
214            __metaclass__ = abc.ABCMeta
215            @abc.abstractmethod
216            def f(self):
217                pass
218        class C(A):
219            def f(self):
220                A.f(self)
221        r = weakref.ref(C)
222        # Trigger cache.
223        C().f()
224        del C
225        test_support.gc_collect()
226        self.assertEqual(r(), None)
227
228def test_main():
229    test_support.run_unittest(TestABC)
230
231
232if __name__ == "__main__":
233    unittest.main()
234