summaryrefslogtreecommitdiffstats
path: root/Lib/test/test_capi.py
diff options
context:
space:
mode:
Diffstat (limited to 'Lib/test/test_capi.py')
-rw-r--r--Lib/test/test_capi.py86
1 files changed, 86 insertions, 0 deletions
diff --git a/Lib/test/test_capi.py b/Lib/test/test_capi.py
index 7b35ba6..4d6e2f2 100644
--- a/Lib/test/test_capi.py
+++ b/Lib/test/test_capi.py
@@ -383,6 +383,92 @@ class CAPITest(unittest.TestCase):
del L
self.assertEqual(PyList.num, 0)
+ def test_subclass_of_heap_gc_ctype_with_tpdealloc_decrefs_once(self):
+ class HeapGcCTypeSubclass(_testcapi.HeapGcCType):
+ def __init__(self):
+ self.value2 = 20
+ super().__init__()
+
+ subclass_instance = HeapGcCTypeSubclass()
+ type_refcnt = sys.getrefcount(HeapGcCTypeSubclass)
+
+ # Test that subclass instance was fully created
+ self.assertEqual(subclass_instance.value, 10)
+ self.assertEqual(subclass_instance.value2, 20)
+
+ # Test that the type reference count is only decremented once
+ del subclass_instance
+ self.assertEqual(type_refcnt - 1, sys.getrefcount(HeapGcCTypeSubclass))
+
+ def test_subclass_of_heap_gc_ctype_with_del_modifying_dunder_class_only_decrefs_once(self):
+ class A(_testcapi.HeapGcCType):
+ def __init__(self):
+ self.value2 = 20
+ super().__init__()
+
+ class B(A):
+ def __init__(self):
+ super().__init__()
+
+ def __del__(self):
+ self.__class__ = A
+ A.refcnt_in_del = sys.getrefcount(A)
+ B.refcnt_in_del = sys.getrefcount(B)
+
+ subclass_instance = B()
+ type_refcnt = sys.getrefcount(B)
+ new_type_refcnt = sys.getrefcount(A)
+
+ # Test that subclass instance was fully created
+ self.assertEqual(subclass_instance.value, 10)
+ self.assertEqual(subclass_instance.value2, 20)
+
+ del subclass_instance
+
+ # Test that setting __class__ modified the reference counts of the types
+ self.assertEqual(type_refcnt - 1, B.refcnt_in_del)
+ self.assertEqual(new_type_refcnt + 1, A.refcnt_in_del)
+
+ # Test that the original type already has decreased its refcnt
+ self.assertEqual(type_refcnt - 1, sys.getrefcount(B))
+
+ # Test that subtype_dealloc decref the newly assigned __class__ only once
+ self.assertEqual(new_type_refcnt, sys.getrefcount(A))
+
+ def test_c_subclass_of_heap_ctype_with_tpdealloc_decrefs_once(self):
+ subclass_instance = _testcapi.HeapCTypeSubclass()
+ type_refcnt = sys.getrefcount(_testcapi.HeapCTypeSubclass)
+
+ # Test that subclass instance was fully created
+ self.assertEqual(subclass_instance.value, 10)
+ self.assertEqual(subclass_instance.value2, 20)
+
+ # Test that the type reference count is only decremented once
+ del subclass_instance
+ self.assertEqual(type_refcnt - 1, sys.getrefcount(_testcapi.HeapCTypeSubclass))
+
+ def test_c_subclass_of_heap_ctype_with_del_modifying_dunder_class_only_decrefs_once(self):
+ subclass_instance = _testcapi.HeapCTypeSubclassWithFinalizer()
+ type_refcnt = sys.getrefcount(_testcapi.HeapCTypeSubclassWithFinalizer)
+ new_type_refcnt = sys.getrefcount(_testcapi.HeapCTypeSubclass)
+
+ # Test that subclass instance was fully created
+ self.assertEqual(subclass_instance.value, 10)
+ self.assertEqual(subclass_instance.value2, 20)
+
+ # The tp_finalize slot will set __class__ to HeapCTypeSubclass
+ del subclass_instance
+
+ # Test that setting __class__ modified the reference counts of the types
+ self.assertEqual(type_refcnt - 1, _testcapi.HeapCTypeSubclassWithFinalizer.refcnt_in_del)
+ self.assertEqual(new_type_refcnt + 1, _testcapi.HeapCTypeSubclass.refcnt_in_del)
+
+ # Test that the original type already has decreased its refcnt
+ self.assertEqual(type_refcnt - 1, sys.getrefcount(_testcapi.HeapCTypeSubclassWithFinalizer))
+
+ # Test that subtype_dealloc decref the newly assigned __class__ only once
+ self.assertEqual(new_type_refcnt, sys.getrefcount(_testcapi.HeapCTypeSubclass))
+
class TestPendingCalls(unittest.TestCase):