aboutsummaryrefslogtreecommitdiffstats
path: root/sources/pyside6/tests/QtCore/qobject_parent_test.py
diff options
context:
space:
mode:
Diffstat (limited to 'sources/pyside6/tests/QtCore/qobject_parent_test.py')
-rw-r--r--sources/pyside6/tests/QtCore/qobject_parent_test.py335
1 files changed, 335 insertions, 0 deletions
diff --git a/sources/pyside6/tests/QtCore/qobject_parent_test.py b/sources/pyside6/tests/QtCore/qobject_parent_test.py
new file mode 100644
index 000000000..6265f77b1
--- /dev/null
+++ b/sources/pyside6/tests/QtCore/qobject_parent_test.py
@@ -0,0 +1,335 @@
+# Copyright (C) 2022 The Qt Company Ltd.
+# SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
+
+'''Test cases for parent-child relationship'''
+
+import gc
+import os
+import sys
+import unittest
+
+from pathlib import Path
+sys.path.append(os.fspath(Path(__file__).resolve().parents[1]))
+from init_paths import init_test_paths
+init_test_paths(False)
+
+from PySide6.QtCore import QObject, QRegularExpression, QTimer, Qt
+
+
+class TestObject1(QTimer):
+ def __init(self, parent):
+ super().__init__(parent)
+
+
+class TestObject2(TestObject1):
+ def __init(self, parent):
+ super().__init__(parent)
+
+
+class ParentRefCountCase(unittest.TestCase):
+ '''Test case for the refcount changes of setParent'''
+
+ def setUp(self):
+ # Acquire resources
+ self.parent = QObject()
+ self.child = QObject()
+
+ def tearDown(self):
+ # Release resources
+ del self.child
+ del self.parent
+ # PYSIDE-535: Need to collect garbage in PyPy to trigger deletion
+ gc.collect()
+
+ @unittest.skipUnless(hasattr(sys, "getrefcount"), f"{sys.implementation.name} has no refcount")
+ def testSetParent(self):
+ # QObject.setParent() refcount changes
+ self.assertEqual(sys.getrefcount(self.child), 2)
+ self.child.setParent(self.parent)
+ self.assertEqual(sys.getrefcount(self.child), 3)
+
+ @unittest.skipUnless(hasattr(sys, "getrefcount"), f"{sys.implementation.name} has no refcount")
+ def testSetParentTwice(self):
+ self.assertEqual(sys.getrefcount(self.child), 2)
+ self.child.setParent(self.parent)
+ self.assertEqual(sys.getrefcount(self.child), 3)
+ self.child.setParent(self.parent)
+ self.assertEqual(sys.getrefcount(self.child), 3)
+
+ @unittest.skipUnless(hasattr(sys, "getrefcount"), f"{sys.implementation.name} has no refcount")
+ def testConstructor(self):
+ # QObject(QObject) refcount changes
+ child = QObject(self.parent)
+ self.assertEqual(sys.getrefcount(child), 3)
+
+
+class ParentCase(unittest.TestCase):
+ '''Small collection of tests related to parent-child relationship'''
+
+ def testSetParent(self):
+ # QObject.setParent()
+ parent = QObject()
+ child = QObject()
+ child.setParent(parent)
+
+ self.assertEqual(parent, child.parent())
+
+ def testParentConstructor(self):
+ # QObject(parent)
+ parent = QObject()
+ child = QObject(parent)
+
+ self.assertEqual(parent, child.parent())
+
+ orig_repr = repr(child)
+ del child
+ # PYSIDE-535: Need to collect garbage in PyPy to trigger deletion
+ gc.collect()
+ self.assertEqual(orig_repr, repr(parent.children()[0]))
+
+ def testChildren(self):
+ # QObject.children()
+ parent = QObject()
+ children = [QObject(parent) for x in range(25)]
+
+ self.assertEqual(parent.children(), children)
+
+ def testFindChild(self):
+ # QObject.findChild() with all QObject
+ parent = QObject()
+ children = [QObject(parent) for i in range(20)]
+
+ for i, child in enumerate(children):
+ child.setObjectName(f'object{i}')
+
+ for i, child in enumerate(children):
+ self.assertEqual(child, parent.findChild(QObject, f'object{i}'))
+
+ def testFindChildOptions(self):
+ parent = QObject()
+ child = QObject(parent)
+ nested_child_name = 'nestedChild'
+ nested_child = QObject(child)
+ nested_child.setObjectName(nested_child_name)
+
+ search_result = parent.findChild(QObject, nested_child_name)
+ self.assertTrue(search_result)
+ search_result = parent.findChild(QObject, nested_child_name,
+ Qt.FindChildrenRecursively)
+ self.assertTrue(search_result)
+ search_result = parent.findChild(QObject, nested_child_name,
+ Qt.FindDirectChildrenOnly)
+ self.assertFalse(search_result)
+
+ search_results = parent.findChildren(QObject, nested_child_name)
+ self.assertEqual(len(search_results), 1)
+ search_result = parent.findChildren(QObject, nested_child_name,
+ Qt.FindChildrenRecursively)
+ self.assertEqual(len(search_results), 1)
+ search_results = parent.findChildren(QObject, nested_child_name,
+ Qt.FindDirectChildrenOnly)
+ self.assertEqual(len(search_results), 0)
+
+ def testFindChildWithoutName(self):
+ parent = QObject()
+ children = [QObject(parent) for i in range(20)]
+
+ for i, child in enumerate(children):
+ child.setObjectName(f'object{i}')
+
+ child = parent.findChild(QObject)
+ self.assertTrue(isinstance(child, QObject))
+
+ def testFindChildren(self):
+ # QObject.findChildren() with all QObject
+ parent = QObject()
+ target_name = 'foo'
+ children = [QTimer(parent) for i in range(20)]
+ children.extend([QObject(parent) for i in range(20)])
+
+ for i, child in enumerate(children):
+ if i % 5 == 0:
+ child.setObjectName(target_name)
+ else:
+ child.setObjectName(str(i))
+
+ # Emulates findChildren with the intended outcome
+ target_children = [x for x in children if x.objectName() == target_name]
+ test_children = parent.findChildren(QObject, target_name)
+ self.assertEqual(target_children, test_children)
+
+ # test findChildren default value
+ res = parent.findChildren(QTimer)
+ self.assertEqual(len(res), 20)
+
+ # test findChildren with a QRegularExpression
+ res = parent.findChildren(QObject, QRegularExpression("^fo+"))
+ self.assertEqual(res, test_children)
+
+ def testParentEquality(self):
+ # QObject.parent() == parent
+ parent = QObject()
+ child = QObject(parent)
+ self.assertEqual(parent, child.parent())
+
+ def testFindChildByType(self):
+ parent = QObject()
+ expected = TestObject2(parent)
+ actual = parent.findChild(TestObject2)
+ self.assertEqual(actual, expected)
+ actual = parent.findChild(TestObject1)
+ self.assertEqual(actual, expected)
+ actual = parent.findChild(QTimer)
+ self.assertEqual(actual, expected)
+
+ def testFindChildrenByType(self):
+ parent = QObject()
+ expected = [TestObject2(parent)]
+ actual = parent.findChildren(TestObject2)
+ self.assertEqual(actual, expected)
+ actual = parent.findChildren(TestObject1)
+ self.assertEqual(actual, expected)
+ actual = parent.findChildren(QTimer)
+ self.assertEqual(actual, expected)
+
+
+class TestParentOwnership(unittest.TestCase):
+ '''Test case for Parent/Child object ownership'''
+
+ @unittest.skipUnless(hasattr(sys, "getrefcount"), f"{sys.implementation.name} has no refcount")
+ def testParentDestructor(self):
+ parent = QObject()
+ self.assertEqual(sys.getrefcount(parent), 2)
+
+ child = QObject(parent)
+ self.assertEqual(sys.getrefcount(child), 3)
+ self.assertEqual(sys.getrefcount(parent), 2)
+
+ del parent
+ self.assertEqual(sys.getrefcount(child), 2)
+
+ # this will fail because parent deleted child cpp object
+ self.assertRaises(RuntimeError, lambda: child.objectName())
+
+ # test parent with multiples children
+ @unittest.skipUnless(hasattr(sys, "getrefcount"), f"{sys.implementation.name} has no refcount")
+ def testMultipleChildren(self):
+ o = QObject()
+ self.assertEqual(sys.getrefcount(o), 2)
+
+ c = QObject(o)
+ self.assertEqual(sys.getrefcount(c), 3)
+ self.assertEqual(sys.getrefcount(o), 2)
+
+ c2 = QObject(o)
+ self.assertEqual(sys.getrefcount(o), 2)
+ self.assertEqual(sys.getrefcount(c), 3)
+ self.assertEqual(sys.getrefcount(c2), 3)
+
+ del o
+ self.assertEqual(sys.getrefcount(c), 2)
+ self.assertEqual(sys.getrefcount(c2), 2)
+
+ # this will fail because parent deleted child cpp object
+ self.assertRaises(RuntimeError, lambda: c.objectName())
+ self.assertRaises(RuntimeError, lambda: c2.objectName())
+
+ # test recursive parent
+ @unittest.skipUnless(hasattr(sys, "getrefcount"), f"{sys.implementation.name} has no refcount")
+ def testRecursiveParent(self):
+ o = QObject()
+ self.assertEqual(sys.getrefcount(o), 2)
+
+ c = QObject(o)
+ self.assertEqual(sys.getrefcount(c), 3)
+ self.assertEqual(sys.getrefcount(o), 2)
+
+ c2 = QObject(c)
+ self.assertEqual(sys.getrefcount(o), 2)
+ self.assertEqual(sys.getrefcount(c), 3)
+ self.assertEqual(sys.getrefcount(c2), 3)
+
+ del o
+ self.assertEqual(sys.getrefcount(c), 2)
+ self.assertEqual(sys.getrefcount(c2), 2)
+
+ # this will fail because parent deleted child cpp object
+ self.assertRaises(RuntimeError, lambda: c.objectName())
+ self.assertRaises(RuntimeError, lambda: c2.objectName())
+
+ # test parent transfer
+ @unittest.skipUnless(hasattr(sys, "getrefcount"), f"{sys.implementation.name} has no refcount")
+ def testParentTransfer(self):
+ o = QObject()
+ self.assertEqual(sys.getrefcount(o), 2)
+
+ c = QObject()
+ self.assertEqual(sys.getrefcount(c), 2)
+
+ c.setParent(o)
+ self.assertEqual(sys.getrefcount(c), 3)
+
+ c.setParent(None)
+ self.assertEqual(sys.getrefcount(c), 2)
+
+ del c
+ del o
+
+
+class ExtQObject(QObject):
+ def __init__(self):
+ super().__init__()
+
+
+class ReparentingTest(unittest.TestCase):
+ '''Test cases for reparenting'''
+
+ def testParentedQObjectIdentity(self):
+ object_list = []
+ parent = QObject()
+ for i in range(3):
+ obj = QObject()
+ object_list.append(obj)
+ obj.setParent(parent)
+ for child in parent.children():
+ self.assertTrue(child in object_list)
+
+ def testParentedExtQObjectType(self):
+ object_list = []
+ parent = QObject()
+ for i in range(3):
+ obj = ExtQObject()
+ object_list.append(obj)
+ obj.setParent(parent)
+ for orig, child in zip(object_list, parent.children()):
+ self.assertEqual(type(orig), type(child))
+
+ def testReparentedQObjectIdentity(self):
+ object_list = []
+ old_parent = QObject()
+ new_parent = QObject()
+ for i in range(3):
+ obj = QObject()
+ object_list.append(obj)
+ obj.setParent(old_parent)
+ for obj in object_list:
+ obj.setParent(new_parent)
+ for child in new_parent.children():
+ self.assertTrue(child in object_list)
+
+ def testReparentedExtQObjectType(self):
+ object_list = []
+ old_parent = QObject()
+ new_parent = QObject()
+ for i in range(3):
+ obj = ExtQObject()
+ object_list.append(obj)
+ obj.setParent(old_parent)
+ for obj in object_list:
+ obj.setParent(new_parent)
+ for orig, child in zip(object_list, new_parent.children()):
+ self.assertEqual(type(orig), type(child))
+
+
+if __name__ == '__main__':
+ unittest.main()