diff options
Diffstat (limited to 'sources/pyside6/tests/QtWidgets')
132 files changed, 6663 insertions, 0 deletions
diff --git a/sources/pyside6/tests/QtWidgets/CMakeLists.txt b/sources/pyside6/tests/QtWidgets/CMakeLists.txt new file mode 100644 index 000000000..01b7d08ea --- /dev/null +++ b/sources/pyside6/tests/QtWidgets/CMakeLists.txt @@ -0,0 +1,134 @@ +# Copyright (C) 2023 The Qt Company Ltd. +# SPDX-License-Identifier: BSD-3-Clause + +#Keep this in alphabetical sort + +PYSIDE_TEST(action_clear.py) +PYSIDE_TEST(add_action_test.py) +PYSIDE_TEST(api2_test.py) +PYSIDE_TEST(application_test.py) +PYSIDE_TEST(bug_172.py) +PYSIDE_TEST(bug_243.py) +PYSIDE_TEST(bug_307.py) +PYSIDE_TEST(bug_338.py) +PYSIDE_TEST(bug_389.py) +PYSIDE_TEST(bug_400.py) +PYSIDE_TEST(bug_429.py) +PYSIDE_TEST(bug_430.py) +PYSIDE_TEST(bug_433.py) +PYSIDE_TEST(bug_467.py) +PYSIDE_TEST(bug_480.py) +PYSIDE_TEST(bug_512.py) +PYSIDE_TEST(bug_525.py) +PYSIDE_TEST(bug_546.py) +PYSIDE_TEST(bug_547.py) +PYSIDE_TEST(bug_549.py) +PYSIDE_TEST(bug_569.py) +PYSIDE_TEST(bug_575.py) +PYSIDE_TEST(bug_576.py) +PYSIDE_TEST(bug_585.py) +PYSIDE_TEST(bug_589.py) +PYSIDE_TEST(bug_635.py) +PYSIDE_TEST(bug_640.py) +PYSIDE_TEST(bug_653.py) +PYSIDE_TEST(bug_662.py) +PYSIDE_TEST(bug_667.py) +PYSIDE_TEST(bug_668.py) +PYSIDE_TEST(bug_674.py) +PYSIDE_TEST(bug_675.py) +PYSIDE_TEST(bug_688.py) +PYSIDE_TEST(bug_693.py) +PYSIDE_TEST(bug_696.py) +PYSIDE_TEST(bug_711.py) +PYSIDE_TEST(bug_722.py) +PYSIDE_TEST(bug_728.py) +PYSIDE_TEST(bug_736.py) +PYSIDE_TEST(bug_750.py) +PYSIDE_TEST(bug_778.py) +PYSIDE_TEST(bug_793.py) +PYSIDE_TEST(bug_811.py) +PYSIDE_TEST(bug_834.py) +PYSIDE_TEST(bug_836.py) +PYSIDE_TEST(bug_844.py) +PYSIDE_TEST(bug_854.py) +PYSIDE_TEST(bug_860.py) +PYSIDE_TEST(bug_862.py) +PYSIDE_TEST(bug_871.py) +PYSIDE_TEST(bug_879.py) +PYSIDE_TEST(bug_919.py) +PYSIDE_TEST(bug_921.py) +PYSIDE_TEST(bug_941.py) +PYSIDE_TEST(bug_964.py) +PYSIDE_TEST(bug_967.py) +PYSIDE_TEST(bug_972.py) +PYSIDE_TEST(bug_979.py) +PYSIDE_TEST(bug_988.py) +PYSIDE_TEST(bug_998.py) +PYSIDE_TEST(bug_1002.py) +PYSIDE_TEST(bug_1006.py) +PYSIDE_TEST(bug_1048.py) +PYSIDE_TEST(bug_1077.py) +PYSIDE_TEST(customproxywidget_test.py) +PYSIDE_TEST(grandparent_method_test.py) +PYSIDE_TEST(hashabletype_test.py) +PYSIDE_TEST(keep_reference_test.py) +PYSIDE_TEST(missing_symbols_test.py) +PYSIDE_TEST(paint_event_test.py) +PYSIDE_TEST(parent_method_test.py) +PYSIDE_TEST(private_mangle_test.py) +PYSIDE_TEST(python_properties_test.py) +PYSIDE_TEST(qabstracttextdocumentlayout_test.py) +PYSIDE_TEST(qaccessible_test.py) +PYSIDE_TEST(qaction_test.py) +PYSIDE_TEST(qapp_issue_585.py) +PYSIDE_TEST(qapp_test.py) +PYSIDE_TEST(qapplication_test.py) +PYSIDE_TEST(qapplication_exit_segfault_test.py) +PYSIDE_TEST(qdialog_test.py) +PYSIDE_TEST(qdynamic_signal.py) +# TODO: This passes, but requires manual button clicking (at least on mac) +#PYSIDE_TEST(qfontdialog_test.py) +PYSIDE_TEST(qformlayout_test.py) +PYSIDE_TEST(qgraphicsitem_test.py) +PYSIDE_TEST(qgraphicsitem_isblocked_test.py) +PYSIDE_TEST(qgraphicsobjectreimpl_test.py) +PYSIDE_TEST(qgraphicsproxywidget_test.py) +PYSIDE_TEST(qgraphicsscene_test.py) +PYSIDE_TEST(qinputdialog_get_test.py) +PYSIDE_TEST(qkeysequenceedit_test.py) +PYSIDE_TEST(qlabel_test.py) +PYSIDE_TEST(qlayout_ref_test.py) +PYSIDE_TEST(qlayout_test.py) +PYSIDE_TEST(qlcdnumber_test.py) +PYSIDE_TEST(qlistwidget_test.py) +PYSIDE_TEST(qlistwidgetitem_test.py) +PYSIDE_TEST(qmainwindow_test.py) +PYSIDE_TEST(qmenu_test.py) +PYSIDE_TEST(qmenuadd_test.py) +PYSIDE_TEST(qobject_mi_test.py) +PYSIDE_TEST(qpicture_test.py) +PYSIDE_TEST(qpushbutton_test.py) +PYSIDE_TEST(qsplitter_test.py) +PYSIDE_TEST(qstyle_test.py) +PYSIDE_TEST(qstyleoption_test.py) +PYSIDE_TEST(qtableview_test.py) +PYSIDE_TEST(qtabwidget_test.py) +PYSIDE_TEST(qtabwidgetclear_test.py) +PYSIDE_TEST(qtextedit_test.py) +PYSIDE_TEST(qtextedit_signal_test.py) +PYSIDE_TEST(qtreeview_test.py) +PYSIDE_TEST(qtreewidget_test.py) +PYSIDE_TEST(qtreewidgetitem_test.py) +PYSIDE_TEST(qtoolbar_test.py) +PYSIDE_TEST(qtoolbox_test.py) +PYSIDE_TEST(qvariant_test.py) +PYSIDE_TEST(qwidget_setlayout_test.py) +PYSIDE_TEST(qwidget_test.py) +PYSIDE_TEST(qcolormap_test.py) +PYSIDE_TEST(reference_count_test.py) +PYSIDE_TEST(signature_test.py) +PYSIDE_TEST(standardpixmap_test.py) +PYSIDE_TEST(test_module_template.py) +PYSIDE_TEST(virtual_protected_inheritance_test.py) +PYSIDE_TEST(virtual_pure_override_test.py) +PYSIDE_TEST(wrong_return_test.py) diff --git a/sources/pyside6/tests/QtWidgets/QtWidgets.pyproject b/sources/pyside6/tests/QtWidgets/QtWidgets.pyproject new file mode 100644 index 000000000..36c000165 --- /dev/null +++ b/sources/pyside6/tests/QtWidgets/QtWidgets.pyproject @@ -0,0 +1,130 @@ +{ + "files": ["action_clear.py", + "add_action_test.py", + "api2_test.py", + "application_test.py", + "bug_1002.py", + "bug_1006.py", + "bug_1048.py", + "bug_1077.py", + "bug_172.py", + "bug_243.py", + "bug_307.py", + "bug_338.py", + "bug_389.py", + "bug_400.py", + "bug_429.py", + "bug_430.py", + "bug_433.py", + "bug_467.py", + "bug_480.py", + "bug_512.py", + "bug_525.py", + "bug_546.py", + "bug_547.py", + "bug_549.py", + "bug_569.py", + "bug_575.py", + "bug_576.py", + "bug_585.py", + "bug_589.py", + "bug_635.py", + "bug_640.py", + "bug_653.py", + "bug_662.py", + "bug_667.py", + "bug_668.py", + "bug_674.py", + "bug_675.py", + "bug_688.py", + "bug_693.py", + "bug_696.py", + "bug_711.py", + "bug_722.py", + "bug_728.py", + "bug_736.py", + "bug_750.py", + "bug_778.py", + "bug_793.py", + "bug_811.py", + "bug_834.py", + "bug_836.py", + "bug_844.py", + "bug_854.py", + "bug_860.py", + "bug_862.py", + "bug_871.py", + "bug_879.py", + "bug_919.py", + "bug_921.py", + "bug_941.py", + "bug_964.py", + "bug_967.py", + "bug_972.py", + "bug_979.py", + "bug_988.py", + "bug_998.py", + "customproxywidget_test.py", + "grandparent_method_test.py", + "hashabletype_test.py", + "import_test.py", + "keep_reference_test.py", + "missing_symbols_test.py", + "paint_event_test.py", + "parent_method_test.py", + "private_mangle_test.py", + "python_properties_test.py", + "qabstracttextdocumentlayout_test.py", + "qaccessible_test.py", + "qaction_test.py", + "qapp_issue_585.py", + "qapp_test.py", + "qapplication_exit_segfault_test.py", + "qapplication_test.py", + "qcolormap_test.py", + "qdynamic_signal.py", + "qfontdialog_test.py", + "qformlayout_test.py", + "qgraphicsitem_isblocked_test.py", + "qgraphicsitem_test.py", + "qgraphicsobjectreimpl_test.py", + "qgraphicsproxywidget_test.py", + "qgraphicsscene_test.py", + "qinputdialog_get_test.py", + "qkeysequenceedit_test.py", + "qlabel_test.py", + "qlayout_ref_test.py", + "qlayout_test.py", + "qlcdnumber_test.py", + "qlistwidget_test.py", + "qlistwidgetitem_test.py", + "qmainwindow_test.py", + "qmenu_test.py", + "qmenuadd_test.py", + "qobject_mi_test.py", + "qpicture_test.py", + "qpushbutton_test.py", + "qsplitter_test.py", + "qstyle_test.py", + "qstyleoption_test.py", + "qtableview_test.py", + "qtabwidget_test.py", + "qtabwidgetclear_test.py", + "qtextedit_signal_test.py", + "qtextedit_test.py", + "qtoolbar_test.py", + "qtoolbox_test.py", + "qtreeview_test.py", + "qtreewidget_test.py", + "qtreewidgetitem_test.py", + "qvariant_test.py", + "qwidget_setlayout_test.py", + "qwidget_test.py", + "reference_count_test.py", + "signature_test.py", + "standardpixmap_test.py", + "test_module_template.py", + "virtual_protected_inheritance_test.py", + "virtual_pure_override_test.py", + "wrong_return_test.py"] +} diff --git a/sources/pyside6/tests/QtWidgets/action_clear.py b/sources/pyside6/tests/QtWidgets/action_clear.py new file mode 100644 index 000000000..5563a4899 --- /dev/null +++ b/sources/pyside6/tests/QtWidgets/action_clear.py @@ -0,0 +1,68 @@ +# Copyright (C) 2022 The Qt Company Ltd. +# SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0 + +import gc +import os +import sys +import unittest +import weakref + +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.QtWidgets import QMenu, QWidget, QMenuBar, QToolBar +from helper.usesqapplication import UsesQApplication + + +class TestQActionLifeCycle(UsesQApplication): + def actionDestroyed(self, act): + self._actionDestroyed = True + + def testMenu(self): + self._actionDestroyed = False + w = QWidget() + menu = QMenu(w) + act = menu.addAction("MENU") + _ref = weakref.ref(act, self.actionDestroyed) + act = None + self.assertFalse(self._actionDestroyed) + menu.clear() + # PYSIDE-535: Need to collect garbage in PyPy to trigger deletion + gc.collect() + self.assertTrue(self._actionDestroyed) + + def testMenuBar(self): + self._actionDestroyed = False + w = QWidget() + menuBar = QMenuBar(w) + act = menuBar.addAction("MENU") + _ref = weakref.ref(act, self.actionDestroyed) + act = None + # PYSIDE-535: Need to collect garbage in PyPy to trigger deletion + gc.collect() + self.assertFalse(self._actionDestroyed) + menuBar.clear() + # PYSIDE-535: Need to collect garbage in PyPy to trigger deletion + gc.collect() + self.assertTrue(self._actionDestroyed) + + def testToolBar(self): + self._actionDestroyed = False + w = QWidget() + toolBar = QToolBar(w) + act = toolBar.addAction("MENU") + _ref = weakref.ref(act, self.actionDestroyed) + act = None + # PYSIDE-535: Need to collect garbage in PyPy to trigger deletion + gc.collect() + self.assertFalse(self._actionDestroyed) + toolBar.clear() + # PYSIDE-535: Need to collect garbage in PyPy to trigger deletion + gc.collect() + self.assertTrue(self._actionDestroyed) + + +if __name__ == "__main__": + unittest.main() diff --git a/sources/pyside6/tests/QtWidgets/add_action_test.py b/sources/pyside6/tests/QtWidgets/add_action_test.py new file mode 100644 index 000000000..3ca1660a9 --- /dev/null +++ b/sources/pyside6/tests/QtWidgets/add_action_test.py @@ -0,0 +1,60 @@ +# Copyright (C) 2022 The Qt Company Ltd. +# SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0 + +'''Tests for QMenuBar.addAction(identifier, callback) calls''' + +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 Qt, SLOT +from PySide6.QtGui import QAction +from PySide6.QtWidgets import QMenuBar, QPushButton + +from helper.usesqapplication import UsesQApplication + + +class AddActionTest(UsesQApplication): + '''QMenuBar addAction''' + + def tearDown(self): + try: + del self.called + except AttributeError: + pass + # PYSIDE-535: Need to collect garbage in PyPy to trigger deletion + gc.collect() + super(AddActionTest, self).tearDown() + + def _callback(self): + self.called = True + + def testBasic(self): + '''QMenuBar.addAction(id, callback)''' + menubar = QMenuBar() + action = menubar.addAction("Accounts", self._callback) + action.activate(QAction.Trigger) + action.setShortcut(Qt.Key_A) + self.assertTrue(self.called) + + def testWithCppSlot(self): + '''QMenuBar.addAction(id, object, slot)''' + menubar = QMenuBar() + widget = QPushButton() + widget.setCheckable(True) + widget.setChecked(False) + action = menubar.addAction("Accounts", widget, SLOT("toggle()")) + action.setShortcut(Qt.Key_A) + action.activate(QAction.Trigger) + self.assertTrue(widget.isChecked()) + + +if __name__ == '__main__': + unittest.main() + diff --git a/sources/pyside6/tests/QtWidgets/api2_test.py b/sources/pyside6/tests/QtWidgets/api2_test.py new file mode 100644 index 000000000..e38672016 --- /dev/null +++ b/sources/pyside6/tests/QtWidgets/api2_test.py @@ -0,0 +1,73 @@ +# 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 PySide API2 support''' + + +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.QtGui import QIntValidator, QValidator +from PySide6.QtWidgets import QWidget, QSpinBox, QApplication + +from helper.usesqapplication import UsesQApplication + + +class WidgetValidatorQInt(QWidget, QIntValidator): + def __init__(self, parent=None): + QWidget.__init__(self, parent) + QIntValidator.__init__(self, parent) + + +class WidgetValidatorQSpinBox(QSpinBox): + def __init__(self, parent=None): + QSpinBox.__init__(self, parent) + + def fixup(self, text): + print("It was called!") + + +class DoubleQObjectInheritanceTest(UsesQApplication): + + def testDouble(self): + '''Double inheritance from QObject classes''' + + obj = WidgetValidatorQInt() + + # QIntValidator methods + state, string, number = obj.validate('Test', 0) + self.assertEqual(state, QValidator.Invalid) + state, string, number = obj.validate('33', 0) + self.assertEqual(state, QValidator.Acceptable) + + def testQSpinBox(self): + obj = WidgetValidatorQSpinBox() + + obj.setRange(1, 10) + obj.setValue(0) + self.assertEqual(obj.value(), 1) + + +class QClipboardTest(UsesQApplication): + + def testQClipboard(self): + # skip this test on macOS because the clipboard is not available during the ssh session + # this cause problems in the buildbot + if sys.platform == 'darwin': + return + clip = QApplication.clipboard() + clip.setText("Testing this thing!") + + text, subtype = clip.text("") + self.assertEqual(subtype, "plain") + self.assertEqual(text, "Testing this thing!") + + +if __name__ == '__main__': + unittest.main() diff --git a/sources/pyside6/tests/QtWidgets/application_test.py b/sources/pyside6/tests/QtWidgets/application_test.py new file mode 100644 index 000000000..1b2477fd7 --- /dev/null +++ b/sources/pyside6/tests/QtWidgets/application_test.py @@ -0,0 +1,42 @@ +#!/usr/bin/python +# Copyright (C) 2022 The Qt Company Ltd. +# SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0 + +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(True) + +from testbinding import TestObject +from PySide6.QtWidgets import QApplication +from PySide6 import __all__ as all + + +class QApplicationInstance(unittest.TestCase): + + def appDestroyed(self): + self.assertTrue(False) + + def testInstanceObject(self): + self.assertEqual(type(qApp), type(None)) + TestObject.createApp() + app1 = QApplication.instance() + app2 = QApplication.instance() + app1.setObjectName("MyApp") + self.assertEqual(app1, app2) + self.assertEqual(app2.objectName(), app1.objectName()) + # We no longer support qApp when embedding + # if len(all) > 3: + # # an import triggers qApp initialization + # __import__("PySide6." + all[-1]) + # self.assertEqual(app1, qApp) + app1.destroyed.connect(self.appDestroyed) + + +if __name__ == '__main__': + unittest.main() + diff --git a/sources/pyside6/tests/QtWidgets/bug_1002.py b/sources/pyside6/tests/QtWidgets/bug_1002.py new file mode 100644 index 000000000..98ae66c47 --- /dev/null +++ b/sources/pyside6/tests/QtWidgets/bug_1002.py @@ -0,0 +1,35 @@ +# Copyright (C) 2022 The Qt Company Ltd. +# SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0 + +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.QtWidgets import QWidget, QPushButton + +from helper.usesqapplication import UsesQApplication + + +class TestBug1002 (UsesQApplication): + @unittest.skipUnless(hasattr(sys, "getrefcount"), f"{sys.implementation.name} has no refcount") + def testReturnWindow(self): + widget = QWidget() + button = QPushButton(widget) + self.assertEqual(sys.getrefcount(widget), 2) + window = button.window() + self.assertEqual(sys.getrefcount(widget), 3) + self.assertEqual(sys.getrefcount(window), 3) + + del widget + # PYSIDE-535: Need to collect garbage in PyPy to trigger deletion + gc.collect() + + +if __name__ == '__main__': + unittest.main() diff --git a/sources/pyside6/tests/QtWidgets/bug_1006.py b/sources/pyside6/tests/QtWidgets/bug_1006.py new file mode 100644 index 000000000..74bf5e2da --- /dev/null +++ b/sources/pyside6/tests/QtWidgets/bug_1006.py @@ -0,0 +1,99 @@ +# Copyright (C) 2022 The Qt Company Ltd. +# SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0 + +import gc +import os +import sys +import unittest +import weakref + +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 Qt +from PySide6.QtWidgets import QDialog, QLabel, QGridLayout, QHBoxLayout, QWidget + +from helper.timedqapplication import TimedQApplication + + +class LabelWindow(QDialog): + def __init__(self, parent): + super().__init__(parent) + + self.test_layout = QGridLayout() + label = QLabel("Label") + self.test_layout.addWidget(label, 0, 0) + self.setLayout(self.test_layout) + self._destroyCalled = False + + def replace(self, unit): + old_item = self.test_layout.itemAtPosition(0, 0) + old_label = old_item.widget() + ref = weakref.ref(old_item, self._destroyed) + + self.test_layout.removeWidget(old_label) + unit.assertRaises(RuntimeError, old_item.widget) + del old_item + # PYSIDE-535: Need to collect garbage in PyPy to trigger deletion + gc.collect() + + label = QLabel("Label New") + old_label.deleteLater() + label.setAlignment(Qt.AlignCenter) + self.test_layout.addWidget(label, 0, 0) + + def _destroyed(self, obj): + self._destroyCalled = True + + +class TestBug1006 (TimedQApplication): + + def testLayoutItemLifeTime(self): + window = LabelWindow(None) + window.replace(self) + self.assertTrue(window._destroyCalled) + self.app.exec() + + def testParentLayout(self): + def createLayout(): + label = QLabel() + layout = QHBoxLayout() + layout.addWidget(label) + + widget = QWidget() + widget.setLayout(layout) + return (layout, widget) + (layout, widget) = createLayout() + item = layout.itemAt(0) + self.assertTrue(isinstance(item.widget(), QWidget)) + + @unittest.skipUnless(hasattr(sys, "getrefcount"), f"{sys.implementation.name} has no refcount") + def testRemoveOrphanWidget(self): + widget = QLabel() + layout = QHBoxLayout() + layout.addWidget(widget) + self.assertEqual(sys.getrefcount(widget), 3) + + layout.removeWidget(widget) + widget.setObjectName("MyWidget") + self.assertEqual(sys.getrefcount(widget), 2) + + @unittest.skipUnless(hasattr(sys, "getrefcount"), f"{sys.implementation.name} has no refcount") + def testRemoveChildWidget(self): + parent = QLabel() + widget = QLabel(parent) + self.assertEqual(sys.getrefcount(widget), 3) + + layout = QHBoxLayout() + layout.addWidget(widget) + self.assertEqual(sys.getrefcount(widget), 3) + + layout.removeWidget(widget) + widget.setObjectName("MyWidget") + self.assertEqual(sys.getrefcount(widget), 3) + + +if __name__ == "__main__": + unittest.main() diff --git a/sources/pyside6/tests/QtWidgets/bug_1048.py b/sources/pyside6/tests/QtWidgets/bug_1048.py new file mode 100644 index 000000000..9d83e2f30 --- /dev/null +++ b/sources/pyside6/tests/QtWidgets/bug_1048.py @@ -0,0 +1,21 @@ +# Copyright (C) 2022 The Qt Company Ltd. +# SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0 + +import os +import sys + +from pathlib import Path +sys.path.append(os.fspath(Path(__file__).resolve().parents[1])) +sys.path.append(os.fspath(Path(__file__).resolve().parents[1] / "util")) +from init_paths import init_test_paths +init_test_paths() + +from PySide6.QtWidgets import QApplication, QGridLayout, QWidget + + +a = QApplication([]) + +w = QWidget() +l = QGridLayout(w) + +l.itemAtPosition(0, 0) diff --git a/sources/pyside6/tests/QtWidgets/bug_1077.py b/sources/pyside6/tests/QtWidgets/bug_1077.py new file mode 100644 index 000000000..c9559609f --- /dev/null +++ b/sources/pyside6/tests/QtWidgets/bug_1077.py @@ -0,0 +1,32 @@ +# Copyright (C) 2022 The Qt Company Ltd. +# SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0 + +''' unit test for BUG #1077 ''' + +import os +import sys +import time + +from pathlib import Path +sys.path.append(os.fspath(Path(__file__).resolve().parents[1])) +sys.path.append(os.fspath(Path(__file__).resolve().parents[1] / "util")) +from init_paths import init_test_paths +init_test_paths() + +from PySide6.QtGui import QSyntaxHighlighter +from PySide6.QtWidgets import QApplication, QTextEdit, QWidget + + +class Highlighter(QSyntaxHighlighter): + def __init__(self, parent, mode): + super().__init__(parent) + self.tstamp = time.time() + + +if __name__ == "__main__": + app = QApplication([]) + python = QTextEdit() + python.setWindowTitle("python") + hl = Highlighter(python.document(), "python") + python.show() + text = hl.document() diff --git a/sources/pyside6/tests/QtWidgets/bug_172.py b/sources/pyside6/tests/QtWidgets/bug_172.py new file mode 100644 index 000000000..2637d6d61 --- /dev/null +++ b/sources/pyside6/tests/QtWidgets/bug_172.py @@ -0,0 +1,26 @@ +# Copyright (C) 2022 The Qt Company Ltd. +# SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0 + +import os +import sys + +from pathlib import Path +sys.path.append(os.fspath(Path(__file__).resolve().parents[1])) +sys.path.append(os.fspath(Path(__file__).resolve().parents[1] / "util")) +from init_paths import init_test_paths +init_test_paths() + +from PySide6.QtWidgets import QApplication, QHBoxLayout, QVBoxLayout, QWidget + + +if __name__ == '__main__': + app = QApplication([]) + + wdg = QWidget() + + hbox = QHBoxLayout() + + vbox = QVBoxLayout() + vbox.addLayout(hbox) + + wdg.setLayout(vbox) diff --git a/sources/pyside6/tests/QtWidgets/bug_243.py b/sources/pyside6/tests/QtWidgets/bug_243.py new file mode 100644 index 000000000..af189837f --- /dev/null +++ b/sources/pyside6/tests/QtWidgets/bug_243.py @@ -0,0 +1,28 @@ +# 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 bug 243: http://bugs.openbossa.org/show_bug.cgi?id=243''' + +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.QtWidgets import QApplication, QMainWindow, QLayout + + +class QAppPresence(unittest.TestCase): + + def testBug(self): + app = QApplication(sys.argv) + window = QMainWindow() + l = window.layout() + self.assertTrue(isinstance(l, QLayout)) + + +if __name__ == '__main__': + unittest.main() diff --git a/sources/pyside6/tests/QtWidgets/bug_307.py b/sources/pyside6/tests/QtWidgets/bug_307.py new file mode 100644 index 000000000..673d5183d --- /dev/null +++ b/sources/pyside6/tests/QtWidgets/bug_307.py @@ -0,0 +1,37 @@ +# Copyright (C) 2022 The Qt Company Ltd. +# SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0 + +import colorsys +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 SIGNAL +from PySide6.QtWidgets import QPushButton, QApplication + + +class Test (QApplication): + def __init__(self, argv): + super().__init__(argv) + self._called = False + + def called(self): + self._called = True + + +class QApplicationSignalsTest(unittest.TestCase): + def testQuit(self): + app = Test([]) + button = QPushButton("BUTTON") + app.connect(button, SIGNAL("clicked()"), app.called) + button.click() + self.assertTrue(app._called) + + +if __name__ == '__main__': + unittest.main() diff --git a/sources/pyside6/tests/QtWidgets/bug_338.py b/sources/pyside6/tests/QtWidgets/bug_338.py new file mode 100644 index 000000000..695b4238a --- /dev/null +++ b/sources/pyside6/tests/QtWidgets/bug_338.py @@ -0,0 +1,38 @@ +# 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 bug 338: http://bugs.openbossa.org/show_bug.cgi?id=338''' + +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.QtWidgets import QApplication, QGraphicsPolygonItem, QGraphicsScene + + +class DiagramItem(QGraphicsPolygonItem): + def __init__(self, parent=None, scene=None): + super().__init__(parent, scene) + + def itemChange(self, change, value): + return value + + +class BugTest(unittest.TestCase): + def test(self): + app = QApplication(sys.argv) + scene = QGraphicsScene() + item = DiagramItem() + item2 = DiagramItem() + # this cause segfault + scene.addItem(item) + scene.addItem(item2) + + +if __name__ == "__main__": + unittest.main() diff --git a/sources/pyside6/tests/QtWidgets/bug_389.py b/sources/pyside6/tests/QtWidgets/bug_389.py new file mode 100644 index 000000000..024908e85 --- /dev/null +++ b/sources/pyside6/tests/QtWidgets/bug_389.py @@ -0,0 +1,28 @@ +# 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 bug 389: http://bugs.openbossa.org/show_bug.cgi?id=389''' + +import sys +import os +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 helper.usesqapplication import UsesQApplication +from PySide6.QtGui import QIcon +from PySide6.QtWidgets import QStyle, QWidget + + +class BugTest(UsesQApplication): + def testCase(self): + s = QWidget().style() + i = s.standardIcon(QStyle.SP_TitleBarMinButton) + self.assertEqual(type(i), QIcon) + + +if __name__ == '__main__': + unittest.main() diff --git a/sources/pyside6/tests/QtWidgets/bug_400.py b/sources/pyside6/tests/QtWidgets/bug_400.py new file mode 100644 index 000000000..79dfa49fc --- /dev/null +++ b/sources/pyside6/tests/QtWidgets/bug_400.py @@ -0,0 +1,38 @@ +# 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 bug 400: http://bugs.openbossa.org/show_bug.cgi?id=400''' + +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 helper.usesqapplication import UsesQApplication +from PySide6.QtWidgets import QTreeWidgetItemIterator, QTreeWidgetItem, QTreeWidget + + +class BugTest(UsesQApplication): + def testCase(self): + treeWidget = QTreeWidget() + treeWidget.setColumnCount(1) + items = [] + for i in range(10): + items.append(QTreeWidgetItem(None, [f"item: {i}"])) + + treeWidget.insertTopLevelItems(0, items) + _iter = QTreeWidgetItemIterator(treeWidget) + index = 0 + while (_iter.value()): + item = _iter.value() + self.assertTrue(item is items[index]) + index += 1 + _iter += 1 + + +if __name__ == '__main__': + unittest.main() diff --git a/sources/pyside6/tests/QtWidgets/bug_429.py b/sources/pyside6/tests/QtWidgets/bug_429.py new file mode 100644 index 000000000..e95c113f3 --- /dev/null +++ b/sources/pyside6/tests/QtWidgets/bug_429.py @@ -0,0 +1,22 @@ +# Copyright (C) 2022 The Qt Company Ltd. +# SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0 + +import os +import sys + +from pathlib import Path +sys.path.append(os.fspath(Path(__file__).resolve().parents[1])) +sys.path.append(os.fspath(Path(__file__).resolve().parents[1] / "util")) +from init_paths import init_test_paths +init_test_paths() + +from PySide6.QtCore import QTimer +from PySide6.QtWidgets import QApplication, QGraphicsScene, QLabel + + +app = QApplication(sys.argv) +scene = QGraphicsScene() +label = QLabel("hello world") +label.show() +QTimer.singleShot(0, label.close) +exit(app.exec()) diff --git a/sources/pyside6/tests/QtWidgets/bug_430.py b/sources/pyside6/tests/QtWidgets/bug_430.py new file mode 100644 index 000000000..6ef9ec7f4 --- /dev/null +++ b/sources/pyside6/tests/QtWidgets/bug_430.py @@ -0,0 +1,29 @@ +# Copyright (C) 2022 The Qt Company Ltd. +# SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0 + +import os +import sys + +from pathlib import Path +sys.path.append(os.fspath(Path(__file__).resolve().parents[1])) +sys.path.append(os.fspath(Path(__file__).resolve().parents[1] / "util")) +from init_paths import init_test_paths +init_test_paths() + +from PySide6.QtCore import QAbstractListModel, QModelIndex, QTimer +from PySide6.QtWidgets import QApplication, QListView + + +class ListModel(QAbstractListModel): + def rowCount(self, parent=QModelIndex()): + return 0 + + +if __name__ == '__main__': + app = QApplication([]) + model = ListModel() + v = QListView() + v.setModel(model) + v.show() + QTimer.singleShot(0, v.close) + app.exec() diff --git a/sources/pyside6/tests/QtWidgets/bug_433.py b/sources/pyside6/tests/QtWidgets/bug_433.py new file mode 100644 index 000000000..c7fbe4b3e --- /dev/null +++ b/sources/pyside6/tests/QtWidgets/bug_433.py @@ -0,0 +1,28 @@ +# Copyright (C) 2022 The Qt Company Ltd. +# SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0 + +import os +import sys + +from pathlib import Path +sys.path.append(os.fspath(Path(__file__).resolve().parents[1])) +sys.path.append(os.fspath(Path(__file__).resolve().parents[1] / "util")) +from init_paths import init_test_paths +init_test_paths() + +from PySide6.QtCore import QTimer +from PySide6.QtWidgets import QApplication, QGraphicsScene, QGraphicsView + + +class Test(QGraphicsView): + def __init__(self, parent=None): + super().__init__(parent) + self.s = QGraphicsScene() + self.setScene(self.s) + + +a = QApplication(sys.argv) +t = Test() +t.show() +QTimer.singleShot(0, t.close) +sys.exit(a.exec_()) diff --git a/sources/pyside6/tests/QtWidgets/bug_467.py b/sources/pyside6/tests/QtWidgets/bug_467.py new file mode 100644 index 000000000..af383e811 --- /dev/null +++ b/sources/pyside6/tests/QtWidgets/bug_467.py @@ -0,0 +1,32 @@ +# 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 bug 367: http://bugs.openbossa.org/show_bug.cgi?id=467''' + +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 helper.usesqapplication import UsesQApplication +from PySide6.QtWidgets import QMainWindow, QApplication + + +class MyWidget(QMainWindow): + def __init__(self, parent=None): + QMainWindow.__init__(self, parent) + + +class BugTest(UsesQApplication): + def testCase(self): + w = MyWidget() + widgets = QApplication.allWidgets() + self.assertTrue(w in widgets) + + +if __name__ == '__main__': + unittest.main() diff --git a/sources/pyside6/tests/QtWidgets/bug_480.py b/sources/pyside6/tests/QtWidgets/bug_480.py new file mode 100644 index 000000000..2fc955561 --- /dev/null +++ b/sources/pyside6/tests/QtWidgets/bug_480.py @@ -0,0 +1,39 @@ +# Copyright (C) 2022 The Qt Company Ltd. +# SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0 + +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.QtWidgets import (QApplication, QGridLayout, QLabel, QVBoxLayout, + QWidget) + + +class BuggyWidget(QWidget): + def setup(self): + self.verticalLayout = QVBoxLayout(self) + self.gridLayout = QGridLayout() + self.lbl = QLabel(self) + self.gridLayout.addWidget(self.lbl, 0, 1, 1, 1) + + # this cause a segfault during the ownership transfer + self.verticalLayout.addLayout(self.gridLayout) + + +class LayoutTransferOwnerShip(unittest.TestCase): + def testBug(self): + app = QApplication([]) + w = BuggyWidget() + w.setup() + w.show() + self.assertTrue(True) + + +if __name__ == '__main__': + unittest.main() + diff --git a/sources/pyside6/tests/QtWidgets/bug_512.py b/sources/pyside6/tests/QtWidgets/bug_512.py new file mode 100644 index 000000000..dab367727 --- /dev/null +++ b/sources/pyside6/tests/QtWidgets/bug_512.py @@ -0,0 +1,34 @@ +# 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 bug 512: http://bugs.openbossa.org/show_bug.cgi?id=512''' + +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 helper.usesqapplication import UsesQApplication +from PySide6.QtWidgets import QGridLayout, QLabel, QWidget + + +class BugTest(UsesQApplication): + def testCase(self): + w = QWidget(None) + lbl = QLabel("Hello", w) + g = QGridLayout() + g.addWidget(lbl, 0, 0) + w.setLayout(g) + w.show() + + t = g.getItemPosition(0) + self.assertEqual(type(t), tuple) + self.assertEqual(t, (0, 0, 1, 1)) + + +if __name__ == '__main__': + unittest.main() diff --git a/sources/pyside6/tests/QtWidgets/bug_525.py b/sources/pyside6/tests/QtWidgets/bug_525.py new file mode 100644 index 000000000..3c49cd377 --- /dev/null +++ b/sources/pyside6/tests/QtWidgets/bug_525.py @@ -0,0 +1,35 @@ +# Copyright (C) 2022 The Qt Company Ltd. +# SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0 + +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.QtWidgets import QApplication +from PySide6.QtWidgets import QMenu + + +class M2(QMenu): + def __init__(self, parent=None): + super().__init__(parent) + self.setTitle(self.tr("M2")) + + +class TestMenuDerivedClass(unittest.TestCase): + def aboutToShowHandler(self): + pass + + def testConnectSignal(self): + app = QApplication([]) + m2 = M2() + # Test if the aboutToShow signal was translated to correct type + m2.aboutToShow.connect(self.aboutToShowHandler) + + +if __name__ == '__main__': + unittest.main() diff --git a/sources/pyside6/tests/QtWidgets/bug_546.py b/sources/pyside6/tests/QtWidgets/bug_546.py new file mode 100644 index 000000000..fcec2f6d7 --- /dev/null +++ b/sources/pyside6/tests/QtWidgets/bug_546.py @@ -0,0 +1,27 @@ +# Copyright (C) 2022 The Qt Company Ltd. +# SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0 + +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.QtWidgets import QApplication, QCompleter, QPlainTextEdit + + +class TestBug546(unittest.TestCase): + + """Test to check a crash at exit""" + def testIt(self): + app = QApplication([]) + textEdit = QPlainTextEdit() + completer = QCompleter(("foo", "bar"), textEdit) + completer.setWidget(textEdit) + + +if __name__ == '__main__': + unittest.main() diff --git a/sources/pyside6/tests/QtWidgets/bug_547.py b/sources/pyside6/tests/QtWidgets/bug_547.py new file mode 100644 index 000000000..dcbe20ee8 --- /dev/null +++ b/sources/pyside6/tests/QtWidgets/bug_547.py @@ -0,0 +1,73 @@ +# Copyright (C) 2022 The Qt Company Ltd. +# SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0 + +""" Unittest for bug #547 """ +""" http://bugs.openbossa.org/show_bug.cgi?id=547 """ + +import sys +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.QtWidgets import QApplication, QTreeWidget, QTreeWidgetItem + + +class MyMainWindow(unittest.TestCase): + app = QApplication(sys.argv) + + @unittest.skipUnless(hasattr(sys, "getrefcount"), f"{sys.implementation.name} has no refcount") + def testCase1(self): + self._tree = QTreeWidget() + self._tree.setColumnCount(2) + self._i1 = None + self._i11 = None + + self._updateTree() + self.assertEqual(sys.getrefcount(self._i1), 3) + self.assertEqual(sys.getrefcount(self._i11), 3) + + self._i11.parent().setExpanded(True) + self._i11.setExpanded(True) + + self._updateTree() + self.assertEqual(sys.getrefcount(self._i1), 3) + self.assertEqual(sys.getrefcount(self._i11), 3) + + @unittest.skipUnless(hasattr(sys, "getrefcount"), f"{sys.implementation.name} has no refcount") + def testCase2(self): + self._tree = QTreeWidget() + self._tree.setColumnCount(2) + self._i1 = None + self._i11 = None + + self._updateTree() + self.assertEqual(sys.getrefcount(self._i1), 3) + self.assertEqual(sys.getrefcount(self._i11), 3) + + self._i11.parent().setExpanded(True) + self._i11.setExpanded(True) + + self.assertEqual(sys.getrefcount(self._i1), 3) + self.assertEqual(sys.getrefcount(self._i11), 3) + + @unittest.skipUnless(hasattr(sys, "getrefcount"), f"{sys.implementation.name} has no refcount") + def _updateTree(self): + self._tree.clear() + if self._i1 and self._i11: + self.assertEqual(sys.getrefcount(self._i1), 2) + self.assertEqual(sys.getrefcount(self._i11), 2) + + self._i1 = QTreeWidgetItem(self._tree, ['1', ]) + self.assertEqual(sys.getrefcount(self._i1), 3) + self._i11 = QTreeWidgetItem(self._i1, ['11', ]) + self.assertEqual(sys.getrefcount(self._i11), 3) + + +if __name__ == '__main__': + unittest.main() + diff --git a/sources/pyside6/tests/QtWidgets/bug_549.py b/sources/pyside6/tests/QtWidgets/bug_549.py new file mode 100644 index 000000000..8efa6e679 --- /dev/null +++ b/sources/pyside6/tests/QtWidgets/bug_549.py @@ -0,0 +1,28 @@ +# Copyright (C) 2022 The Qt Company Ltd. +# SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0 + +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.QtWidgets import QApplication, QGraphicsWidget + + +class TestBug549(unittest.TestCase): + def testBug(self): + app = QApplication([]) + w = QGraphicsWidget() + w.setContentsMargins(1, 2, 3, 4) + self.assertEqual(w.getContentsMargins(), (1, 2, 3, 4)) + w.setWindowFrameMargins(5, 6, 7, 8) + self.assertEqual(w.getWindowFrameMargins(), (5, 6, 7, 8)) + + +if __name__ == '__main__': + unittest.main() + diff --git a/sources/pyside6/tests/QtWidgets/bug_569.py b/sources/pyside6/tests/QtWidgets/bug_569.py new file mode 100644 index 000000000..0f95aed02 --- /dev/null +++ b/sources/pyside6/tests/QtWidgets/bug_569.py @@ -0,0 +1,30 @@ +# Copyright (C) 2022 The Qt Company Ltd. +# SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0 + +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.QtWidgets import QTableWidgetItem, QListWidgetItem, QTreeWidgetItem + + +class TestBug569(unittest.TestCase): + + def testIt(self): + types = (QTableWidgetItem, QListWidgetItem, QTreeWidgetItem) + for t in types: + a = t() + a.__lt__ = lambda other: True + b = t() + b.__lt__ = lambda other: False + self.assertTrue(a < b) + self.assertFalse(b < a) + + +if __name__ == '__main__': + unittest.main() diff --git a/sources/pyside6/tests/QtWidgets/bug_575.py b/sources/pyside6/tests/QtWidgets/bug_575.py new file mode 100644 index 000000000..f9a927817 --- /dev/null +++ b/sources/pyside6/tests/QtWidgets/bug_575.py @@ -0,0 +1,33 @@ +# Copyright (C) 2022 The Qt Company Ltd. +# SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0 + +""" Unittest for bug #575 """ +""" http://bugs.openbossa.org/show_bug.cgi?id=575 """ + +import sys +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.QtWidgets import QApplication, QPlainTextEdit, QTextEdit + + +class Bug575(unittest.TestCase): + def testPropertyValues(self): + app = QApplication(sys.argv) + textEdit = QPlainTextEdit() + textEdit.insertPlainText("PySide INdT") + selection = QTextEdit.ExtraSelection() + selection.cursor = textEdit.textCursor() + selection.cursor.setPosition(2) + self.assertEqual(selection.cursor.position(), 2) + + +if __name__ == '__main__': + unittest.main() + diff --git a/sources/pyside6/tests/QtWidgets/bug_576.py b/sources/pyside6/tests/QtWidgets/bug_576.py new file mode 100644 index 000000000..4a17e7aa8 --- /dev/null +++ b/sources/pyside6/tests/QtWidgets/bug_576.py @@ -0,0 +1,49 @@ +# Copyright (C) 2022 The Qt Company Ltd. +# SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0 + +""" Unittest for bug #576 """ +""" http://bugs.openbossa.org/show_bug.cgi?id=576 """ + +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 +from PySide6.QtWidgets import QApplication, QPushButton, QWidget + + +class Bug576(unittest.TestCase): + def onButtonDestroyed(self, button): + self._destroyed = True + self.assertTrue(isinstance(button, QPushButton)) + + @unittest.skipUnless(hasattr(sys, "getrefcount"), f"{sys.implementation.name} has no refcount") + def testWidgetParent(self): + self._destroyed = False + app = QApplication(sys.argv) + w = QWidget() + + b = QPushButton("test") + b.destroyed[QObject].connect(self.onButtonDestroyed) + self.assertEqual(sys.getrefcount(b), 2) + b.setParent(w) + self.assertEqual(sys.getrefcount(b), 3) + b.parent() + self.assertEqual(sys.getrefcount(b), 3) + b.setParent(None) + self.assertEqual(sys.getrefcount(b), 2) + del b + # PYSIDE-535: Need to collect garbage in PyPy to trigger deletion + gc.collect() + self.assertTrue(self._destroyed) + + +if __name__ == '__main__': + unittest.main() + diff --git a/sources/pyside6/tests/QtWidgets/bug_585.py b/sources/pyside6/tests/QtWidgets/bug_585.py new file mode 100644 index 000000000..e26ca9ce0 --- /dev/null +++ b/sources/pyside6/tests/QtWidgets/bug_585.py @@ -0,0 +1,38 @@ +# 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 bug 585: http://bugs.openbossa.org/show_bug.cgi?id=585''' + +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.QtWidgets import QApplication, QTreeWidget, QTreeWidgetItem + + +class Bug585(unittest.TestCase): + @unittest.skipUnless(hasattr(sys, "getrefcount"), f"{sys.implementation.name} has no refcount") + def testCase(self): + app = QApplication([]) + self._tree = QTreeWidget() + self._tree.setColumnCount(2) + i1 = QTreeWidgetItem(self._tree, ['1', ]) + i2 = QTreeWidgetItem(self._tree, ['2', ]) + refCount = sys.getrefcount(i1) + + # this function return None + # because the topLevelItem does not has a parent item + # but still have a TreeWidget as a parent + self._tree.topLevelItem(0).parent() + + self.assertEqual(refCount, sys.getrefcount(i1)) + + +if __name__ == '__main__': + unittest.main() + diff --git a/sources/pyside6/tests/QtWidgets/bug_589.py b/sources/pyside6/tests/QtWidgets/bug_589.py new file mode 100644 index 000000000..a19f544a5 --- /dev/null +++ b/sources/pyside6/tests/QtWidgets/bug_589.py @@ -0,0 +1,32 @@ +# Copyright (C) 2022 The Qt Company Ltd. +# SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0 + +# trimmed down diagramscene.py to demonstrate crash in sizeHint() + +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.QtWidgets import QApplication, QGraphicsProxyWidget + + +class CustomWidget(QGraphicsProxyWidget): + def itemChange(self, eventType, value): + QGraphicsProxyWidget.itemChange(self, eventType, value) + + +class Bug589(unittest.TestCase): + def testCase(self): + widget = QGraphicsProxyWidget() + custom = CustomWidget() + custom.setParentItem(widget) + + +if __name__ == "__main__": + app = QApplication(sys.argv) + unittest.main() diff --git a/sources/pyside6/tests/QtWidgets/bug_635.py b/sources/pyside6/tests/QtWidgets/bug_635.py new file mode 100644 index 000000000..66a8c58c6 --- /dev/null +++ b/sources/pyside6/tests/QtWidgets/bug_635.py @@ -0,0 +1,41 @@ +# 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 bug 635: http://bugs.openbossa.org/show_bug.cgi?id=635''' + +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.QtGui import QIcon +from PySide6.QtWidgets import QApplication, QToolBar + + +class testQToolBar(unittest.TestCase): + def callback(self): + self._called = True + + def testAddAction(self): + bar = QToolBar() + self._called = False + a = bar.addAction("act1", self.callback) + a.trigger() + self.assertTrue(self._called) + + def testAddActionWithIcon(self): + bar = QToolBar() + self._called = False + icon = QIcon() + a = bar.addAction(icon, "act1", self.callback) + a.trigger() + self.assertTrue(self._called) + + +if __name__ == '__main__': + app = QApplication(sys.argv) + unittest.main() diff --git a/sources/pyside6/tests/QtWidgets/bug_640.py b/sources/pyside6/tests/QtWidgets/bug_640.py new file mode 100644 index 000000000..b2620b541 --- /dev/null +++ b/sources/pyside6/tests/QtWidgets/bug_640.py @@ -0,0 +1,23 @@ +# Copyright (C) 2022 The Qt Company Ltd. +# SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0 + +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.QtWidgets import QStyleOptionGraphicsItem + + +class Bug640(unittest.TestCase): + def testIt(self): + option = QStyleOptionGraphicsItem() + a = option.state # crash!? + + +if __name__ == "__main__": + unittest.main() diff --git a/sources/pyside6/tests/QtWidgets/bug_653.py b/sources/pyside6/tests/QtWidgets/bug_653.py new file mode 100644 index 000000000..1cf8390df --- /dev/null +++ b/sources/pyside6/tests/QtWidgets/bug_653.py @@ -0,0 +1,29 @@ +# Copyright (C) 2022 The Qt Company Ltd. +# SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0 + +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.QtWidgets import QApplication, QWizard, QWizardPage + + +class TestBug653(unittest.TestCase): + """Crash after calling QWizardPage.wizard()""" + def testIt(self): + app = QApplication([]) + + wizard = QWizard() + page = QWizardPage() + wizard.addPage(page) + page.wizard() # crash here if the bug still exists due to a circular dependency + wizard.show() + + +if __name__ == "__main__": + unittest.main() diff --git a/sources/pyside6/tests/QtWidgets/bug_662.py b/sources/pyside6/tests/QtWidgets/bug_662.py new file mode 100644 index 000000000..e3a3130d0 --- /dev/null +++ b/sources/pyside6/tests/QtWidgets/bug_662.py @@ -0,0 +1,42 @@ +# 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 bug 662: http://bugs.openbossa.org/show_bug.cgi?id=662''' + +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.QtGui import QTextCharFormat +from PySide6.QtWidgets import QTextEdit, QApplication +import sys + + +class testQTextBlock(unittest.TestCase): + + def testIterator(self): + edit = QTextEdit() + cursor = edit.textCursor() + fmt = QTextCharFormat() + frags = [] + for i in range(10): + fmt.setFontPointSize(i + 10) + frags.append(f"block{i}") + cursor.insertText(frags[i], fmt) + + doc = edit.document() + block = doc.begin() + + index = 0 + for i in block: + self.assertEqual(i.fragment().text(), frags[index]) + index += 1 + + +if __name__ == '__main__': + app = QApplication(sys.argv) + unittest.main() diff --git a/sources/pyside6/tests/QtWidgets/bug_667.py b/sources/pyside6/tests/QtWidgets/bug_667.py new file mode 100644 index 000000000..be6700d83 --- /dev/null +++ b/sources/pyside6/tests/QtWidgets/bug_667.py @@ -0,0 +1,37 @@ +# Copyright (C) 2022 The Qt Company Ltd. +# SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0 + +import os +import sys + +from pathlib import Path +sys.path.append(os.fspath(Path(__file__).resolve().parents[1])) +sys.path.append(os.fspath(Path(__file__).resolve().parents[1] / "util")) +from init_paths import init_test_paths +init_test_paths() + +from PySide6.QtCore import QTimer, QPointF +from PySide6.QtWidgets import QApplication, QGraphicsView, QGraphicsScene, QGraphicsEllipseItem + + +class Ball(QGraphicsEllipseItem): + def __init__(self, d, parent=None): + super().__init__(0, 0, d, d, parent) + self.vel = QPointF(0, 0) # commenting this out prevents the crash + + +class Foo(QGraphicsView): + def __init__(self): + super().__init__(None) + self.scene = QGraphicsScene(self.rect()) + self.setScene(self.scene) + self.scene.addItem(Ball(10)) + + +if __name__ == "__main__": + app = QApplication(sys.argv) + w = Foo() + w.show() + w.raise_() + QTimer.singleShot(0, w.close) + sys.exit(app.exec()) diff --git a/sources/pyside6/tests/QtWidgets/bug_668.py b/sources/pyside6/tests/QtWidgets/bug_668.py new file mode 100644 index 000000000..0c22436b3 --- /dev/null +++ b/sources/pyside6/tests/QtWidgets/bug_668.py @@ -0,0 +1,34 @@ +# Copyright (C) 2022 The Qt Company Ltd. +# SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0 + +import os +import sys + +from pathlib import Path +sys.path.append(os.fspath(Path(__file__).resolve().parents[1])) +sys.path.append(os.fspath(Path(__file__).resolve().parents[1] / "util")) +from init_paths import init_test_paths +init_test_paths() + +from PySide6.QtCore import QDir, QModelIndex, QTimer +from PySide6.QtWidgets import QApplication, QFileSystemModel, QMainWindow, QTreeView + + +class A(QMainWindow): + def __init__(self, parent=None): + super().__init__(parent) + a = QFileSystemModel(self) + a.setRootPath(QDir.homePath()) + + v = QTreeView(self) + v.setModel(a) + self.setCentralWidget(v) + # Test index() method (see PYSIDE-570, PYSIDE-331) + index = a.index(0, 0, QModelIndex()) + + +app = QApplication([]) +m = A() +m.show() +QTimer.singleShot(0, m.close) +app.exec() diff --git a/sources/pyside6/tests/QtWidgets/bug_674.py b/sources/pyside6/tests/QtWidgets/bug_674.py new file mode 100644 index 000000000..901b29275 --- /dev/null +++ b/sources/pyside6/tests/QtWidgets/bug_674.py @@ -0,0 +1,35 @@ +# Copyright (C) 2022 The Qt Company Ltd. +# SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0 + +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.QtWidgets import QApplication, QGraphicsScene + + +class TestBug679(unittest.TestCase): + '''QGraphicsScene::clear() is missing''' + @unittest.skipUnless(hasattr(sys, "getrefcount"), f"{sys.implementation.name} has no refcount") + def testIt(self): + app = QApplication([]) + + scene = QGraphicsScene() + hello = scene.addText("Hello") + scene.addText("World") + + self.assertEqual(sys.getrefcount(hello), 3) + scene.clear() + self.assertEqual(sys.getrefcount(hello), 2) + self.assertEqual(len(scene.items()), 0) + self.assertRaises(RuntimeError, hello.isVisible) # the C++ object was deleted + + +if __name__ == '__main__': + unittest.main() + diff --git a/sources/pyside6/tests/QtWidgets/bug_675.py b/sources/pyside6/tests/QtWidgets/bug_675.py new file mode 100644 index 000000000..221df88b0 --- /dev/null +++ b/sources/pyside6/tests/QtWidgets/bug_675.py @@ -0,0 +1,28 @@ +# Copyright (C) 2022 The Qt Company Ltd. +# SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0 + +import os +import sys + +from pathlib import Path +sys.path.append(os.fspath(Path(__file__).resolve().parents[1])) +sys.path.append(os.fspath(Path(__file__).resolve().parents[1] / "util")) +from init_paths import init_test_paths +init_test_paths() + +from PySide6.QtWidgets import (QApplication, QGraphicsLinearLayout, + QGraphicsScene, QGraphicsView, QTextEdit) + + +app = QApplication([]) + +scene = QGraphicsScene() + +# don't segfault due to lack of keepReferenceCall +textEdit = scene.addWidget(QTextEdit()) + +layout = QGraphicsLinearLayout() +layout.addItem(textEdit) + +view = QGraphicsView(scene) +view.show() diff --git a/sources/pyside6/tests/QtWidgets/bug_688.py b/sources/pyside6/tests/QtWidgets/bug_688.py new file mode 100644 index 000000000..3180d08bf --- /dev/null +++ b/sources/pyside6/tests/QtWidgets/bug_688.py @@ -0,0 +1,98 @@ +# 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 bug 688: http://bugs.openbossa.org/show_bug.cgi?id=688''' + +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 helper.usesqapplication import UsesQApplication +from PySide6.QtGui import QTextFrame, QTextCursor, QTextCharFormat, QFont, QTextFrameFormat +from PySide6.QtWidgets import QTextEdit + + +class BugTest(UsesQApplication): + def testCase(self): + editor = QTextEdit() + cursor = QTextCursor(editor.textCursor()) + cursor.movePosition(QTextCursor.Start) + + mainFrame = cursor.currentFrame() + + plainCharFormat = QTextCharFormat() + boldCharFormat = QTextCharFormat() + boldCharFormat.setFontWeight(QFont.Bold) + cursor.insertText(""" + Text documents are represented by the + QTextDocument class, rather than by QString objects. + Each QTextDocument object contains information about + the document's internal representation, its structure, + and keeps track of modifications to provide undo/redo + facilities. This approach allows features such as the + layout management to be delegated to specialized + classes, but also provides a focus for the framework.""", + plainCharFormat) + + frameFormat = QTextFrameFormat() + frameFormat.setMargin(32) + frameFormat.setPadding(8) + frameFormat.setBorder(4) + cursor.insertFrame(frameFormat) + + cursor.insertText(""" + Documents are either converted from external sources + or created from scratch using Qt. The creation process + can done by an editor widget, such as QTextEdit, or by + explicit calls to the Scribe API.""", + boldCharFormat) + + cursor = mainFrame.lastCursorPosition() + cursor.insertText(""" + There are two complementary ways to visualize the + contents of a document: as a linear buffer that is + used by editors to modify the contents, and as an + object hierarchy containing structural information + that is useful to layout engines. In the hierarchical + model, the objects generally correspond to visual + elements such as frames, tables, and lists. At a lower + level, these elements describe properties such as the + style of text used and its alignment. The linear + representation of the document is used for editing and + manipulation of the document's contents.""", + plainCharFormat) + + frame = cursor.currentFrame() + + items = [] + + # test iterator + for i in frame: + items.append(i) + + # test __iadd__ + b = frame.begin() + i = 0 + while not b.atEnd(): + self.assertEqual(b, items[i]) + self.assertTrue(b.parentFrame(), items[i].parentFrame()) + b.__iadd__(1) + i += 1 + + # test __isub__ + b = frame.end() + i = 0 + while i > 0: + self.assertEqual(b, items[i]) + self.assertTrue(b.parentFrame(), items[i].parentFrame()) + b.__isub__(1) + i -= 1 + + +if __name__ == '__main__': + unittest.main() diff --git a/sources/pyside6/tests/QtWidgets/bug_693.py b/sources/pyside6/tests/QtWidgets/bug_693.py new file mode 100644 index 000000000..95981e272 --- /dev/null +++ b/sources/pyside6/tests/QtWidgets/bug_693.py @@ -0,0 +1,42 @@ +# Copyright (C) 2022 The Qt Company Ltd. +# SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0 + +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 QAbstractListModel, QLine +from PySide6.QtWidgets import QApplication, QListView + + +class MyModel (QAbstractListModel): + + stupidLine = QLine(0, 0, 10, 10) + + def rowCount(self, parent): + return 1 + + def data(self, index, role): + return self.stupidLine + + +class TestBug693(unittest.TestCase): + def testIt(self): + app = QApplication([]) + model = MyModel() + view = QListView() + view.setModel(model) + view.show() + + # This must NOT throw the exception: + # RuntimeError: Internal C++ object (PySide6.QtCore.QLine) already deleted. + MyModel.stupidLine.isNull() + + +if __name__ == "__main__": + unittest.main() diff --git a/sources/pyside6/tests/QtWidgets/bug_696.py b/sources/pyside6/tests/QtWidgets/bug_696.py new file mode 100644 index 000000000..19e9978a6 --- /dev/null +++ b/sources/pyside6/tests/QtWidgets/bug_696.py @@ -0,0 +1,38 @@ +#!/usr/bin/env python +# Copyright (C) 2022 The Qt Company Ltd. +# SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0 + +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 helper.usesqapplication import UsesQApplication +from PySide6.QtWidgets import QMainWindow, QMenu, QApplication + + +class MainWindow(QMainWindow): + def __init__(self, *args): + self._menu = QMenu(self.dontexist) # attribute called with invalid C++ object + + +class MainWindow2(QMainWindow): + def __init__(self): + self.show() + + +class Bug696(UsesQApplication): + def testContructorInitialization(self): + self.assertRaises(AttributeError, MainWindow) + + def testContructorInitializationAndCPPFunction(self): + self.assertRaises(RuntimeError, MainWindow2) + + +if __name__ == '__main__': + unittest.main() + diff --git a/sources/pyside6/tests/QtWidgets/bug_711.py b/sources/pyside6/tests/QtWidgets/bug_711.py new file mode 100644 index 000000000..fed330fb9 --- /dev/null +++ b/sources/pyside6/tests/QtWidgets/bug_711.py @@ -0,0 +1,34 @@ +# Copyright (C) 2022 The Qt Company Ltd. +# SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0 + +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.QtGui import QAction +from PySide6.QtWidgets import QToolBar, QApplication, QToolButton + + +class TestLabelPixmap(unittest.TestCase): + def testReference(self): + toolbar = QToolBar() + + for i in range(20): + toolbar.addAction(QAction(f"Action {i}")) + + buttons = toolbar.findChildren(QToolButton, "") + toolbar.clear() + + for b in buttons: + self.assertRaises(RuntimeError, b.objectName) + + +if __name__ == '__main__': + app = QApplication([]) + unittest.main() + diff --git a/sources/pyside6/tests/QtWidgets/bug_722.py b/sources/pyside6/tests/QtWidgets/bug_722.py new file mode 100644 index 000000000..dc20e14cf --- /dev/null +++ b/sources/pyside6/tests/QtWidgets/bug_722.py @@ -0,0 +1,36 @@ +# Copyright (C) 2022 The Qt Company Ltd. +# SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0 + +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 helper.usesqapplication import UsesQApplication + +from PySide6.QtWidgets import QDoubleSpinBox, QGraphicsBlurEffect + + +class TestSignalConnection(UsesQApplication): + def testFloatSignal(self): + foo1 = QDoubleSpinBox() + foo2 = QDoubleSpinBox() + foo1.valueChanged[float].connect(foo2.setValue) + foo2.valueChanged[float].connect(foo1.setValue) + foo1.setValue(0.42) + self.assertEqual(foo1.value(), foo2.value()) + + def testQRealSignal(self): + foo1 = QDoubleSpinBox() + effect = QGraphicsBlurEffect() + effect.blurRadiusChanged['qreal'].connect(foo1.setValue) # check if qreal is a valid type + effect.setBlurRadius(0.42) + self.assertAlmostEqual(foo1.value(), effect.blurRadius()) + + +if __name__ == '__main__': + unittest.main() diff --git a/sources/pyside6/tests/QtWidgets/bug_728.py b/sources/pyside6/tests/QtWidgets/bug_728.py new file mode 100644 index 000000000..531adbb25 --- /dev/null +++ b/sources/pyside6/tests/QtWidgets/bug_728.py @@ -0,0 +1,39 @@ +# Copyright (C) 2022 The Qt Company Ltd. +# SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0 + +import os +import sys + +from pathlib import Path +sys.path.append(os.fspath(Path(__file__).resolve().parents[1])) +sys.path.append(os.fspath(Path(__file__).resolve().parents[1] / "util")) +from init_paths import init_test_paths +init_test_paths() + +from PySide6.QtWidgets import QApplication, QDialog, QFileDialog +from PySide6.QtCore import QDir, QTimer + + +# Periodically check for the file dialog to appear and close it +dialog = None + + +def timerHandler(): + global dialog + if dialog is not None: + dialog.reject() + else: + for widget in QApplication.topLevelWidgets(): + if isinstance(widget, QDialog) and widget.isVisible(): + dialog = widget + + +app = QApplication([]) +QTimer.singleShot(30000, app.quit) # emergency +timer = QTimer() +timer.setInterval(50) +timer.timeout.connect(timerHandler) +timer.start() + +# This test for a dead lock in QFileDialog.getOpenFileNames, the test fail with a timeout if the dead lock exists. +QFileDialog.getOpenFileNames(None, "caption", QDir.homePath(), None, "", QFileDialog.DontUseNativeDialog) diff --git a/sources/pyside6/tests/QtWidgets/bug_736.py b/sources/pyside6/tests/QtWidgets/bug_736.py new file mode 100644 index 000000000..af4bcbda8 --- /dev/null +++ b/sources/pyside6/tests/QtWidgets/bug_736.py @@ -0,0 +1,30 @@ +# Copyright (C) 2022 The Qt Company Ltd. +# SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0 + +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 Qt +from PySide6.QtWidgets import QApplication, QSlider + + +class TestBug736 (unittest.TestCase): + + def testIt(self): + app = QApplication([]) + slider = QSlider(Qt.Horizontal) + slider2 = QSlider(Qt.Horizontal) + + slider2.setMaximum(10) + slider.valueChanged[int].connect(slider2.setMaximum) + slider.valueChanged[int].emit(100) + self.assertEqual(slider2.maximum(), 100) + + +if __name__ == '__main__': + unittest.main() diff --git a/sources/pyside6/tests/QtWidgets/bug_750.py b/sources/pyside6/tests/QtWidgets/bug_750.py new file mode 100644 index 000000000..999f6a3db --- /dev/null +++ b/sources/pyside6/tests/QtWidgets/bug_750.py @@ -0,0 +1,38 @@ +# Copyright (C) 2022 The Qt Company Ltd. +# SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0 + +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 helper.usesqapplication import UsesQApplication + +from PySide6.QtCore import QTimer +from PySide6.QtGui import QPainter, QFont, QFontInfo +from PySide6.QtWidgets import QWidget + + +class MyWidget(QWidget): + def paintEvent(self, e): + p = QPainter(self) + self._info = p.fontInfo() + self._app.quit() + + +class TestQPainter(UsesQApplication): + def testFontInfo(self): + w = MyWidget() + w._app = self.app + w._info = None + QTimer.singleShot(300, w.show) + self.app.exec() + self.assertTrue(w._info) + + +if __name__ == '__main__': + unittest.main() diff --git a/sources/pyside6/tests/QtWidgets/bug_778.py b/sources/pyside6/tests/QtWidgets/bug_778.py new file mode 100644 index 000000000..1a7def6c7 --- /dev/null +++ b/sources/pyside6/tests/QtWidgets/bug_778.py @@ -0,0 +1,34 @@ +# Copyright (C) 2022 The Qt Company Ltd. +# SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0 + +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 helper.usesqapplication import UsesQApplication + +from PySide6.QtWidgets import QTreeWidget, QTreeWidgetItem, QTreeWidgetItemIterator + + +class QTreeWidgetItemIteratorTest(UsesQApplication): + def testWidgetIterator(self): + treeWidget = QTreeWidget() + treeWidget.setColumnCount(1) + items = [] + for i in range(10): + items.append(QTreeWidgetItem(None, [f'item: {i}'])) + treeWidget.insertTopLevelItems(0, items) + + index = 0 + for it in QTreeWidgetItemIterator(treeWidget): + self.assertEqual(it.value().text(0), f'item: {index}') + index += 1 + + +if __name__ == '__main__': + unittest.main() diff --git a/sources/pyside6/tests/QtWidgets/bug_793.py b/sources/pyside6/tests/QtWidgets/bug_793.py new file mode 100644 index 000000000..94f42a5d3 --- /dev/null +++ b/sources/pyside6/tests/QtWidgets/bug_793.py @@ -0,0 +1,45 @@ +# Copyright (C) 2022 The Qt Company Ltd. +# SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0 + +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 QTimer +from PySide6.QtWidgets import QWidget, QApplication + + +class TestW1(QWidget): + def __init__(self, parent=None): + super().__init__(parent) + TestW2(parent, self) + + +class TestW2(QWidget): + def __init__(self, ancestor, parent=None): + super().__init__(parent) + self.ancestor_ref = ancestor + + +class Test(QWidget): + def __init__(self): + super().__init__() + TestW1(self) + + +class TestQApplicationDestrcutor(unittest.TestCase): + def testDestructor(self): + w = Test() + w.show() + QTimer.singleShot(0, w.close) + + +if __name__ == '__main__': + app = QApplication(sys.argv) + unittest.main() + sys.exit(app.exec()) diff --git a/sources/pyside6/tests/QtWidgets/bug_811.py b/sources/pyside6/tests/QtWidgets/bug_811.py new file mode 100644 index 000000000..b3537e1f7 --- /dev/null +++ b/sources/pyside6/tests/QtWidgets/bug_811.py @@ -0,0 +1,46 @@ +# Copyright (C) 2022 The Qt Company Ltd. +# SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0 + +import os +import sys +import unittest +import weakref + +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 helper.usesqapplication import UsesQApplication + +from PySide6.QtGui import QTextBlockUserData, QTextCursor +from PySide6.QtWidgets import QTextEdit + + +class TestUserData(QTextBlockUserData): + def __init__(self, data): + super().__init__() + self.data = data + + +class TestUserDataRefCount(UsesQApplication): + @unittest.skipUnless(hasattr(sys, "getrefcount"), f"{sys.implementation.name} has no refcount") + def testRefcount(self): + textedit = QTextEdit() + textedit.setReadOnly(True) + doc = textedit.document() + cursor = QTextCursor(doc) + cursor.insertText("PySide Rocks") + ud = TestUserData({"Life": 42}) + self.assertEqual(sys.getrefcount(ud), 2) + cursor.block().setUserData(ud) + self.assertEqual(sys.getrefcount(ud), 3) + ud2 = cursor.block().userData() + self.assertEqual(sys.getrefcount(ud), 4) + self.udata = weakref.ref(ud, None) + del ud, ud2 + self.assertEqual(sys.getrefcount(self.udata()), 2) + + +if __name__ == '__main__': + unittest.main() diff --git a/sources/pyside6/tests/QtWidgets/bug_834.py b/sources/pyside6/tests/QtWidgets/bug_834.py new file mode 100644 index 000000000..685f17e56 --- /dev/null +++ b/sources/pyside6/tests/QtWidgets/bug_834.py @@ -0,0 +1,33 @@ +# Copyright (C) 2022 The Qt Company Ltd. +# SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0 + +import os +import sys + +from pathlib import Path +sys.path.append(os.fspath(Path(__file__).resolve().parents[1])) +sys.path.append(os.fspath(Path(__file__).resolve().parents[1] / "util")) +from init_paths import init_test_paths +init_test_paths() + +from PySide6.QtCore import QTimer, Qt +from PySide6.QtWidgets import QApplication, QDockWidget, QMainWindow + + +class Window(QMainWindow): + def childEvent(self, event): + super(Window, self).childEvent(event) + + +app = QApplication([]) +window = Window() + +dock1 = QDockWidget() +dock2 = QDockWidget() +window.addDockWidget(Qt.LeftDockWidgetArea, dock1) +window.addDockWidget(Qt.LeftDockWidgetArea, dock2) +window.tabifyDockWidget(dock1, dock2) + +window.show() +QTimer.singleShot(0, window.close) +app.exec() diff --git a/sources/pyside6/tests/QtWidgets/bug_836.py b/sources/pyside6/tests/QtWidgets/bug_836.py new file mode 100644 index 000000000..c2d3d5609 --- /dev/null +++ b/sources/pyside6/tests/QtWidgets/bug_836.py @@ -0,0 +1,46 @@ +# Copyright (C) 2022 The Qt Company Ltd. +# SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0 + +import os +import sys + +from pathlib import Path +sys.path.append(os.fspath(Path(__file__).resolve().parents[1])) +sys.path.append(os.fspath(Path(__file__).resolve().parents[1] / "util")) +from init_paths import init_test_paths +init_test_paths() + +from PySide6.QtCore import QTimer +from PySide6.QtWidgets import QApplication, QFrame + + +class Mixin1(object): + pass + + +class Mixin2(object): + pass + + +class Mixin3(object): + pass + + +class MainWindow(Mixin1, Mixin2, Mixin3, QFrame): + def __init__(self): + super().__init__() + + +def main(): + app = QApplication([]) + # if it doesn't crash it should pass + w = MainWindow() + w.show() + QTimer.singleShot(0, w.close) + app.exec() + + +if __name__ == "__main__": + main() + + diff --git a/sources/pyside6/tests/QtWidgets/bug_844.py b/sources/pyside6/tests/QtWidgets/bug_844.py new file mode 100644 index 000000000..913b4235c --- /dev/null +++ b/sources/pyside6/tests/QtWidgets/bug_844.py @@ -0,0 +1,31 @@ +# Copyright (C) 2022 The Qt Company Ltd. +# SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0 + +import sys +import os + +from pathlib import Path +sys.path.append(os.fspath(Path(__file__).resolve().parents[1])) +from init_paths import init_test_paths +init_test_paths() + +from PySide6.QtWidgets import QApplication, QLabel +from PySide6.QtCore import QObject, QTimer + + +class QtKeyPressListener(QObject): + def __init__(self, obj): + super().__init__() + obj.installEventFilter(self) + + def eventFilter(self, obj, event): + # This used to crash here due to a misbehaviour of type discovery! + return QObject.eventFilter(self, obj, event) + + +app = QApplication([]) +key_listener = QtKeyPressListener(app) +w = QLabel('Hello') +w.show() +QTimer.singleShot(0, w.close) +app.exec() diff --git a/sources/pyside6/tests/QtWidgets/bug_854.py b/sources/pyside6/tests/QtWidgets/bug_854.py new file mode 100644 index 000000000..1dbfd4b3a --- /dev/null +++ b/sources/pyside6/tests/QtWidgets/bug_854.py @@ -0,0 +1,54 @@ +# Copyright (C) 2022 The Qt Company Ltd. +# SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0 + +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.QtWidgets import QTableView, QApplication +from PySide6.QtCore import QAbstractItemModel, QModelIndex + +from helper.usesqapplication import UsesQApplication + + +class VirtualList(QAbstractItemModel): + def __getitem__(self, index): + self._getItemCalled = True + pass + + def rowCount(self, parent): + return 5000 + + def columnCount(self, parent): + return 3 + + def index(self, row, column, parent): + return self.createIndex(row, column) + + def parent(self, index): + return QModelIndex() + + def data(self, index, role): + row = index.row() + col = index.column() + return f"({row}, {col})" + + +class TestQAbstractItemModel(UsesQApplication): + def testSetModel(self): + model = VirtualList() + model._getItemCalled = False + table = QTableView() + table.setModel(model) + table.show() + self.assertFalse(model._getItemCalled) + + +if __name__ == "__main__": + unittest.main() + diff --git a/sources/pyside6/tests/QtWidgets/bug_860.py b/sources/pyside6/tests/QtWidgets/bug_860.py new file mode 100644 index 000000000..779feaa14 --- /dev/null +++ b/sources/pyside6/tests/QtWidgets/bug_860.py @@ -0,0 +1,46 @@ +# Copyright (C) 2022 The Qt Company Ltd. +# SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0 + +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 QSignalMapper +from PySide6.QtWidgets import QCheckBox + +from helper.usesqapplication import UsesQApplication + + +class MultipleSlotTest(UsesQApplication): + def cb_changed(self, i): + self._changed = True + + def cb_changedVoid(self): + self._changed = True + + def testSignalMapper(self): + checkboxMapper = QSignalMapper() + box = QCheckBox('check me') + box.stateChanged.connect(checkboxMapper.map) + + checkboxMapper.setMapping(box, box.text()) + checkboxMapper.mappedString[str].connect(self.cb_changed) + self._changed = False + box.setChecked(True) + self.assertTrue(self._changed) + + def testSimpleSignal(self): + box = QCheckBox('check me') + box.stateChanged[int].connect(self.cb_changedVoid) + self._changed = False + box.setChecked(True) + self.assertTrue(self._changed) + + +if __name__ == '__main__': + unittest.main() diff --git a/sources/pyside6/tests/QtWidgets/bug_862.py b/sources/pyside6/tests/QtWidgets/bug_862.py new file mode 100644 index 000000000..49d9e24b2 --- /dev/null +++ b/sources/pyside6/tests/QtWidgets/bug_862.py @@ -0,0 +1,78 @@ +# 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 for bug 862, original description was: +# +# print seems to be broken at least for QGraphicsItems-derived objects. The +# attached code shows: +# +# <__main__.MyQObject object at 0xf99f38> +# <__main__.MyQWidget object at 0xf99f38> +# <PySide.QtGui.MyQGraphicsObject (this = 0x11c0d60 , parent = 0x0 , pos = +# QPointF(0, 0) , z = 0 , flags = ( ) ) at 0xf99f38> +# <PySide.QtGui.QGraphicsItem (this = 0x11c2e60 , parent = 0x0 , pos = QPointF(0, +# 0) , z = 0 , flags = ( ) ) at 0xf99f38> +# +# Where it should be showing something like: +# +# <__main__.MyQObject object at 0x7f55cf226c20> +# <__main__.MyQWidget object at 0x7f55cf226c20> +# <__main__.MyQGraphicsObject object at 0x7f55cf226c20> +# <__main__.MyQGraphicsItem object at 0x7f55cf226c20> +# + +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 +from PySide6.QtWidgets import QApplication, QGraphicsItem, QGraphicsWidget, QGraphicsObject, QWidget +import PySide6.QtCore + + +class MyQObject(QObject): + def __init__(self): + super().__init__() + + +class MyQWidget(QWidget): + def __init__(self): + super().__init__() + + +class MyQGraphicsObject(QGraphicsObject): + def __init__(self): + super().__init__() + + +class MyQGraphicsItem(QGraphicsItem): + def __init__(self): + super().__init__() + + +class TestRepr (unittest.TestCase): + + def testIt(self): + + app = QApplication([]) + + self.assertEqual("<__main__.MyQObject(0x", repr(MyQObject())[:22]) + self.assertEqual("<__main__.MyQWidget(0x", repr(MyQWidget())[:22]) + self.assertEqual("<__main__.MyQGraphicsObject(0x", repr(MyQGraphicsObject())[:30]) + self.assertEqual("<__main__.MyQGraphicsItem(0x", repr(MyQGraphicsItem())[:28]) + + self.assertEqual("<PySide6.QtCore.QObject(0x", repr(QObject())[:26]) + self.assertEqual("<PySide6.QtCore.QObject(0x", repr(PySide6.QtCore.QObject())[:26]) + self.assertEqual("<PySide6.QtWidgets.QWidget(0x", repr(QWidget())[:29]) + self.assertEqual("<PySide6.QtWidgets.QGraphicsWidget(0x", repr(QGraphicsWidget())[:37]) + + +if __name__ == "__main__": + unittest.main() diff --git a/sources/pyside6/tests/QtWidgets/bug_871.py b/sources/pyside6/tests/QtWidgets/bug_871.py new file mode 100644 index 000000000..4ee9b575a --- /dev/null +++ b/sources/pyside6/tests/QtWidgets/bug_871.py @@ -0,0 +1,53 @@ +# Copyright (C) 2022 The Qt Company Ltd. +# SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0 + +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 helper.usesqapplication import UsesQApplication +from PySide6.QtGui import QValidator, QIntValidator +from PySide6.QtWidgets import QLineEdit + +'''Bug #871 - http://bugs.pyside.org/show_bug.cgi?id=871''' + + +class BlankIntValidator(QIntValidator): + def validate(self, input, pos): + if input == '': + return QValidator.Acceptable, input, pos + else: + return QIntValidator.validate(self, input, pos) + + +class Bug871Test(UsesQApplication): + def testWithoutValidator(self): + edit = QLineEdit() + self.assertEqual(edit.text(), '') + edit.insert('1') + self.assertEqual(edit.text(), '1') + edit.insert('a') + self.assertEqual(edit.text(), '1a') + edit.insert('2') + self.assertEqual(edit.text(), '1a2') + + def testWithIntValidator(self): + edit = QLineEdit() + edit.setValidator(BlankIntValidator(edit)) + self.assertEqual(edit.text(), '') + edit.insert('1') + self.assertEqual(edit.text(), '1') + edit.insert('a') + self.assertEqual(edit.text(), '1') + edit.insert('2') + self.assertEqual(edit.text(), '12') + + +if __name__ == "__main__": + unittest.main() + diff --git a/sources/pyside6/tests/QtWidgets/bug_879.py b/sources/pyside6/tests/QtWidgets/bug_879.py new file mode 100644 index 000000000..31c656543 --- /dev/null +++ b/sources/pyside6/tests/QtWidgets/bug_879.py @@ -0,0 +1,43 @@ +# Copyright (C) 2022 The Qt Company Ltd. +# SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0 + +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 QCoreApplication, QTimer, QEvent, Qt +from PySide6.QtWidgets import QApplication, QSpinBox +from PySide6.QtGui import QKeyEvent + + +class MySpinBox(QSpinBox): + + def validate(self, text, pos): + return QSpinBox.validate(self, text, pos) + + +class TestBug879 (unittest.TestCase): + + def testIt(self): + app = QApplication([]) + self.box = MySpinBox() + self.box.show() + + QTimer.singleShot(0, self.sendKbdEvent) + QTimer.singleShot(100, app.quit) + app.exec() + + self.assertEqual(self.box.text(), '0') + + def sendKbdEvent(self): + ev = QKeyEvent(QEvent.KeyPress, Qt.Key_A, Qt.NoModifier, 'a') + QCoreApplication.sendEvent(self.box, ev) + + +if __name__ == '__main__': + unittest.main() diff --git a/sources/pyside6/tests/QtWidgets/bug_919.py b/sources/pyside6/tests/QtWidgets/bug_919.py new file mode 100644 index 000000000..67387ed26 --- /dev/null +++ b/sources/pyside6/tests/QtWidgets/bug_919.py @@ -0,0 +1,51 @@ +# Copyright (C) 2022 The Qt Company Ltd. +# SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0 + +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 helper.timedqapplication import TimedQApplication +from PySide6.QtCore import Signal, QTimer +from PySide6.QtGui import QPainter +from PySide6.QtWidgets import QPushButton, QStyleOptionButton, QApplication, QStyle + + +class MyWidget(QPushButton): + def __init__(self, parent=None): + QPushButton.__init__(self, parent) + self._painted = False + + def _emitPainted(self): + self.paintReceived.emit() + + def paintEvent(self, e): + p = QPainter(self) + style = QApplication.style() + option = QStyleOptionButton() + style.drawControl(QStyle.CE_PushButton, option, p) + self._painted = True + QTimer.singleShot(0, self._emitPainted) + + paintReceived = Signal() + + +class TestBug919(TimedQApplication): + def setUp(self): + TimedQApplication.setUp(self, 2000) + + def testFontInfo(self): + w = MyWidget() + w.paintReceived.connect(self.app.quit) + w.show() + self.app.exec() + self.assertTrue(w._painted) + + +if __name__ == '__main__': + unittest.main() diff --git a/sources/pyside6/tests/QtWidgets/bug_921.py b/sources/pyside6/tests/QtWidgets/bug_921.py new file mode 100644 index 000000000..dafc1faef --- /dev/null +++ b/sources/pyside6/tests/QtWidgets/bug_921.py @@ -0,0 +1,67 @@ +#!/usr/bin/env python +# Copyright (C) 2022 The Qt Company Ltd. +# SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0 + +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, Signal, Qt +from PySide6.QtWidgets import QMainWindow +from helper.timedqapplication import TimedQApplication + + +class Signaller(QObject): + s1 = Signal() + s2 = Signal() + s3 = Signal() + + +class Window(object): + + def __init__(self, s): + self._window = QMainWindow() + self._window.setAttribute(Qt.WA_DeleteOnClose, True) + self._window.setWindowTitle("Demo!") + + self._s = s + self._s.s1.connect(self._on_signal) + self._s.s2.connect(self._on_signal) + + def show(self): + self._window.show() + + def _on_signal(self): + self._window.setWindowTitle("Signaled!") + + +class TestTimedApp(TimedQApplication): + def testSignals(self): + s = Signaller() + w = Window(s) + w.show() + + def midleFunction(): + def internalFunction(): + pass + s.s3.connect(internalFunction) + + midleFunction() + self.app.exec() + del w + # PYSIDE-535: Need to collect garbage in PyPy to trigger deletion + gc.collect() + + s.s1.emit() + s.s2.emit() + s.s3.emit() + + +if __name__ == '__main__': + unittest.main() diff --git a/sources/pyside6/tests/QtWidgets/bug_941.py b/sources/pyside6/tests/QtWidgets/bug_941.py new file mode 100644 index 000000000..336aa2f58 --- /dev/null +++ b/sources/pyside6/tests/QtWidgets/bug_941.py @@ -0,0 +1,31 @@ +# Copyright (C) 2022 The Qt Company Ltd. +# SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0 + +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 Qt +from PySide6.QtWidgets import QApplication, QHeaderView + + +def foo(a, b): + pass + + +class TestBug941 (unittest.TestCase): + + def testIt(self): + app = QApplication([]) + view = QHeaderView(Qt.Horizontal) + self.assertTrue(view.sortIndicatorChanged.connect(foo)) + view.sortIndicatorChanged.emit(0, Qt.Vertical) # this can't raise an exception! + + +if __name__ == '__main__': + unittest.main() diff --git a/sources/pyside6/tests/QtWidgets/bug_964.py b/sources/pyside6/tests/QtWidgets/bug_964.py new file mode 100644 index 000000000..86bbddf16 --- /dev/null +++ b/sources/pyside6/tests/QtWidgets/bug_964.py @@ -0,0 +1,31 @@ +# Copyright (C) 2022 The Qt Company Ltd. +# SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0 + +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 QStringListModel, Qt +from PySide6.QtWidgets import QAbstractItemView, QApplication, QListView + + +class TestBug964 (unittest.TestCase): + + def testIt(self): + app = QApplication([]) + model = QStringListModel(["1", "2"]) + view = QListView() + view.setModel(model) + view.setCurrentIndex(model.index(0, 0)) + newCursor = view.moveCursor(QAbstractItemView.MoveDown, Qt.NoModifier) + self.assertEqual(newCursor.row(), 1) + self.assertEqual(newCursor.column(), 0) + + +if __name__ == "__main__": + unittest.main() diff --git a/sources/pyside6/tests/QtWidgets/bug_967.py b/sources/pyside6/tests/QtWidgets/bug_967.py new file mode 100644 index 000000000..03af030ca --- /dev/null +++ b/sources/pyside6/tests/QtWidgets/bug_967.py @@ -0,0 +1,31 @@ +# Copyright (C) 2022 The Qt Company Ltd. +# SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0 + +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.QtWidgets import QApplication, QComboBox + + +class TestBug967 (unittest.TestCase): + + def callback(self, arg): + self.arg = arg + + def testIt(self): + self.arg = None + app = QApplication([]) + obj = QComboBox() + obj.currentIndexChanged.connect(self.callback) + obj.currentIndexChanged.emit(5) + self.assertEqual(self.arg, 5) + + +if __name__ == "__main__": + unittest.main() diff --git a/sources/pyside6/tests/QtWidgets/bug_972.py b/sources/pyside6/tests/QtWidgets/bug_972.py new file mode 100644 index 000000000..895cea128 --- /dev/null +++ b/sources/pyside6/tests/QtWidgets/bug_972.py @@ -0,0 +1,52 @@ +# Copyright (C) 2022 The Qt Company Ltd. +# SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0 + +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 QSizeF +from PySide6.QtWidgets import QGraphicsProxyWidget, QSizePolicy, QPushButton, QGraphicsScene, QGraphicsView + +from helper.timedqapplication import TimedQApplication + + +def createItem(minimum, preferred, maximum, name): + w = QGraphicsProxyWidget() + + w.setWidget(QPushButton(name)) + w.setMinimumSize(minimum) + w.setPreferredSize(preferred) + w.setMaximumSize(maximum) + w.setSizePolicy(QSizePolicy.Preferred, QSizePolicy.Preferred) + + return w + + +class TestBug972 (TimedQApplication): + + # Test if the function QGraphicsProxyWidget.setWidget have the correct behavior + def testIt(self): + scene = QGraphicsScene() + + minSize = QSizeF(30, 100) + prefSize = QSizeF(210, 100) + maxSize = QSizeF(300, 100) + + a = createItem(minSize, prefSize, maxSize, "A") + b = createItem(minSize, prefSize, maxSize, "B") + c = createItem(minSize, prefSize, maxSize, "C") + d = createItem(minSize, prefSize, maxSize, "D") + + view = QGraphicsView(scene) + view.show() + self.app.exec() + + +if __name__ == "__main__": + unittest.main() diff --git a/sources/pyside6/tests/QtWidgets/bug_979.py b/sources/pyside6/tests/QtWidgets/bug_979.py new file mode 100644 index 000000000..a6c17385e --- /dev/null +++ b/sources/pyside6/tests/QtWidgets/bug_979.py @@ -0,0 +1,21 @@ +# Copyright (C) 2022 The Qt Company Ltd. +# SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0 + +import os +import sys + +from pathlib import Path +sys.path.append(os.fspath(Path(__file__).resolve().parents[1])) +from init_paths import init_test_paths +init_test_paths() + +from PySide6.QtWidgets import QDialog +from import_test import PysideImportTest2 + + +class PysideImportTest1(QDialog, PysideImportTest2): + pass + + +if __name__ == '__main__': + quit() diff --git a/sources/pyside6/tests/QtWidgets/bug_988.py b/sources/pyside6/tests/QtWidgets/bug_988.py new file mode 100644 index 000000000..f82ba6d27 --- /dev/null +++ b/sources/pyside6/tests/QtWidgets/bug_988.py @@ -0,0 +1,31 @@ +# Copyright (C) 2022 The Qt Company Ltd. +# SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0 + +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.QtWidgets import QApplication, QTabWidget + + +class TestBug988 (unittest.TestCase): + + def callback(self, arg): + self.arg = arg + + def testIt(self): + self.arg = None + app = QApplication([]) + obj = QTabWidget() + obj.currentChanged.connect(self.callback) + obj.currentChanged.emit(5) + self.assertEqual(self.arg, 5) + + +if __name__ == "__main__": + unittest.main() diff --git a/sources/pyside6/tests/QtWidgets/bug_998.py b/sources/pyside6/tests/QtWidgets/bug_998.py new file mode 100644 index 000000000..0f6311515 --- /dev/null +++ b/sources/pyside6/tests/QtWidgets/bug_998.py @@ -0,0 +1,23 @@ +# Copyright (C) 2022 The Qt Company Ltd. +# SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0 + +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.QtWidgets import QApplication + + +class TestBug998 (unittest.TestCase): + def testNoFocusWindow(self): + widget = QApplication.focusWidget() + self.assertTrue(widget == None) + + +if __name__ == '__main__': + unittest.main() diff --git a/sources/pyside6/tests/QtWidgets/customproxywidget_test.py b/sources/pyside6/tests/QtWidgets/customproxywidget_test.py new file mode 100644 index 000000000..f7a1a1b1d --- /dev/null +++ b/sources/pyside6/tests/QtWidgets/customproxywidget_test.py @@ -0,0 +1,47 @@ +# Copyright (C) 2022 The Qt Company Ltd. +# SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0 + +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 helper.usesqapplication import UsesQApplication +from PySide6.QtCore import Qt, QTimer +from PySide6.QtGui import QPainter +from PySide6.QtWidgets import QLabel +from PySide6.QtWidgets import QGraphicsScene, QGraphicsView, QGraphicsItem, QGraphicsProxyWidget + + +class CustomProxy(QGraphicsProxyWidget): + def __init__(self, parent=None, wFlags=0): + QGraphicsProxyWidget.__init__(self, parent, wFlags) + + +class CustomProxyWidgetTest(UsesQApplication): + def testCustomProxyWidget(self): + scene = QGraphicsScene() + + proxy = CustomProxy(None, Qt.Window) + widget = QLabel('Widget') + proxy.setWidget(widget) + proxy.setCacheMode(QGraphicsItem.DeviceCoordinateCache) + scene.addItem(proxy) + scene.setSceneRect(scene.itemsBoundingRect()) + + view = QGraphicsView(scene) + view.setRenderHints(QPainter.Antialiasing | QPainter.SmoothPixmapTransform) + view.setViewportUpdateMode(QGraphicsView.BoundingRectViewportUpdate) + view.show() + + timer = QTimer.singleShot(100, self.app.quit) + self.app.exec() + + +if __name__ == '__main__': + unittest.main() + diff --git a/sources/pyside6/tests/QtWidgets/grandparent_method_test.py b/sources/pyside6/tests/QtWidgets/grandparent_method_test.py new file mode 100644 index 000000000..ef848e22d --- /dev/null +++ b/sources/pyside6/tests/QtWidgets/grandparent_method_test.py @@ -0,0 +1,35 @@ +# Copyright (C) 2022 The Qt Company Ltd. +# SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0 + +'''Tests for calling methods further than the direct parent''' + +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.QtWidgets import QPushButton, QWidget + +from helper.usesqapplication import UsesQApplication + + +class Dummy(QPushButton): + + def show(self): + QWidget.show(self) + self.called = True + + +class GrandParentMethod(UsesQApplication): + def testMethod(self): + obj = Dummy() + obj.show() + self.assertTrue(obj.called) + + +if __name__ == '__main__': + unittest.main() diff --git a/sources/pyside6/tests/QtWidgets/hashabletype_test.py b/sources/pyside6/tests/QtWidgets/hashabletype_test.py new file mode 100644 index 000000000..f12cceb5a --- /dev/null +++ b/sources/pyside6/tests/QtWidgets/hashabletype_test.py @@ -0,0 +1,30 @@ +# 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 __hash__''' + +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.QtWidgets import QTreeWidgetItem +from helper.usesqapplication import UsesQApplication + + +class HashableTest(UsesQApplication): + + def testQTreeWidgetItemHash(self): + h = {} + obj = QTreeWidgetItem() + h[obj] = 2 + self.assertTrue(h.get(obj), 2) + + +if __name__ == '__main__': + unittest.main() + diff --git a/sources/pyside6/tests/QtWidgets/import_test.py b/sources/pyside6/tests/QtWidgets/import_test.py new file mode 100644 index 000000000..0b60241f0 --- /dev/null +++ b/sources/pyside6/tests/QtWidgets/import_test.py @@ -0,0 +1,2 @@ +class PysideImportTest2(object): + pass diff --git a/sources/pyside6/tests/QtWidgets/keep_reference_test.py b/sources/pyside6/tests/QtWidgets/keep_reference_test.py new file mode 100644 index 000000000..9d21c4580 --- /dev/null +++ b/sources/pyside6/tests/QtWidgets/keep_reference_test.py @@ -0,0 +1,91 @@ +#!/usr/bin/env python +# Copyright (C) 2022 The Qt Company Ltd. +# SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0 + +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 helper.usesqapplication import UsesQApplication +from PySide6.QtCore import QAbstractTableModel +from PySide6.QtWidgets import QTableView + + +class TestModel(QAbstractTableModel): + def __init__(self, parent=None): + QAbstractTableModel.__init__(self, parent) + + def rowCount(self, parent): + return 0 + + def columnCount(self, parent): + return 0 + + def data(self, index, role): + return None + + +class KeepReferenceTest(UsesQApplication): + + def testModelWithoutParent(self): + view = QTableView() + model = TestModel() + view.setModel(model) + samemodel = view.model() + self.assertEqual(model, samemodel) + + def testModelWithParent(self): + view = QTableView() + model = TestModel(None) + view.setModel(model) + samemodel = view.model() + self.assertEqual(model, samemodel) + + @unittest.skipUnless(hasattr(sys, "getrefcount"), f"{sys.implementation.name} has no refcount") + def testReferenceCounting(self): + '''Tests reference count of model object referred by view objects.''' + model1 = TestModel() + refcount1 = sys.getrefcount(model1) + view1 = QTableView() + view1.setModel(model1) + self.assertEqual(sys.getrefcount(view1.model()), refcount1 + 1) + + view2 = QTableView() + view2.setModel(model1) + self.assertEqual(sys.getrefcount(view2.model()), refcount1 + 2) + + model2 = TestModel() + view2.setModel(model2) + self.assertEqual(sys.getrefcount(view1.model()), refcount1 + 1) + + @unittest.skipUnless(hasattr(sys, "getrefcount"), f"{sys.implementation.name} has no refcount") + def testReferenceCountingWhenDeletingReferrer(self): + '''Tests reference count of model object referred by deceased view object.''' + model = TestModel() + refcount1 = sys.getrefcount(model) + view = QTableView() + view.setModel(model) + self.assertEqual(sys.getrefcount(view.model()), refcount1 + 1) + + del view + self.assertEqual(sys.getrefcount(model), refcount1) + + def testReferreedObjectSurvivalAfterContextEnd(self): + '''Model object assigned to a view object must survive after getting out of context.''' + def createModelAndSetToView(view): + model = TestModel() + model.setObjectName('created model') + view.setModel(model) + view = QTableView() + createModelAndSetToView(view) + model = view.model() + + +if __name__ == '__main__': + unittest.main() + diff --git a/sources/pyside6/tests/QtWidgets/missing_symbols_test.py b/sources/pyside6/tests/QtWidgets/missing_symbols_test.py new file mode 100644 index 000000000..076c9e7e1 --- /dev/null +++ b/sources/pyside6/tests/QtWidgets/missing_symbols_test.py @@ -0,0 +1,43 @@ +# Copyright (C) 2022 The Qt Company Ltd. +# SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0 + +'''(Very) Simple test case for missing names from QtGui and QtWidgets''' + +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 import QtGui +from PySide6 import QtWidgets + + +class MissingClasses(unittest.TestCase): + def testQDrag(self): # Bug 222 + getattr(QtGui, 'QDrag') + + def testQDropEvent(self): # Bug 255 + getattr(QtGui, 'QDropEvent') + + +class MissingMembers(unittest.TestCase): + + def testQFontMetricsSize(self): # Bug 223 + QtGui.QFontMetrics.size + + def testQLayoutSetSpacing(self): # Bug 231 + QtWidgets.QLayout.setSpacing + + def testQImageLoad(self): # Bug 257 + QtGui.QImage.load + + def testQStandardItemModelinsertRow(self): # Bug 227 + QtGui.QStandardItemModel.insertRow + + +if __name__ == '__main__': + unittest.main() diff --git a/sources/pyside6/tests/QtWidgets/paint_event_test.py b/sources/pyside6/tests/QtWidgets/paint_event_test.py new file mode 100644 index 000000000..d995c2a37 --- /dev/null +++ b/sources/pyside6/tests/QtWidgets/paint_event_test.py @@ -0,0 +1,68 @@ +# 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 paint event override in python''' + +import gc +import os +import sys +import unittest + +from textwrap import dedent + +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 QTimer +from PySide6.QtWidgets import QApplication, QWidget + +from helper.usesqapplication import UsesQApplication + + +class MyWidget(QWidget): + '''Sample widget''' + + def __init__(self, app): + # Creates a new widget + assert (app) + + super().__init__() + self.app = app + self.paint_event_called = False + + def paintEvent(self, event): + # Empty paint event method + super().paintEvent(event) + self.paint_event_called = True + QTimer.singleShot(20, self.close) + + +class PaintEventOverride(UsesQApplication): + '''Test case for overriding QWidget.paintEvent''' + + qapplication = True + + def setUp(self): + # Acquire resources + super(PaintEventOverride, self).setUp() + self.widget = MyWidget(self.app) + + def tearDown(self): + # Release resources + del self.widget + # PYSIDE-535: Need to collect garbage in PyPy to trigger deletion + gc.collect() + super(PaintEventOverride, self).tearDown() + + def testPaintEvent(self): + # Test QWidget.paintEvent override + self.widget.show() + self.widget.setWindowTitle("paint_event_test") + self.app.exec() + self.assertTrue(self.widget.paint_event_called) + + +if __name__ == '__main__': + unittest.main() diff --git a/sources/pyside6/tests/QtWidgets/parent_method_test.py b/sources/pyside6/tests/QtWidgets/parent_method_test.py new file mode 100644 index 000000000..0ab09eead --- /dev/null +++ b/sources/pyside6/tests/QtWidgets/parent_method_test.py @@ -0,0 +1,38 @@ +# Copyright (C) 2022 The Qt Company Ltd. +# SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0 + +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, QTimer, QThread +from PySide6.QtWidgets import QTableView, QWidget + + +class Foo(QTableView): + def __init__(self, parent=None): + QTableView.__init__(self, parent) + + +from helper.usesqapplication import UsesQApplication + + +class TestParentType(UsesQApplication): + + def testParentType(self): + # Test the problem with calling QObject.parent from a QWidget + # when the parent is a python class derived from a QWidget-derived + # class. The method was returning the last C++ class in the hierarchy + parent = Foo() + w2 = QWidget(parent) + self.assertTrue(isinstance(w2.parentWidget(), Foo)) + self.assertTrue(isinstance(w2.parent(), Foo)) + + +if __name__ == '__main__': + unittest.main() diff --git a/sources/pyside6/tests/QtWidgets/private_mangle_test.py b/sources/pyside6/tests/QtWidgets/private_mangle_test.py new file mode 100644 index 000000000..67ad14d68 --- /dev/null +++ b/sources/pyside6/tests/QtWidgets/private_mangle_test.py @@ -0,0 +1,94 @@ +# Copyright (C) 2022 The Qt Company Ltd. +# SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only + +""" +This is the example from https://bugreports.qt.io/browse/PYSIDE-772 +with no interaction as a unittest. +""" + +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 Signal +from PySide6.QtWidgets import QApplication, QWidget +from PySide6 import QtWidgets + + +class Harness(QWidget): + clicked = Signal() + + def __init__(self): + super().__init__() + self.clicked.connect(self.method) + self.clicked.connect(self._method) + self.clicked.connect(self.__method) + + def method(self): # Public method + self.method_result = self.sender() + + def _method(self): # Private method + self.method__result = self.sender() + + def __method(self): # Name mangled method + self.method___result = self.sender() + + +class _Under(QWidget): + clicked = Signal() + + def __init__(self): + super().__init__() + self.clicked.connect(self.method) + self.clicked.connect(self._method) + self.clicked.connect(self.__method) + + def method(self): # Public method + self.method_result = self.sender() + + def _method(self): # Private method + self.method__result = self.sender() + + def __method(self): # Name mangled method + self.method___result = self.sender() + + +class TestMangle(unittest.TestCase): + + def setUp(self): + QApplication() + + def tearDown(self): + qApp.shutdown() + + def testPrivateMangle(self): + harness = Harness() + harness.clicked.emit() + self.assertEqual(harness.method_result, harness) + self.assertEqual(harness.method__result, harness) + self.assertEqual(harness.method___result, harness) + self.assertTrue("method" in type(harness).__dict__) + self.assertTrue("_method" in type(harness).__dict__) + self.assertFalse("__method" in type(harness).__dict__) + self.assertTrue("_Harness__method" in type(harness).__dict__) + + def testPrivateMangleUnder(self): + harness = _Under() + harness.clicked.emit() + self.assertEqual(harness.method_result, harness) + self.assertEqual(harness.method__result, harness) + self.assertEqual(harness.method___result, harness) + # make sure that we skipped over the underscore in "_Under" + self.assertTrue("method" in type(harness).__dict__) + self.assertTrue("_method" in type(harness).__dict__) + self.assertFalse("__method" in type(harness).__dict__) + self.assertTrue("_Under__method" in type(harness).__dict__) + + +if __name__ == '__main__': + unittest.main() diff --git a/sources/pyside6/tests/QtWidgets/python_properties_test.py b/sources/pyside6/tests/QtWidgets/python_properties_test.py new file mode 100644 index 000000000..ee8a38014 --- /dev/null +++ b/sources/pyside6/tests/QtWidgets/python_properties_test.py @@ -0,0 +1,31 @@ +# Copyright (C) 2022 The Qt Company Ltd. +# SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0 + +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 QLocale +from PySide6.QtWidgets import QGraphicsItem, QStyleOptionViewItem + + +class Properties(unittest.TestCase): + + def testStaticProperty(self): + self.assertEqual(QGraphicsItem.UserType, 65536) + + def testInstanceProperty(self): + p = QStyleOptionViewItem() + self.assertTrue(isinstance(p.locale, QLocale)) + + # PSYIDE-304, can assign to a "const QWidget *" field + p.widget = None + + +if __name__ == '__main__': + unittest.main() diff --git a/sources/pyside6/tests/QtWidgets/qabstracttextdocumentlayout_test.py b/sources/pyside6/tests/QtWidgets/qabstracttextdocumentlayout_test.py new file mode 100644 index 000000000..1ae3b0a35 --- /dev/null +++ b/sources/pyside6/tests/QtWidgets/qabstracttextdocumentlayout_test.py @@ -0,0 +1,59 @@ +# Copyright (C) 2022 The Qt Company Ltd. +# SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0 + +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 QSizeF, QTimer +from PySide6.QtGui import QTextFormat, QTextCharFormat, QPyTextObject +from PySide6.QtWidgets import QTextEdit +from helper.usesqapplication import UsesQApplication + + +class Foo(QPyTextObject): + called = False + + def intrinsicSize(self, doc, posInDocument, format): + Foo.called = True + return QSizeF(10, 10) + + def drawObject(self, painter, rect, doc, posInDocument, format): + pass + + +class QAbstractTextDocumentLayoutTest(UsesQApplication): + + objectType = QTextFormat.UserObject + 1 + + def foo(self): + fmt = QTextCharFormat() + fmt.setObjectType(QAbstractTextDocumentLayoutTest.objectType) + + cursor = self.textEdit.textCursor() + cursor.insertText(chr(0xfffc), fmt) + self.textEdit.setTextCursor(cursor) + self.textEdit.close() + + def testIt(self): + + self.textEdit = QTextEdit() + self.textEdit.show() + + interface = Foo() + self.textEdit.document().documentLayout().registerHandler(QAbstractTextDocumentLayoutTest.objectType, interface) + + QTimer.singleShot(0, self.foo) + self.app.exec() + + self.assertTrue(Foo.called) + + +if __name__ == "__main__": + unittest.main() + diff --git a/sources/pyside6/tests/QtWidgets/qaccessible_test.py b/sources/pyside6/tests/QtWidgets/qaccessible_test.py new file mode 100644 index 000000000..021cf9c6b --- /dev/null +++ b/sources/pyside6/tests/QtWidgets/qaccessible_test.py @@ -0,0 +1,138 @@ +# 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 QAccessible::installFactory().''' + +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 QCoreApplication, Qt +from PySide6.QtGui import QAccessible, QAccessibleInterface, QColor +from PySide6.QtWidgets import QWidget, QLineEdit, QVBoxLayout + +from helper.usesqapplication import UsesQApplication + + +class LineEditAccessible(QAccessibleInterface): + """Mimick a QAccessibleInterface implementation for QLineEdit.""" + + instance_count = 0 + + def __init__(self, widget): + super().__init__() + LineEditAccessible.instance_count += 1 + self._widget = widget + self._name = self._widget.objectName() + print('LineEditAccessible', self._name) + + def __del__(self): + LineEditAccessible.instance_count -= 1 + print('~LineEditAccessible', self._name) + + def actionInterface(self): + return None + + def backgroundColor(self): + return QColor(Qt.white) + + def child(self, index): + return None + + def childAt(self, x, y): + return None + + def childCount(self): + return 0 + + def focusChild(self): + return None + + def foregroundColor(self): + return QColor(Qt.black) + + def indexOfChild(self, child): + return -1 + + def isValid(self): + return True + + def object(self): + return self._widget + + def parent(self): + return None + + def rect(self): + return self._widget.geometry() + + def role(self): + return QAccessible.EditableText + + def setText(self, t, text): + pass + + def state(self): + return QAccessible.State() + + def tableCellInterface(self): + return None + + def tableInterface(self): + return None + + def text(self, t): + return self._widget.text() if t == QAccessible.Value else '' + + def textInterface(self): + return None + + def valueInterface(self): + return None + + def window(self): + return self._widget.window().windowHandle() + + +def accessible_factory(key, obj): + """Factory function for QAccessibleInterface for QLineEdit's.""" + if obj.metaObject().className() == 'QLineEdit': + return LineEditAccessible(obj) + return None + + +class Window(QWidget): + """Test window with 2 QLineEdit's.""" + def __init__(self): + super().__init__() + self.setObjectName('top') + layout = QVBoxLayout(self) + self.m_line_edit1 = QLineEdit("bla") + layout.addWidget(self.m_line_edit1) + self.m_line_edit2 = QLineEdit("bla") + layout.addWidget(self.m_line_edit2) + + +class QAccessibleTest(UsesQApplication): + """Test that LineEditAccessible instances are created for QLineEdit's.""" + + def setUp(self): + super().setUp() + QAccessible.installFactory(accessible_factory) + window = Window() + + def testLineEdits(self): + window = Window() + window.show() + while not window.windowHandle().isExposed(): + QCoreApplication.processEvents() + self.assertEqual(LineEditAccessible.instance_count, 2) + + +if __name__ == "__main__": + unittest.main() diff --git a/sources/pyside6/tests/QtWidgets/qaction_test.py b/sources/pyside6/tests/QtWidgets/qaction_test.py new file mode 100644 index 000000000..a0049421f --- /dev/null +++ b/sources/pyside6/tests/QtWidgets/qaction_test.py @@ -0,0 +1,65 @@ +# Copyright (C) 2022 The Qt Company Ltd. +# SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0 + +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.QtGui import QAction +from PySide6.QtWidgets import QWidget, QMenu +from helper.usesqapplication import UsesQApplication + + +class QPainterDrawText(UsesQApplication): + + def _cb(self): + self._called = True + + def testSignal(self): + o = QWidget() + act = QAction(o) + self._called = False + act.triggered.connect(self._cb) + act.trigger() + self.assertTrue(self._called) + + def testNewCtor(self): + o = QWidget() + self._called = False + myAction = QAction("&Quit", o, triggered=self._cb) + myAction.trigger() + self.assertTrue(self._called) + + +class SetShortcutTest(UsesQApplication): + + def testSetShortcut(self): + # Somehow an exception was leaking from the constructor + # and appearing in setShortcut. + o = QWidget() + action = QAction('aaaa', o) + shortcut = 'Ctrl+N' + action.setShortcut(shortcut) + s2 = action.shortcut() + self.assertEqual(s2, shortcut) + + def testMenu(self): + # Test the setMenu()/menu() old functionality removed in Qt6 + # that was added via helper functions. + menu = QMenu("menu") + action = QAction("action") + + # Using QAction::setMenu(QObject*) + action.setMenu(menu) + + self.assertEqual(action.menu(), menu) + + +if __name__ == '__main__': + unittest.main() + diff --git a/sources/pyside6/tests/QtWidgets/qapp_issue_585.py b/sources/pyside6/tests/QtWidgets/qapp_issue_585.py new file mode 100644 index 000000000..0b5453af5 --- /dev/null +++ b/sources/pyside6/tests/QtWidgets/qapp_issue_585.py @@ -0,0 +1,53 @@ +# Copyright (C) 2022 The Qt Company Ltd. +# SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0 + +""" +The bug was caused by this commit: +"Support the qApp macro correctly, final version incl. debug" +e30e0c161b2b4d50484314bf006e9e5e8ff6b380 +2017-10-27 + +The bug was first solved by this commit: +"Fix qApp macro refcount" +b811c874dedd14fd8b072bc73761d39255216073 +2018-03-21 + +This test triggers the refcounting bug of qApp, issue PYSIDE-585. +Finally, the real patch included more changes, because another error +was in the ordering of shutdown calls. It was found using the following +Python configuration: + + In Python 3.6 create a directory 'debug' and cd into it. + + ../configure --with-pydebug --prefix=$HOME/pydebug/ --enable-shared + +Then a lot more refcounting errors show up, which are due to a bug in +the code position of the shutdown procedure. +The reason for the initial refcount bug was that the shutdown code is once +more often called than the creation of the qApp wrapper. +Finally, it was easiest and more intuitive to simply make the refcount of +qApp_content equal to that of Py_None, which is also not supposed to be +garbage-collected. + +For some reason, the test does not work as a unittest because it creates +no crash. We leave it this way. +""" + +import os +import sys + +from pathlib import Path +sys.path.append(os.fspath(Path(__file__).resolve().parents[1])) +sys.path.append(os.fspath(Path(__file__).resolve().parents[1] / "util")) +from init_paths import init_test_paths +init_test_paths() + +from PySide6.QtCore import QTimer +from PySide6.QtWidgets import QApplication + + +app_instance = QApplication([]) +# If the following line is commented, application doesn't crash on exit anymore. +app_instance2 = app_instance +QTimer.singleShot(0, qApp.quit) +app_instance.exec_() diff --git a/sources/pyside6/tests/QtWidgets/qapp_test.py b/sources/pyside6/tests/QtWidgets/qapp_test.py new file mode 100644 index 000000000..5a66b8e33 --- /dev/null +++ b/sources/pyside6/tests/QtWidgets/qapp_test.py @@ -0,0 +1,31 @@ +# 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 the presence of qApp Macro''' + +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.QtWidgets import QApplication + + +class QAppPresence(unittest.TestCase): + + def testQApp(self): + # QtGui.qApp variable is instance of QApplication + self.assertTrue(isinstance(qApp, QApplication)) + + +def main(): + app = QApplication([]) + unittest.main() + + +if __name__ == '__main__': + main() diff --git a/sources/pyside6/tests/QtWidgets/qapplication_exit_segfault_test.py b/sources/pyside6/tests/QtWidgets/qapplication_exit_segfault_test.py new file mode 100644 index 000000000..8bb47bc1c --- /dev/null +++ b/sources/pyside6/tests/QtWidgets/qapplication_exit_segfault_test.py @@ -0,0 +1,30 @@ +# Copyright (C) 2022 The Qt Company Ltd. +# SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0 + +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.QtWidgets import QApplication, QPushButton, QWidget, QSpinBox + + +class QApplicationDelete(unittest.TestCase): + '''Test for segfault when deleting a QApplication before a QWidget''' + + def testQPushButton(self): + # QApplication deleted before QPushButton + a = QApplication([]) + b = QPushButton('aaaa') + del a + # PYSIDE-535: Need to collect garbage in PyPy to trigger deletion + gc.collect() + + +if __name__ == '__main__': + unittest.main() diff --git a/sources/pyside6/tests/QtWidgets/qapplication_test.py b/sources/pyside6/tests/QtWidgets/qapplication_test.py new file mode 100644 index 000000000..7c5b61fd9 --- /dev/null +++ b/sources/pyside6/tests/QtWidgets/qapplication_test.py @@ -0,0 +1,23 @@ +# Copyright (C) 2022 The Qt Company Ltd. +# SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0 + +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.QtWidgets import QApplication + + +class TestQApplication(unittest.TestCase): + def testNoArguments(self): + app = QApplication() + self.assertIsInstance(app, QApplication) + + +if __name__ == '__main__': + unittest.main() diff --git a/sources/pyside6/tests/QtWidgets/qcolormap_test.py b/sources/pyside6/tests/QtWidgets/qcolormap_test.py new file mode 100644 index 000000000..f63a9486f --- /dev/null +++ b/sources/pyside6/tests/QtWidgets/qcolormap_test.py @@ -0,0 +1,25 @@ +# Copyright (C) 2022 The Qt Company Ltd. +# SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0 + +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.QtWidgets import QColormap +from helper.usesqapplication import UsesQApplication + + +class QColormapTest(UsesQApplication): + + def testQColormap(self): + qc = QColormap.instance() + self.assertEqual(qc.size(), -1) + + +if __name__ == '__main__': + unittest.main() diff --git a/sources/pyside6/tests/QtWidgets/qdialog_test.py b/sources/pyside6/tests/QtWidgets/qdialog_test.py new file mode 100644 index 000000000..cb85ce7e2 --- /dev/null +++ b/sources/pyside6/tests/QtWidgets/qdialog_test.py @@ -0,0 +1,52 @@ +# Copyright (C) 2022 The Qt Company Ltd. +# SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0 + +import os +import sys +import unittest +import weakref + +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 Slot, QTimer +from PySide6.QtWidgets import QDialog, QMainWindow +from helper.timedqapplication import TimedQApplication + + +class Window(QMainWindow): + def __init__(self): + super().__init__() + self.setWindowTitle("Main") + self.dialog = None + + @Slot() + def execDialog(self): + dialog = QDialog(self) + self.dialog = weakref.ref(dialog) + dialog.setWindowTitle("Dialog") + dialog.setMinimumWidth(200) + QTimer.singleShot(500, dialog.reject) + dialog.exec() + self.close() + + +class DialogExecTest(TimedQApplication): + """Test whether the parent-child relationship (dialog/main window) is removed when + using QDialog.exec() (instead show()), preventing the dialog from leaking.""" + + def setUp(self): + super().setUp(10000) + self._window = Window() + + def testExec(self): + self._window.show() + QTimer.singleShot(500, self._window.execDialog) + self.app.exec() + self.assertTrue(self._window.dialog() is None) + + +if __name__ == '__main__': + unittest.main() diff --git a/sources/pyside6/tests/QtWidgets/qdynamic_signal.py b/sources/pyside6/tests/QtWidgets/qdynamic_signal.py new file mode 100644 index 000000000..83d6af383 --- /dev/null +++ b/sources/pyside6/tests/QtWidgets/qdynamic_signal.py @@ -0,0 +1,41 @@ +# Copyright (C) 2022 The Qt Company Ltd. +# SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0 + +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 +from PySide6.QtWidgets import QInputDialog + +from helper.usesqapplication import UsesQApplication + + +class DynamicSignalTest(UsesQApplication): + + def cb(self, obj): + self._called = True + + def testQDialog(self): + dlg = QInputDialog() + dlg.setInputMode(QInputDialog.TextInput) + lst = dlg.children() + self.assertTrue(len(lst)) + obj = lst[0] + self._called = False + obj.destroyed[QObject].connect(self.cb) + obj = None + del dlg + # PYSIDE-535: Need to collect garbage in PyPy to trigger deletion + gc.collect() + self.assertTrue(self._called) + + +if __name__ == '__main__': + unittest.main() diff --git a/sources/pyside6/tests/QtWidgets/qfontdialog_test.py b/sources/pyside6/tests/QtWidgets/qfontdialog_test.py new file mode 100644 index 000000000..764329732 --- /dev/null +++ b/sources/pyside6/tests/QtWidgets/qfontdialog_test.py @@ -0,0 +1,31 @@ +# Copyright (C) 2022 The Qt Company Ltd. +# SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0 + +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.QtGui import QFont +from PySide6.QtWidgets import QFontDialog +from helper.timedqapplication import TimedQApplication + + +class TestFontDialog(TimedQApplication): + + def testGetFont(self): + QFontDialog.getFont() + + def testGetFontQDialog(self): + QFontDialog.getFont(QFont("FreeSans", 10)) + + def testGetFontQDialogQString(self): + QFontDialog.getFont(QFont("FreeSans", 10), None, "Select font") + + +if __name__ == '__main__': + unittest.main() diff --git a/sources/pyside6/tests/QtWidgets/qformlayout_test.py b/sources/pyside6/tests/QtWidgets/qformlayout_test.py new file mode 100644 index 000000000..f87ea6935 --- /dev/null +++ b/sources/pyside6/tests/QtWidgets/qformlayout_test.py @@ -0,0 +1,99 @@ +# Copyright (C) 2022 The Qt Company Ltd. +# SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0 + +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.QtWidgets import QFormLayout, QWidget, QLabel, QMainWindow + +from helper.usesqapplication import UsesQApplication + + +class QFormLayoutTest(UsesQApplication): + + def testGetItemPosition(self): + formlayout = QFormLayout() + + row, role = formlayout.getItemPosition(0) + self.assertTrue(isinstance(row, int)) + self.assertTrue(isinstance(role, QFormLayout.ItemRole)) + self.assertEqual(row, -1) + + widget = QWidget() + formlayout.addRow(widget) + row, role = formlayout.getItemPosition(0) + self.assertTrue(isinstance(row, int)) + self.assertTrue(isinstance(role, QFormLayout.ItemRole)) + self.assertEqual(row, 0) + self.assertEqual(role, QFormLayout.SpanningRole) + + def testGetWidgetPosition(self): + formlayout = QFormLayout() + widget = QWidget() + + row, role = formlayout.getWidgetPosition(widget) + self.assertTrue(isinstance(row, int)) + self.assertTrue(isinstance(role, QFormLayout.ItemRole)) + self.assertEqual(row, -1) + + formlayout.addRow(widget) + row, role = formlayout.getWidgetPosition(widget) + self.assertTrue(isinstance(row, int)) + self.assertTrue(isinstance(role, QFormLayout.ItemRole)) + self.assertEqual(row, 0) + self.assertEqual(role, QFormLayout.SpanningRole) + + def testGetLayoutPosition(self): + formlayout = QFormLayout() + layout = QFormLayout() + + row, role = formlayout.getLayoutPosition(layout) + self.assertTrue(isinstance(row, int)) + self.assertTrue(isinstance(role, QFormLayout.ItemRole)) + self.assertEqual(row, -1) + + formlayout.addRow(layout) + row, role = formlayout.getLayoutPosition(layout) + self.assertTrue(isinstance(row, int)) + self.assertTrue(isinstance(role, QFormLayout.ItemRole)) + self.assertEqual(row, 0) + self.assertEqual(role, QFormLayout.SpanningRole) + + def testTakeRow(self): + window = QMainWindow() + window.setCentralWidget(QWidget()) + formlayout = QFormLayout(window.centralWidget()) + + widget_label = "blub" + widget = QLabel(widget_label) + + self.assertEqual(formlayout.count(), 0) + formlayout.addRow(widget) + self.assertEqual(formlayout.count(), 1) + self.assertEqual(formlayout.itemAt(0).widget(), widget) + + widget_id = id(widget) + + # Now there are no more references to the original widget on the + # Python side. Assert that this does not break the references to + # the widget on the C++ side so that "taking" the row will work. + del widget + + takeRowResult = formlayout.takeRow(0) + self.assertEqual(formlayout.count(), 0) + + widget = takeRowResult.fieldItem.widget() + + self.assertIsNotNone(widget) + self.assertEqual(widget_id, id(widget)) + self.assertEqual(widget.text(), widget_label) + + +if __name__ == "__main__": + unittest.main() diff --git a/sources/pyside6/tests/QtWidgets/qgraphicsitem_isblocked_test.py b/sources/pyside6/tests/QtWidgets/qgraphicsitem_isblocked_test.py new file mode 100644 index 000000000..cb4115b55 --- /dev/null +++ b/sources/pyside6/tests/QtWidgets/qgraphicsitem_isblocked_test.py @@ -0,0 +1,41 @@ +#!/usr/bin/python +# Copyright (C) 2022 The Qt Company Ltd. +# SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0 + +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 QRectF +from PySide6.QtWidgets import QGraphicsItem +from PySide6.QtGui import QColor +from helper.usesqapplication import UsesQApplication + + +class Item(QGraphicsItem): + + def __init__(self): + super().__init__() + + def boundingRect(self): + return QRectF(0, 0, 100, 100) + + def paint(self, painter, option, widget): + painter.setBrush(QColor(255, 255, 255)) + painter.drawRect(0, 0, 100, 100) + + +class QGraphicsViewIsBlockedTest(UsesQApplication): + + def testIsBlockedByModalPanel(self): + (first, second) = Item().isBlockedByModalPanel() + self.assertFalse(first) + + +if __name__ == "__main__": + unittest.main() diff --git a/sources/pyside6/tests/QtWidgets/qgraphicsitem_test.py b/sources/pyside6/tests/QtWidgets/qgraphicsitem_test.py new file mode 100644 index 000000000..1114ad4fe --- /dev/null +++ b/sources/pyside6/tests/QtWidgets/qgraphicsitem_test.py @@ -0,0 +1,50 @@ +# 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 related to QGraphicsItem and subclasses''' + +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.QtGui import QPolygonF, QColor, QBrush +from PySide6.QtWidgets import QGraphicsScene + +from helper.usesqapplication import UsesQApplication + + +class QColorOnSetBrush(UsesQApplication): + '''Test case for passing a QColor directly to setBrush''' + + def setUp(self): + # Acquire resources + super(QColorOnSetBrush, self).setUp() + + self.scene = QGraphicsScene() + poly = QPolygonF() + self.item = self.scene.addPolygon(poly) + self.color = QColor('black') + + def tearDown(self): + # Release resources + del self.color + del self.item + del self.scene + # PYSIDE-535: Need to collect garbage in PyPy to trigger deletion + gc.collect() + super(QColorOnSetBrush, self).tearDown() + + def testQColor(self): + # QGraphicsAbstractShapeItem.setBrush(QColor) + self.item.setBrush(self.color) + self.assertEqual(QBrush(self.color), self.item.brush()) + + +if __name__ == '__main__': + unittest.main() diff --git a/sources/pyside6/tests/QtWidgets/qgraphicsobjectreimpl_test.py b/sources/pyside6/tests/QtWidgets/qgraphicsobjectreimpl_test.py new file mode 100644 index 000000000..a3d28b4d3 --- /dev/null +++ b/sources/pyside6/tests/QtWidgets/qgraphicsobjectreimpl_test.py @@ -0,0 +1,62 @@ +# 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 related to QGraphicsItem and subclasses''' + +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.QtWidgets import QGraphicsObject, QGraphicsWidget +from PySide6.QtCore import QRectF + +from helper.usesqapplication import UsesQApplication + + +class GObjA(QGraphicsObject): + def paint(self, *args): + pass + + def boundingRect(self): + return QRectF() + + def itemChange(self, *args): + return QGraphicsObject.itemChange(self, *args) + + +class GObjB(QGraphicsObject): + def paint(self, *args): + pass + + def boundingRect(self): + return QRectF() + + +class QGraphicsObjectReimpl(UsesQApplication): + '''Test case for reimplementing QGraphicsObject''' + + def testReimplementationTypes(self): + w = QGraphicsWidget() + + # PYSIDE-86: + # This case failed because GObjA was reimplementing + # the method itemChange() from QGraphicsItem, + # and then the QVariant was not associated with + # a QGraphicsItem but a QObjectItem because the base + # class was a QObject. + gobjA = GObjA() + gobjA.setParentItem(w) + self.assertIs(type(w), type(gobjA.parentItem())) + + gobjB = GObjB() + gobjB.setParentItem(w) + self.assertIs(type(w), type(gobjB.parentItem())) + + +if __name__ == '__main__': + unittest.main() diff --git a/sources/pyside6/tests/QtWidgets/qgraphicsproxywidget_test.py b/sources/pyside6/tests/QtWidgets/qgraphicsproxywidget_test.py new file mode 100644 index 000000000..dee616bbe --- /dev/null +++ b/sources/pyside6/tests/QtWidgets/qgraphicsproxywidget_test.py @@ -0,0 +1,42 @@ +# Copyright (C) 2022 The Qt Company Ltd. +# SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0 + +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 helper.usesqapplication import UsesQApplication +from PySide6.QtCore import Qt, QTimer +from PySide6.QtGui import QPainter +from PySide6.QtWidgets import QLabel +from PySide6.QtWidgets import QGraphicsScene, QGraphicsView, QGraphicsItem, QGraphicsProxyWidget + + +class QGraphicsProxyWidgetTest(UsesQApplication): + def testQGraphicsProxyWidget(self): + scene = QGraphicsScene() + + proxy = QGraphicsProxyWidget(None, Qt.Window) + widget = QLabel('Widget') + proxy.setWidget(widget) + proxy.setCacheMode(QGraphicsItem.DeviceCoordinateCache) + scene.addItem(proxy) + scene.setSceneRect(scene.itemsBoundingRect()) + + view = QGraphicsView(scene) + view.setRenderHints(QPainter.Antialiasing | QPainter.SmoothPixmapTransform) + view.setViewportUpdateMode(QGraphicsView.BoundingRectViewportUpdate) + view.show() + + timer = QTimer.singleShot(100, self.app.quit) + self.app.exec() + + +if __name__ == '__main__': + unittest.main() + diff --git a/sources/pyside6/tests/QtWidgets/qgraphicsscene_test.py b/sources/pyside6/tests/QtWidgets/qgraphicsscene_test.py new file mode 100644 index 000000000..86604f27b --- /dev/null +++ b/sources/pyside6/tests/QtWidgets/qgraphicsscene_test.py @@ -0,0 +1,213 @@ +# Copyright (C) 2022 The Qt Company Ltd. +# SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0 + +'''Basic test cases for QGraphicsScene''' + +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 QPointF +from PySide6.QtGui import QPolygonF, QPixmap, QPainterPath, QTransform, QWindow +from PySide6.QtWidgets import QApplication, QPushButton +from PySide6.QtWidgets import QGraphicsScene +from PySide6.QtWidgets import QGraphicsEllipseItem, QGraphicsLineItem +from PySide6.QtWidgets import QGraphicsPathItem, QGraphicsPixmapItem +from PySide6.QtWidgets import QGraphicsPolygonItem, QGraphicsRectItem +from PySide6.QtWidgets import QGraphicsSimpleTextItem, QGraphicsTextItem +from PySide6.QtWidgets import QGraphicsProxyWidget, QGraphicsView + +from helper.usesqapplication import UsesQApplication + + +class Constructor(unittest.TestCase): + '''QGraphicsScene constructor''' + + def testConstructor(self): + # QGraphicsScene constructor + obj = QGraphicsScene() + self.assertTrue(isinstance(obj, QGraphicsScene)) + +# Test for PYSIDE-868: Test whether painter.device() can be accessed +# correctly. This was crashing when the underlying QPaintDevice was a +# QWidget due to handling multiple inheritance incorrectly. + + +class CustomScene(QGraphicsScene): + def __init__(self, parent=None): + super().__init__(parent) + self.dpi = 0 + + def drawBackground(self, painter, rect): + self.dpi = painter.device().physicalDpiX() + + def drawForeground(self, painter, rect): + self.dpi = painter.device().physicalDpiX() + + +class ConstructorWithRect(unittest.TestCase): + '''QGraphicsScene qrect constructor and related sizes''' + + def setUp(self): + # Acquire resources + # PyQt4 doesn't accept a QRect as argument to constructor + self.scene = QGraphicsScene(0, 200, 150, 175) + + def tearDown(self): + # Release resources + del self.scene + # PYSIDE-535: Need to collect garbage in PyPy to trigger deletion + gc.collect() + + def testHeight(self): + # QGraphicsScene.height() + self.assertEqual(self.scene.height(), 175) + + def testWidth(self): + # QGraphicsScene.width() + self.assertEqual(self.scene.width(), 150) + + +class AddItem(UsesQApplication): + '''Tests for QGraphicsScene.add*''' + + qapplication = True + + def setUp(self): + # Acquire resources + super(AddItem, self).setUp() + self.scene = QGraphicsScene() + # While the scene does not inherits from QWidget, requires + # an application to make the internals work. + + def tearDown(self): + # Release resources + del self.scene + # PYSIDE-535: Need to collect garbage in PyPy to trigger deletion + gc.collect() + super(AddItem, self).tearDown() + + def testEllipse(self): + # QGraphicsScene.addEllipse + item = self.scene.addEllipse(100, 100, 100, 100) + self.assertTrue(isinstance(item, QGraphicsEllipseItem)) + + def testLine(self): + # QGraphicsScene.addLine + item = self.scene.addLine(100, 100, 200, 200) + self.assertTrue(isinstance(item, QGraphicsLineItem)) + + def testPath(self): + # QGraphicsScene.addPath + item = self.scene.addPath(QPainterPath()) + self.assertTrue(isinstance(item, QGraphicsPathItem)) + + def testPixmap(self): + # QGraphicsScene.addPixmap + item = self.scene.addPixmap(QPixmap()) + self.assertTrue(isinstance(item, QGraphicsPixmapItem)) + + def testPolygon(self): + # QGraphicsScene.addPolygon + points = [QPointF(0, 0), QPointF(100, 100), QPointF(0, 100)] + item = self.scene.addPolygon(QPolygonF(points)) + self.assertTrue(isinstance(item, QGraphicsPolygonItem)) + + def testRect(self): + # QGraphicsScene.addRect + item = self.scene.addRect(100, 100, 100, 100) + self.assertTrue(isinstance(item, QGraphicsRectItem)) + + def testSimpleText(self): + # QGraphicsScene.addSimpleText + item = self.scene.addSimpleText('Monty Python 42') + self.assertTrue(isinstance(item, QGraphicsSimpleTextItem)) + + def testText(self): + # QGraphicsScene.addText + item = self.scene.addText('Monty Python 42') + self.assertTrue(isinstance(item, QGraphicsTextItem)) + + def testWidget(self): + # QGraphicsScene.addWidget + # XXX: printing some X11 error when using under PyQt4 + item = self.scene.addWidget(QPushButton()) + self.assertTrue(isinstance(item, QGraphicsProxyWidget)) + + +class ItemRetrieve(UsesQApplication): + '''Tests for QGraphicsScene item retrieval methods''' + + qapplication = True + + def setUp(self): + # Acquire resources + super(ItemRetrieve, self).setUp() + self.scene = QGraphicsScene() + + self.topleft = QGraphicsRectItem(0, 0, 100, 100) + self.topright = QGraphicsRectItem(100, 0, 100, 100) + self.bottomleft = QGraphicsRectItem(0, 100, 100, 100) + self.bottomright = QGraphicsRectItem(100, 100, 100, 100) + + self.items = [self.topleft, self.topright, self.bottomleft, + self.bottomright] + + for item in self.items: + self.scene.addItem(item) + + def tearDown(self): + # Release resources + del self.scene + # PYSIDE-535: Need to collect garbage in PyPy to trigger deletion + gc.collect() + super(ItemRetrieve, self).tearDown() + + def testItems(self): + # QGraphicsScene.items() + items = self.scene.items() + for i in items: + self.assertTrue(i in self.items) + + def testItemAt(self): + # QGraphicsScene.itemAt() + self.assertEqual(self.scene.itemAt(50, 50, QTransform()), self.topleft) + self.assertEqual(self.scene.itemAt(150, 50, QTransform()), self.topright) + self.assertEqual(self.scene.itemAt(50, 150, QTransform()), self.bottomleft) + self.assertEqual(self.scene.itemAt(150, 150, QTransform()), self.bottomright) + + +class TestGraphicsGroup(UsesQApplication): + def testIt(self): + scene = QGraphicsScene() + i1 = QGraphicsRectItem() + scene.addItem(i1) + i2 = QGraphicsRectItem(i1) + i3 = QGraphicsRectItem() + i4 = QGraphicsRectItem() + group = scene.createItemGroup((i2, i3, i4)) + scene.removeItem(i1) + del i1 # this shouldn't delete i2 + # PYSIDE-535: Need to collect garbage in PyPy to trigger deletion + gc.collect() + self.assertEqual(i2.scene(), scene) + scene.destroyItemGroup(group) + self.assertRaises(RuntimeError, group.type) + + def testCustomScene(self): # For PYSIDE-868, see above + scene = CustomScene() + view = QGraphicsView(scene) + view.show() + while scene.dpi == 0: + QApplication.processEvents() + view.hide() + + +if __name__ == '__main__': + unittest.main() diff --git a/sources/pyside6/tests/QtWidgets/qinputdialog_get_test.py b/sources/pyside6/tests/QtWidgets/qinputdialog_get_test.py new file mode 100644 index 000000000..260653ae7 --- /dev/null +++ b/sources/pyside6/tests/QtWidgets/qinputdialog_get_test.py @@ -0,0 +1,47 @@ +# Copyright (C) 2022 The Qt Company Ltd. +# SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0 + +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 QTimer +from PySide6.QtWidgets import QApplication, QInputDialog, QDialog +from helper.usesqapplication import UsesQApplication + + +def close_dialog(): + for w in QApplication.topLevelWidgets(): + if isinstance(w, QDialog): + w.reject() + + +class TestInputDialog(UsesQApplication): + + def testGetDouble(self): + QTimer.singleShot(500, close_dialog) + self.assertEqual(QInputDialog.getDouble(None, "title", "label"), (0.0, False)) + + def testGetInt(self): + QTimer.singleShot(500, close_dialog) + self.assertEqual(QInputDialog.getInt(None, "title", "label"), (0, False)) + + def testGetItem(self): + QTimer.singleShot(500, close_dialog) + (item, bool) = QInputDialog.getItem(None, "title", "label", ["1", "2", "3"]) + self.assertEqual(str(item), "1") + + def testGetText(self): + QTimer.singleShot(500, close_dialog) + (text, bool) = QInputDialog.getText(None, "title", "label") + self.assertEqual(str(text), "") + + +if __name__ == '__main__': + unittest.main() + diff --git a/sources/pyside6/tests/QtWidgets/qkeysequenceedit_test.py b/sources/pyside6/tests/QtWidgets/qkeysequenceedit_test.py new file mode 100644 index 000000000..bcb4c7a61 --- /dev/null +++ b/sources/pyside6/tests/QtWidgets/qkeysequenceedit_test.py @@ -0,0 +1,31 @@ +# 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 QKeySequenceEdit.''' + +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 QTimer +from PySide6.QtWidgets import QKeySequenceEdit + +from helper.usesqapplication import UsesQApplication + + +class QKeySequenceEditTest(UsesQApplication): + def testKeySequence(self): + keySequenceEdit = QKeySequenceEdit() + keySequenceEdit.show() + QTimer.singleShot(0, keySequenceEdit.close) + self.app.exec() + print(keySequenceEdit.keySequence()) + + +if __name__ == "__main__": + unittest.main() diff --git a/sources/pyside6/tests/QtWidgets/qlabel_test.py b/sources/pyside6/tests/QtWidgets/qlabel_test.py new file mode 100644 index 000000000..aba90b7b8 --- /dev/null +++ b/sources/pyside6/tests/QtWidgets/qlabel_test.py @@ -0,0 +1,77 @@ +# 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 QLabel''' + +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(True) + +from PySide6.QtCore import Qt +from PySide6.QtGui import QPixmap +from PySide6.QtWidgets import QLabel +from shiboken6 import Shiboken + +from helper.usesqapplication import UsesQApplication + + +class QLabelTest(UsesQApplication): + '''Test case for calling QLabel.setPixmap''' + + def setUp(self): + super(QLabelTest, self).setUp() + self.label = QLabel() + + def tearDown(self): + del self.label + # PYSIDE-535: Need to collect garbage in PyPy to trigger deletion + gc.collect() + super(QLabelTest, self).tearDown() + + def testSetPixmap(self): + + p1 = QPixmap(5, 5) + p2 = QPixmap(10, 10) + + self.label.setPixmap(p1) + self.assertIsNotNone(self.label.pixmap()) + + # PYSIDE-150: + # When a new QPixmap is assigned to a QLabel, + # the previous one needs to be cleared. + # This means we should not keep a copy of the QPixmap + # on Python-side. + + # Getting pointer to the QPixmap + ret_p = self.label.pixmap() + self.assertIsNot(p1, ret_p) + # Save the address of the pointer + ret_p_addr = Shiboken.getCppPointer(ret_p) + # Remove the QPixmap + del ret_p + # PYSIDE-535: Need to collect garbage in PyPy to trigger deletion + gc.collect() + # Set new QPixmap + self.label.setPixmap(p2) + + # There should be no pointers remaining with the same + # address that our QPixmap p1 because it was deleted + # using `del ret_p` + self.assertTrue(all(Shiboken.getCppPointer(o) != ret_p_addr + for o in Shiboken.getAllValidWrappers())) + + # Test for PYSIDE-1673, QObject.property() returning a QFlags<> property. + def testQObjectProperty(self): + a = self.label.property("alignment") + self.assertEqual(type(a), Qt.Alignment) + print("alignment=", a) + + +if __name__ == '__main__': + unittest.main() diff --git a/sources/pyside6/tests/QtWidgets/qlayout_ref_test.py b/sources/pyside6/tests/QtWidgets/qlayout_ref_test.py new file mode 100644 index 000000000..df9bd7f90 --- /dev/null +++ b/sources/pyside6/tests/QtWidgets/qlayout_ref_test.py @@ -0,0 +1,171 @@ +# 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 QLayout handling of child widgets references''' + +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.QtWidgets import QHBoxLayout, QVBoxLayout, QGridLayout, QWidget +from PySide6.QtWidgets import QStackedLayout, QFormLayout +from PySide6.QtWidgets import QApplication, QPushButton, QLabel + +from helper.usesqapplication import UsesQApplication + + +class SaveReference(UsesQApplication): + '''Test case to check if QLayout-derived classes increment the refcount + of widgets passed to addWidget()''' + + # Adding here as nose can't see the qapplication attrib we inherit + qapplication = True + + def setUp(self): + # Acquire resources + super(SaveReference, self).setUp() + self.widget1 = QPushButton('click me') + self.widget2 = QLabel('aaa') + + def tearDown(self): + # Release resources + del self.widget2 + del self.widget1 + # PYSIDE-535: Need to collect garbage in PyPy to trigger deletion + gc.collect() + super(SaveReference, self).tearDown() + + @unittest.skipUnless(hasattr(sys, "getrefcount"), f"{sys.implementation.name} has no refcount") + def checkLayoutReference(self, layout): + # Checks the reference cound handling of layout.addWidget + self.assertEqual(sys.getrefcount(self.widget1), 2) + layout.addWidget(self.widget1) + self.assertEqual(sys.getrefcount(self.widget1), 3) + + self.assertEqual(sys.getrefcount(self.widget2), 2) + layout.addWidget(self.widget2) + self.assertEqual(sys.getrefcount(self.widget2), 3) + + # Check if doesn't mess around with previous widget refcount + self.assertEqual(sys.getrefcount(self.widget1), 3) + + @unittest.skipUnless(hasattr(sys, "getrefcount"), f"{sys.implementation.name} has no refcount") + def testMoveLayout(self): + l = QHBoxLayout() + self.assertEqual(sys.getrefcount(self.widget1), 2) + l.addWidget(self.widget1) + self.assertEqual(sys.getrefcount(self.widget1), 3) + + w = QWidget() + w.setLayout(l) + self.assertEqual(sys.getrefcount(self.widget1), 3) + + def testHBoxReference(self): + # QHBoxLayout.addWidget reference count + w = QWidget() + self.checkLayoutReference(QHBoxLayout(w)) + + def testVBoxReference(self): + # QVBoxLayout.addWidget reference count + w = QWidget() + self.checkLayoutReference(QVBoxLayout(w)) + + def testGridReference(self): + # QGridLayout.addWidget reference count + w = QWidget() + self.checkLayoutReference(QGridLayout(w)) + + def testFormReference(self): + # QFormLayout.addWidget reference count + w = QWidget() + self.checkLayoutReference(QFormLayout(w)) + + def testStackedReference(self): + # QStackedLayout.addWidget reference count + w = QWidget() + self.checkLayoutReference(QStackedLayout(w)) + + +class MultipleAdd(UsesQApplication): + '''Test case to check if refcount is incremented only once when multiple + calls to addWidget are made with the same widget''' + + qapplication = True + + def setUp(self): + # Acquire resources + super(MultipleAdd, self).setUp() + self.widget = QPushButton('click me') + self.win = QWidget() + self.layout = QHBoxLayout(self.win) + + def tearDown(self): + # Release resources + del self.widget + del self.layout + del self.win + # PYSIDE-535: Need to collect garbage in PyPy to trigger deletion + gc.collect() + super(MultipleAdd, self).tearDown() + + @unittest.skipUnless(hasattr(sys, "getrefcount"), f"{sys.implementation.name} has no refcount") + def testRefCount(self): + # Multiple QLayout.addWidget calls on the same widget + self.assertEqual(sys.getrefcount(self.widget), 2) + self.layout.addWidget(self.widget) + self.assertEqual(sys.getrefcount(self.widget), 3) + self.layout.addWidget(self.widget) + self.assertEqual(sys.getrefcount(self.widget), 3) + self.layout.addWidget(self.widget) + self.assertEqual(sys.getrefcount(self.widget), 3) + + +class InternalAdd(UsesQApplication): + @unittest.skipUnless(hasattr(sys, "getrefcount"), f"{sys.implementation.name} has no refcount") + def testInternalRef(self): + mw = QWidget() + w = QWidget() + ow = QWidget() + + topLayout = QGridLayout() + + # unique reference + self.assertEqual(sys.getrefcount(w), 2) + self.assertEqual(sys.getrefcount(ow), 2) + + topLayout.addWidget(w, 0, 0) + topLayout.addWidget(ow, 1, 0) + + # layout keep the referemce + self.assertEqual(sys.getrefcount(w), 3) + self.assertEqual(sys.getrefcount(ow), 3) + + mainLayout = QGridLayout() + + mainLayout.addLayout(topLayout, 1, 0, 1, 4) + + # the same reference + self.assertEqual(sys.getrefcount(w), 3) + self.assertEqual(sys.getrefcount(ow), 3) + + mw.setLayout(mainLayout) + + # now trasfer the ownership to mw + self.assertEqual(sys.getrefcount(w), 3) + self.assertEqual(sys.getrefcount(ow), 3) + + del mw + + # remove the ref and invalidate the widget + self.assertEqual(sys.getrefcount(w), 2) + self.assertEqual(sys.getrefcount(ow), 2) + + +if __name__ == '__main__': + unittest.main() diff --git a/sources/pyside6/tests/QtWidgets/qlayout_test.py b/sources/pyside6/tests/QtWidgets/qlayout_test.py new file mode 100644 index 000000000..cc41f78b1 --- /dev/null +++ b/sources/pyside6/tests/QtWidgets/qlayout_test.py @@ -0,0 +1,139 @@ +# Copyright (C) 2022 The Qt Company Ltd. +# SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0 + +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 helper.usesqapplication import UsesQApplication +from PySide6.QtCore import QTimer +from PySide6.QtWidgets import (QFormLayout, QHBoxLayout, QLayout, QPushButton, + QSpacerItem, QWidget, QWidgetItem) + + +class MyLayout(QLayout): + def __init__(self, parent=None): + QLayout.__init__(self, parent) + self._list = [] + + def addItem(self, item): + self.add(item) + + def addWidget(self, widget): + self.add(QWidgetItem(widget)) + + def itemAt(self, index): + if index < len(self._list): + return self._list[index] + + return None + + def count(self): + return len(self._list) + + def add(self, item): + self._list.append(item) + + +class MissingItemAtLayout(QLayout): + def __init__(self, parent=None): + QLayout.__init__(self, parent) + self._list = [] + + def addItem(self, item): + self.add(item) + + def addWidget(self, widget): + self.add(QWidgetItem(widget)) + + def count(self): + return len(self._list) + + def add(self, item): + self._list.append(item) + +# Test if a layout implemented in python, the QWidget.setLayout works +# fine because this implement som layout functions used in glue code of +# QWidget, then in c++ when call a virtual function this need call the QLayout +# function implemented in python + + +class QLayoutTest(UsesQApplication): + @unittest.skipUnless(hasattr(sys, "getrefcount"), f"{sys.implementation.name} has no refcount") + def testOwnershipTransfer(self): + b = QPushButton("teste") + l = MyLayout() + + l.addWidget(b) + + self.assertEqual(sys.getrefcount(b), 2) + + w = QWidget() + + # transfer ref + w.setLayout(l) + + self.assertEqual(sys.getrefcount(b), 3) + + @unittest.skipUnless(hasattr(sys, "getrefcount"), f"{sys.implementation.name} has no refcount") + def testReferenceTransfer(self): + b = QPushButton("teste") + l = QHBoxLayout() + + # keep ref + l.addWidget(b) + self.assertEqual(sys.getrefcount(b), 3) + + w = QWidget() + + # transfer ref + w.setLayout(l) + + self.assertEqual(sys.getrefcount(b), 3) + + # release ref + del w + + self.assertEqual(sys.getrefcount(b), 2) + + def testMissingFunctions(self): + w = QWidget() + b = QPushButton("test") + l = MissingItemAtLayout() + + l.addWidget(b) + + self.assertRaises(RuntimeError, w.setLayout, l) + + def testQFormLayout(self): + w = QWidget() + formLayout = QFormLayout() + spacer = QSpacerItem(100, 30) + formLayout.setItem(0, QFormLayout.SpanningRole, spacer) + w.setLayout(formLayout) + w.show() + QTimer.singleShot(10, w.close) + self.app.exec() + del w + # PYSIDE-535: Need to collect garbage in PyPy to trigger deletion + gc.collect() + # PYSIDE-535: Why do I need to do it twice, here? + gc.collect() + self.assertRaises(RuntimeError, spacer.isEmpty) + + def testConstructorProperties(self): + """PYSIDE-1986, test passing properties to the constructor of + QHBoxLayout, which does not have default arguments.""" + layout = QHBoxLayout(objectName="layout", spacing=30) + self.assertEqual(layout.spacing(), 30) + self.assertEqual(layout.objectName(), "layout") + + +if __name__ == '__main__': + unittest.main() diff --git a/sources/pyside6/tests/QtWidgets/qlcdnumber_test.py b/sources/pyside6/tests/QtWidgets/qlcdnumber_test.py new file mode 100644 index 000000000..bc186f755 --- /dev/null +++ b/sources/pyside6/tests/QtWidgets/qlcdnumber_test.py @@ -0,0 +1,33 @@ +# Copyright (C) 2022 The Qt Company Ltd. +# SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0 + +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.QtWidgets import QApplication, QLCDNumber + + +class QLCDNumberOverflow(unittest.TestCase): + '''Test case for unhandled overflow on QLCDNumber() numDigits argument (see bug #215).''' + + def assertRaises(self, *args, **kwds): + if not hasattr(sys, "pypy_version_info"): + # PYSIDE-535: PyPy complains "Fatal RPython error: NotImplementedError" + return super().assertRaises(*args, **kwds) + + def setUp(self): + self.app = QApplication([]) + + def testnumDigitsOverflow(self): + # NOTE: PyQt4 raises TypeError, but boost.python raises OverflowError + self.assertRaises(OverflowError, QLCDNumber, 840835495615213080) + + +if __name__ == '__main__': + unittest.main() diff --git a/sources/pyside6/tests/QtWidgets/qlistwidget_test.py b/sources/pyside6/tests/QtWidgets/qlistwidget_test.py new file mode 100644 index 000000000..377e63ffb --- /dev/null +++ b/sources/pyside6/tests/QtWidgets/qlistwidget_test.py @@ -0,0 +1,77 @@ +# Copyright (C) 2022 The Qt Company Ltd. +# SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0 + +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, QTimer, Qt +from PySide6.QtWidgets import QListWidget, QListWidgetItem +from helper.usesqapplication import UsesQApplication + + +class QListWidgetTest(UsesQApplication): + + @unittest.skipUnless(hasattr(sys, "getrefcount"), f"{sys.implementation.name} has no refcount") + def populateList(self, lst): + o = QObject() + o.setObjectName("obj") + + item = QListWidgetItem("item0") + item.setData(Qt.UserRole, o) + # item._data = o + self.assertTrue(sys.getrefcount(o), 3) + self.assertTrue(sys.getrefcount(item), 2) + lst.addItem(item) + self.assertTrue(sys.getrefcount(item), 3) + + @unittest.skipUnless(hasattr(sys, "getrefcount"), f"{sys.implementation.name} has no refcount") + def checkCurrentItem(self, lst): + item = lst.currentItem() + self.assertTrue(sys.getrefcount(item), 3) + + @unittest.skipUnless(hasattr(sys, "getrefcount"), f"{sys.implementation.name} has no refcount") + def checkItemData(self, lst): + item = lst.currentItem() + o = item.data(Qt.UserRole) + self.assertTrue(sys.getrefcount(o), 4) + self.assertEqual(o, item._data) + self.assertTrue(sys.getrefcount(o), 2) + + @unittest.skipUnless(hasattr(sys, "getrefcount"), f"{sys.implementation.name} has no refcount") + def testConstructorWithParent(self): + lst = QListWidget() + self.populateList(lst) + self.checkCurrentItem(lst) + i = lst.item(0) + self.assertTrue(sys.getrefcount(i), 3) + + del lst + self.assertTrue(sys.getrefcount(i), 2) + del i + + def testIt(self): + lst = QListWidget() + lst.show() + slot = lambda: lst.removeItemWidget(lst.currentItem()) + lst.addItem(QListWidgetItem("foo")) + QTimer.singleShot(0, slot) + QTimer.singleShot(0, lst.close) + self.app.exec() + self.assertEqual(lst.count(), 1) + + def testClear(self): + lst = QListWidget() + lst.addItem("foo") + item = lst.item(0) + self.assertIsNone(lst.clear()) + self.assertRaises(RuntimeError, lambda: item.text()) + + +if __name__ == '__main__': + unittest.main() diff --git a/sources/pyside6/tests/QtWidgets/qlistwidgetitem_test.py b/sources/pyside6/tests/QtWidgets/qlistwidgetitem_test.py new file mode 100644 index 000000000..a85c1b48f --- /dev/null +++ b/sources/pyside6/tests/QtWidgets/qlistwidgetitem_test.py @@ -0,0 +1,42 @@ +# Copyright (C) 2022 The Qt Company Ltd. +# SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0 + +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.QtWidgets import QListWidget, QListWidgetItem +from helper.usesqapplication import UsesQApplication + + +class QListWidgetItemConstructor(UsesQApplication): + + def setUp(self): + super(QListWidgetItemConstructor, self).setUp() + self.widgetList = QListWidget() + + def tearDown(self): + del self.widgetList + # PYSIDE-535: Need to collect garbage in PyPy to trigger deletion + gc.collect() + super(QListWidgetItemConstructor, self).tearDown() + + def testConstructorWithParent(self): + # Bug 235 - QListWidgetItem constructor not saving ownership + QListWidgetItem(self.widgetList) + item = self.widgetList.item(0) + self.assertEqual(item.listWidget(), self.widgetList) + + def testConstructorWithNone(self): + # Bug 452 - QListWidgetItem() not casting NoneType to null correctly. + item = QListWidgetItem(None, 123) + + +if __name__ == '__main__': + unittest.main() diff --git a/sources/pyside6/tests/QtWidgets/qmainwindow_test.py b/sources/pyside6/tests/QtWidgets/qmainwindow_test.py new file mode 100644 index 000000000..2f245c8ff --- /dev/null +++ b/sources/pyside6/tests/QtWidgets/qmainwindow_test.py @@ -0,0 +1,97 @@ +# Copyright (C) 2022 The Qt Company Ltd. +# SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0 + +import os +import sys +import unittest +import weakref + +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 QTimer +from PySide6.QtWidgets import QMainWindow, QPushButton, QToolButton, QWidget +from helper.usesqapplication import UsesQApplication + + +class MainWindow(QMainWindow): + def __init__(self): + super().__init__() + + self.createToolbar() + + def createToolbar(self): + pointerButton = QToolButton() + pointerToolbar = self.addToolBar("Pointer type") + pointerToolbar.addWidget(pointerButton) + + +class MyButton(QPushButton): + def __init__(self, parent=None): + super().__init__() + self._called = False + + def myCallback(self): + self._called = True + + +class TestMainWindow(UsesQApplication): + + def testCreateToolbar(self): + w = MainWindow() + w.show() + QTimer.singleShot(1000, self.app.quit) + self.app.exec() + + def objDel(self, obj): + self.app.quit() + + @unittest.skipUnless(hasattr(sys, "getrefcount"), f"{sys.implementation.name} has no refcount") + def testRefCountToNull(self): + w = QMainWindow() + c = QWidget() + self.assertEqual(sys.getrefcount(c), 2) + w.setCentralWidget(c) + self.assertEqual(sys.getrefcount(c), 3) + wr = weakref.ref(c, self.objDel) + w.setCentralWidget(None) + c = None + self.app.exec() + + @unittest.skipUnless(hasattr(sys, "getrefcount"), f"{sys.implementation.name} has no refcount") + def testRefCountToAnother(self): + w = QMainWindow() + c = QWidget() + self.assertEqual(sys.getrefcount(c), 2) + w.setCentralWidget(c) + self.assertEqual(sys.getrefcount(c), 3) + + c2 = QWidget() + w.setCentralWidget(c2) + self.assertEqual(sys.getrefcount(c2), 3) + + wr = weakref.ref(c, self.objDel) + w.setCentralWidget(None) + c = None + + self.app.exec() + + def testSignalDisconect(self): + w = QMainWindow() + b = MyButton("button") + b.clicked.connect(b.myCallback) + w.setCentralWidget(b) + + b = MyButton("button") + b.clicked.connect(b.myCallback) + w.setCentralWidget(b) + + b.click() + self.assertEqual(b._called, True) + + +if __name__ == '__main__': + unittest.main() + diff --git a/sources/pyside6/tests/QtWidgets/qmenu_test.py b/sources/pyside6/tests/QtWidgets/qmenu_test.py new file mode 100644 index 000000000..a6976a637 --- /dev/null +++ b/sources/pyside6/tests/QtWidgets/qmenu_test.py @@ -0,0 +1,76 @@ +# Copyright (C) 2022 The Qt Company Ltd. +# SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0 + +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.QtWidgets import QMenu +from PySide6.QtGui import QKeySequence, QIcon +from PySide6.QtCore import SLOT + +from helper.usesqapplication import UsesQApplication + + +class QMenuAddAction(UsesQApplication): + + def setUp(self): + super(QMenuAddAction, self).setUp() + self.menu = QMenu() + + def tearDown(self): + del self.menu + # PYSIDE-535: Need to collect garbage in PyPy to trigger deletion + gc.collect() + super(QMenuAddAction, self).tearDown() + + def testAddActionWithoutKeySequenceCallable(self): + # bug #280 + action = self.menu.addAction(self.app.tr('aaa'), lambda: 1) + + def testAddActionKeySequenceCallable(self): + # bug #228 + action = self.menu.addAction(self.app.tr('aaa'), lambda: 1, + QKeySequence(self.app.tr('Ctrl+O'))) + + def testAddActionKeySequenceSlot(self): + action = self.menu.addAction('Quit', self.app, SLOT('quit()'), + QKeySequence('Ctrl+O')) + + +class QMenuAddActionWithIcon(UsesQApplication): + + def setUp(self): + super(QMenuAddActionWithIcon, self).setUp() + self.menu = QMenu() + self.icon = QIcon() + + def tearDown(self): + del self.menu + del self.icon + # PYSIDE-535: Need to collect garbage in PyPy to trigger deletion + gc.collect() + super(QMenuAddActionWithIcon, self).tearDown() + + def testAddActionWithoutKeySequenceCallable(self): + # bug #280 + action = self.menu.addAction(self.icon, self.app.tr('aaa'), lambda: 1) + + def testAddActionKeySequenceCallable(self): + # bug #228 + action = self.menu.addAction(self.icon, self.app.tr('aaa'), lambda: 1, + QKeySequence(self.app.tr('Ctrl+O'))) + + def testAddActionKeySequenceSlot(self): + action = self.menu.addAction(self.icon, 'Quit', self.app, SLOT('quit()'), + QKeySequence('Ctrl+O')) + + +if __name__ == '__main__': + unittest.main() diff --git a/sources/pyside6/tests/QtWidgets/qmenuadd_test.py b/sources/pyside6/tests/QtWidgets/qmenuadd_test.py new file mode 100644 index 000000000..5b42e755f --- /dev/null +++ b/sources/pyside6/tests/QtWidgets/qmenuadd_test.py @@ -0,0 +1,33 @@ +# 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 the QMenu.addAction() method''' + +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.QtWidgets import QMenu +from helper.usesqapplication import UsesQApplication + + +class QMenuAddAction(UsesQApplication): + + def openFile(self, *args): + self.arg = args + + def testQMenuAddAction(self): + fileMenu = QMenu("&File") + + addNewAction = fileMenu.addAction("&Open...", self.openFile) + addNewAction.trigger() + self.assertEqual(self.arg, ()) + + +if __name__ == '__main__': + unittest.main() diff --git a/sources/pyside6/tests/QtWidgets/qobject_mi_test.py b/sources/pyside6/tests/QtWidgets/qobject_mi_test.py new file mode 100644 index 000000000..d90961495 --- /dev/null +++ b/sources/pyside6/tests/QtWidgets/qobject_mi_test.py @@ -0,0 +1,51 @@ +# 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 multiple inheritance from 2 QObjects''' + +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 +from PySide6.QtGui import QIntValidator, QValidator +from PySide6.QtWidgets import QWidget + +from helper.usesqapplication import UsesQApplication + + +class WidgetValidator(QWidget, QIntValidator): + def __init__(self, parent=None): + QWidget.__init__(self, parent) + QIntValidator.__init__(self, parent) + + +class DoubleQObjectInheritanceTest(UsesQApplication): + + def testDouble(self): + '''Double inheritance from QObject classes''' + + obj = WidgetValidator() + + # QObject methods + obj.setObjectName('aaaa') + self.assertEqual(obj.objectName(), 'aaaa') + + # QWidget methods + obj.setVisible(False) + self.assertFalse(obj.isVisible()) + + # QIntValidator methods + state, string, number = obj.validate('aaaa', 0) + self.assertEqual(state, QValidator.Invalid) + state, string, number = obj.validate('33', 0) + self.assertEqual(state, QValidator.Acceptable) + + +if __name__ == '__main__': + unittest.main() diff --git a/sources/pyside6/tests/QtWidgets/qpicture_test.py b/sources/pyside6/tests/QtWidgets/qpicture_test.py new file mode 100644 index 000000000..b81713b57 --- /dev/null +++ b/sources/pyside6/tests/QtWidgets/qpicture_test.py @@ -0,0 +1,48 @@ +# Copyright (C) 2022 The Qt Company Ltd. +# SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0 + +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 helper.usesqapplication import UsesQApplication +from PySide6.QtCore import QTimer +from PySide6.QtGui import QPicture, QPainter +from PySide6.QtWidgets import QWidget + + +class MyWidget(QWidget): + def paintEvent(self, e): + with QPainter(self) as p: + p.drawPicture(0, 0, self._picture) + self._app.quit() + + +class QPictureTest(UsesQApplication): + def testFromData(self): + picture = QPicture() + with QPainter(picture) as painter: + painter.drawEllipse(10, 20, 80, 70) + + data = picture.data() + picture2 = QPicture() + picture2.setData(data) + + self.assertEqual(picture2.data(), picture.data()) + + w = MyWidget() + w._picture = picture2 + w._app = self.app + + QTimer.singleShot(300, w.show) + self.app.exec() + + +if __name__ == '__main__': + unittest.main() + diff --git a/sources/pyside6/tests/QtWidgets/qpushbutton_test.py b/sources/pyside6/tests/QtWidgets/qpushbutton_test.py new file mode 100644 index 000000000..bfc04130e --- /dev/null +++ b/sources/pyside6/tests/QtWidgets/qpushbutton_test.py @@ -0,0 +1,54 @@ +# Copyright (C) 2022 The Qt Company Ltd. +# SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0 + +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 helper.usesqapplication import UsesQApplication +from PySide6.QtWidgets import QPushButton, QMenu, QWidget +from PySide6.QtCore import QTimer, Qt + + +class MyWidget(QWidget): + def __init__(self): + super().__init__() + + m = QMenu(self) + b = QPushButton("Hello", self) + b.setMenu(m) + + +class QPushButtonTest(UsesQApplication): + def createMenu(self, button): + m = QMenu() + button.setMenu(m) + + def testSetMenu(self): + w = MyWidget() + w.show() + + timer = QTimer.singleShot(100, self.app.quit) + self.app.exec() + + def buttonCb(self, checked): + self._clicked = True + + def testBoolinSignal(self): + b = QPushButton() + b.setCheckable(True) + b.setShortcut(Qt.Key_A) + self._clicked = False + b.toggled[bool].connect(self.buttonCb) + b.toggle() + self.assertTrue(self._clicked) + + +if __name__ == '__main__': + unittest.main() + diff --git a/sources/pyside6/tests/QtWidgets/qsplitter_test.py b/sources/pyside6/tests/QtWidgets/qsplitter_test.py new file mode 100644 index 000000000..ae383f425 --- /dev/null +++ b/sources/pyside6/tests/QtWidgets/qsplitter_test.py @@ -0,0 +1,29 @@ +# Copyright (C) 2022 The Qt Company Ltd. +# SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0 + +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.QtWidgets import QSplitter + +from helper.usesqapplication import UsesQApplication + + +class QSplitterTest(UsesQApplication): + + def testGetRange(self): + splitter = QSplitter() + _min, _max = splitter.getRange(0) + self.assertTrue(isinstance(_min, int)) + self.assertTrue(isinstance(_max, int)) + + +if __name__ == "__main__": + unittest.main() + diff --git a/sources/pyside6/tests/QtWidgets/qstyle_test.py b/sources/pyside6/tests/QtWidgets/qstyle_test.py new file mode 100644 index 000000000..5a9b29dc6 --- /dev/null +++ b/sources/pyside6/tests/QtWidgets/qstyle_test.py @@ -0,0 +1,76 @@ +# Copyright (C) 2022 The Qt Company Ltd. +# SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0 + +import sys +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 helper.usesqapplication import UsesQApplication + +from PySide6.QtGui import QWindow +from PySide6.QtWidgets import (QApplication, QFontComboBox, QLabel, QProxyStyle, + QStyleFactory, QWidget) + + +class ProxyStyle(QProxyStyle): + + def __init__(self, style): + QProxyStyle.__init__(self, style) + self.polished = 0 + + def polish(self, widget): + self.polished = self.polished + 1 + super(ProxyStyle, self).polish(widget) + + +class SetStyleTest(UsesQApplication): + '''Tests setting the same QStyle for all objects in a UI hierarchy.''' + + def testSetStyle(self): + '''All this test have to do is not break with some invalid Python wrapper.''' + + def setStyleHelper(widget, style): + widget.setStyle(style) + widget.setPalette(style.standardPalette()) + for child in widget.children(): + if isinstance(child, QWidget): + setStyleHelper(child, style) + + container = QWidget() + # QFontComboBox is used because it has an QLineEdit created in C++ inside it, + # and if the QWidget.setStyle(style) steals the ownership of the style + # for the C++ originated widget everything will break. + fontComboBox = QFontComboBox(container) + label = QLabel(container) + label.setText('Label') + style = QStyleFactory.create(QStyleFactory.keys()[0]) + setStyleHelper(container, style) + + def testSetProxyStyle(self): + label = QLabel("QtWidgets/ProxyStyle test") + baseStyle = QStyleFactory.create(QApplication.instance().style().objectName()) + self.assertTrue(baseStyle) + proxyStyle = ProxyStyle(baseStyle) + label.setStyle(proxyStyle) + label.show() + while not label.windowHandle().isExposed(): + QApplication.instance().processEvents() + self.assertTrue(proxyStyle.polished > 0) + + @unittest.skipUnless(hasattr(sys, "getrefcount"), f"{sys.implementation.name} has no refcount") + def testSetStyleOwnership(self): + style = QStyleFactory.create(QStyleFactory.keys()[0]) + self.assertEqual(sys.getrefcount(style), 2) + QApplication.instance().setStyle(style) + self.assertEqual(sys.getrefcount(style), 3) + + +if __name__ == '__main__': + unittest.main() + diff --git a/sources/pyside6/tests/QtWidgets/qstyleoption_test.py b/sources/pyside6/tests/QtWidgets/qstyleoption_test.py new file mode 100644 index 000000000..06798b9e9 --- /dev/null +++ b/sources/pyside6/tests/QtWidgets/qstyleoption_test.py @@ -0,0 +1,43 @@ +# Copyright (C) 2022 The Qt Company Ltd. +# SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0 + +import sys +import os +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 helper.usesqapplication import UsesQApplication + +from PySide6.QtWidgets import (QApplication, QCommonStyle, QPushButton) + + +text = '' + + +class Style(QCommonStyle): + + def drawControl(self, element, option, painter, widget=None): + # This should be a QStyleOptionButton with a "text" field + global text + text = option.text + + +class StyleOptionTest(UsesQApplication): + '''PYSIDE-1909: Test cast to derived style option classes.''' + + def testStyle(self): + global text + button = QPushButton("Hello World") + button.setStyle(Style()) + button.show() + while not text: + QApplication.processEvents() + self.assertEqual(text, button.text()) + + +if __name__ == '__main__': + unittest.main() diff --git a/sources/pyside6/tests/QtWidgets/qtableview_test.py b/sources/pyside6/tests/QtWidgets/qtableview_test.py new file mode 100644 index 000000000..c43666f23 --- /dev/null +++ b/sources/pyside6/tests/QtWidgets/qtableview_test.py @@ -0,0 +1,28 @@ +# Copyright (C) 2022 The Qt Company Ltd. +# SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0 + +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 QAbstractTableModel +from PySide6.QtWidgets import QTableWidget +from helper.usesqapplication import UsesQApplication + + +class QPenTest(UsesQApplication): + + def testItemModel(self): + tv = QTableWidget() + + self.assertEqual(type(tv.model()), QAbstractTableModel) + + +if __name__ == '__main__': + unittest.main() + diff --git a/sources/pyside6/tests/QtWidgets/qtabwidget_test.py b/sources/pyside6/tests/QtWidgets/qtabwidget_test.py new file mode 100644 index 000000000..8db45f24b --- /dev/null +++ b/sources/pyside6/tests/QtWidgets/qtabwidget_test.py @@ -0,0 +1,43 @@ +# Copyright (C) 2022 The Qt Company Ltd. +# SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0 + +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.QtWidgets import QPushButton, QTabWidget +from helper.timedqapplication import TimedQApplication + + +def makeBug643(tab): + button = QPushButton('Foo') + tab.insertTab(0, button, 'Foo') + + +class RemoveTabMethod(TimedQApplication): + def setUp(self): + TimedQApplication.setUp(self) + self.tab = QTabWidget() + + def tearDown(self): + del self.tab + # PYSIDE-535: Need to collect garbage in PyPy to trigger deletion + gc.collect() + TimedQApplication.tearDown(self) + + def testRemoveTabPresence(self): + self.assertTrue(getattr(self.tab, 'removeTab')) + + def testInsertTab(self): + makeBug643(self.tab) + self.assertEqual(self.tab.count(), 1) + + +if __name__ == '__main__': + unittest.main() diff --git a/sources/pyside6/tests/QtWidgets/qtabwidgetclear_test.py b/sources/pyside6/tests/QtWidgets/qtabwidgetclear_test.py new file mode 100644 index 000000000..49e16e8d2 --- /dev/null +++ b/sources/pyside6/tests/QtWidgets/qtabwidgetclear_test.py @@ -0,0 +1,48 @@ +# Copyright (C) 2022 The Qt Company Ltd. +# SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0 + +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.QtWidgets import QMainWindow, QTabWidget, QTextEdit, QSplitter +from helper.usesqapplication import UsesQApplication + + +class TabWidgetClear(QMainWindow): + def __init__(self): + super().__init__() + self.tabWidget = QTabWidget(self) + self.setCentralWidget(self.tabWidget) + self.editBox = QTextEdit(self) + self.tabWidget.addTab(self.getSplitter(), 'Test') + + def getSplitter(self): + splitter = QSplitter() + splitter.addWidget(self.editBox) + return splitter + + def toggle(self): + self.tabWidget.clear() + self.getSplitter() + + +class TestTabWidgetClear(UsesQApplication): + + def testClear(self): + self.window = TabWidgetClear() + self.window.show() + try: + self.window.toggle() + except RuntimeError as e: + # This should never happened, PYSIDE-213 + raise e + + +if __name__ == '__main__': + unittest.main() diff --git a/sources/pyside6/tests/QtWidgets/qtextedit_signal_test.py b/sources/pyside6/tests/QtWidgets/qtextedit_signal_test.py new file mode 100644 index 000000000..16929f0f2 --- /dev/null +++ b/sources/pyside6/tests/QtWidgets/qtextedit_signal_test.py @@ -0,0 +1,50 @@ +# Copyright (C) 2022 The Qt Company Ltd. +# SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0 + +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 Signal, Slot +from PySide6.QtWidgets import QMainWindow, QPushButton, QTextEdit +from helper.usesqapplication import UsesQApplication + + +class MyWindow(QMainWindow): + appendText = Signal(str) + + @Slot() + def onButtonPressed(self): + self.appendText.emit("PySide") + + def __init__(self, parent=None): + super().__init__(parent) + + self.textEdit = QTextEdit() + self.btn = QPushButton("ClickMe") + self.btn.clicked.connect(self.onButtonPressed) + self.appendText.connect(self.textEdit.append) + + def start(self): + self.btn.click() + + def text(self): + return self.textEdit.toPlainText() + + +class testSignalWithCPPSlot(UsesQApplication): + + def testEmission(self): + w = MyWindow() + w.start() + self.assertEqual(w.text(), "PySide") + + +if __name__ == '__main__': + unittest.main() + diff --git a/sources/pyside6/tests/QtWidgets/qtextedit_test.py b/sources/pyside6/tests/QtWidgets/qtextedit_test.py new file mode 100644 index 000000000..b82350293 --- /dev/null +++ b/sources/pyside6/tests/QtWidgets/qtextedit_test.py @@ -0,0 +1,45 @@ +# 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 QTextEdit and ownership problems.''' + +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.QtWidgets import QTextEdit + +from helper.usesqapplication import UsesQApplication + + +class DontTouchReference(UsesQApplication): + '''Check if the QTextTable returned by QTextCursor.insertTable() is not + referenced by the QTextCursor that returns it.''' + + def setUp(self): + super(DontTouchReference, self).setUp() + self.editor = QTextEdit() + self.cursor = self.editor.textCursor() + self.table = self.cursor.insertTable(1, 1) + + @unittest.skipUnless(hasattr(sys, "getrefcount"), f"{sys.implementation.name} has no refcount") + def testQTextTable(self): + # methods which return QTextTable should not increment its reference + self.assertEqual(sys.getrefcount(self.table), 2) + f = self.cursor.currentFrame() + del f + self.assertEqual(sys.getrefcount(self.table), 2) + # destroying the cursor should not raise any "RuntimeError: internal + # C++ object already deleted." when accessing the QTextTable + del self.cursor + self.assertEqual(sys.getrefcount(self.table), 2) + cell = self.table.cellAt(0, 0) + + +if __name__ == "__main__": + unittest.main() diff --git a/sources/pyside6/tests/QtWidgets/qtoolbar_test.py b/sources/pyside6/tests/QtWidgets/qtoolbar_test.py new file mode 100644 index 000000000..6fa5865cf --- /dev/null +++ b/sources/pyside6/tests/QtWidgets/qtoolbar_test.py @@ -0,0 +1,50 @@ +# 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 QToolbar''' + +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.QtGui import QAction +from PySide6.QtWidgets import QToolBar, QMainWindow + +from helper.usesqapplication import UsesQApplication + + +class AddActionText(UsesQApplication): + '''Test case for calling QToolbar.addAction passing a text''' + + def setUp(self): + # Acquire resources + super(AddActionText, self).setUp() + self.window = QMainWindow() + self.toolbar = QToolBar() + self.window.addToolBar(self.toolbar) + + def tearDown(self): + # Release resources + super(AddActionText, self).tearDown() + del self.toolbar + del self.window + # PYSIDE-535: Need to collect garbage in PyPy to trigger deletion + gc.collect() + + def testText(self): + # QToolBar.addAction(text) - add a QToolButton + self.toolbar.addAction('aaaa') + self.assertEqual(len(self.toolbar.actions()), 1) + action = self.toolbar.actions()[0] + self.assertTrue(isinstance(action, QAction)) + self.assertEqual(action.text(), 'aaaa') + + +if __name__ == '__main__': + unittest.main() diff --git a/sources/pyside6/tests/QtWidgets/qtoolbox_test.py b/sources/pyside6/tests/QtWidgets/qtoolbox_test.py new file mode 100644 index 000000000..d069416b7 --- /dev/null +++ b/sources/pyside6/tests/QtWidgets/qtoolbox_test.py @@ -0,0 +1,45 @@ +# Copyright (C) 2022 The Qt Company Ltd. +# SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0 + +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.QtGui import QIcon +from PySide6.QtWidgets import QToolBox, QWidget + +from helper.usesqapplication import UsesQApplication + + +class OwnershipControl(UsesQApplication): + + def setUp(self): + super(OwnershipControl, self).setUp() + self.toolbox = QToolBox() + + def tearDown(self): + del self.toolbox + # PYSIDE-535: Need to collect garbage in PyPy to trigger deletion + gc.collect() + super(OwnershipControl, self).tearDown() + + def testAddItem(self): + # Was losing ownership of the widget. + index = self.toolbox.addItem(QWidget(), 'item') + item = self.toolbox.widget(index) + self.assertTrue(isinstance(item, QWidget)) + + def testAddItemWithIcon(self): + index = self.toolbox.addItem(QWidget(), QIcon(), 'item') + item = self.toolbox.widget(index) + self.assertTrue(isinstance(item, QWidget)) + + +if __name__ == '__main__': + unittest.main() diff --git a/sources/pyside6/tests/QtWidgets/qtreeview_test.py b/sources/pyside6/tests/QtWidgets/qtreeview_test.py new file mode 100644 index 000000000..fd535bfad --- /dev/null +++ b/sources/pyside6/tests/QtWidgets/qtreeview_test.py @@ -0,0 +1,84 @@ +# Copyright (C) 2022 The Qt Company Ltd. +# SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0 + +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.QtGui import QStandardItemModel +from PySide6.QtWidgets import (QWidget, QTreeView, QVBoxLayout, + QStyledItemDelegate, QHeaderView) +from PySide6.QtCore import Qt +from helper.usesqapplication import UsesQApplication + + +class Widget(QWidget): + def __init__(self, parent=None): + QWidget.__init__(self, parent) + self.treeView = QTreeView(self) + layout = QVBoxLayout() + layout.addWidget(self.treeView) + self.setLayout(layout) + self.treeView.setModel(QStandardItemModel()) + + self.treeView.model().setHorizontalHeaderLabels(('3', '1', '5')) + + +class QWidgetTest(UsesQApplication): + + def testDelegates(self): + widget = Widget() + t = widget.treeView + + # When calling setItemDelegateForColumn using a separate variable + # for the second argument (QAbstractItemDelegate), there was no problem + # on keeping the reference to this object, since the variable was kept + # alive (case A) + # Contrary, when instantiating this argument on the function call + # Using QStyledItemDelegate inside the call the reference of the + # object was lost, causing a segfault. (case B) + + # Case A + d = QStyledItemDelegate() + # Using QStyledItemDelegate from a variable so we keep the reference alive + # and we encounter no segfault. + t.setItemDelegateForColumn(0, d) + # This raised the Segmentation Fault too, because manually destroying + # the object caused a missing refrence. + del d + # PYSIDE-535: Need to collect garbage in PyPy to trigger deletion + gc.collect() + + # Getting the delegates + a = t.itemDelegateForColumn(0) + self.assertIsInstance(a, QStyledItemDelegate) + + # Case B + t.setItemDelegateForColumn(1, QStyledItemDelegate()) + + # Getting the delegates + b = t.itemDelegateForColumn(1) + self.assertIsInstance(b, QStyledItemDelegate) + + # Test for Rows + t.setItemDelegateForRow(0, QStyledItemDelegate()) + self.assertIsInstance(t.itemDelegateForRow(0), QStyledItemDelegate) + + # Test for general delegate + t.setItemDelegate(QStyledItemDelegate()) + self.assertIsInstance(t.itemDelegate(), QStyledItemDelegate) + + def testHeader(self): + tree = QTreeView() + tree.setHeader(QHeaderView(Qt.Horizontal)) + self.assertIsNotNone(tree.header()) + + +if __name__ == '__main__': + unittest.main() diff --git a/sources/pyside6/tests/QtWidgets/qtreewidget_test.py b/sources/pyside6/tests/QtWidgets/qtreewidget_test.py new file mode 100644 index 000000000..6c2db32b9 --- /dev/null +++ b/sources/pyside6/tests/QtWidgets/qtreewidget_test.py @@ -0,0 +1,48 @@ +# Copyright (C) 2022 The Qt Company Ltd. +# SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0 + +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.QtWidgets import QTreeWidget, QTreeWidgetItem, QPushButton +from helper.usesqapplication import UsesQApplication + + +class QTreeWidgetTest(UsesQApplication): + + # PYSIDE-73: + # There was a problem when adding items to a QTreeWidget + # when the Widget was being build on the method call instead + # of as a separate variable. + # The problem was there was not ownership transfer, so the + # QTreeWidget did not own the QWidget element + def testSetItemWidget(self): + + treeWidget = QTreeWidget() + treeWidget.setColumnCount(2) + + item = QTreeWidgetItem(['text of column 0', '']) + treeWidget.insertTopLevelItem(0, item) + # Adding QPushButton inside the method + treeWidget.setItemWidget(item, 1, + QPushButton('Push button on column 1')) + + # Getting the widget back + w = treeWidget.itemWidget(treeWidget.itemAt(0, 1), 1) + self.assertIsInstance(w, QPushButton) + + p = QPushButton('New independent button') + # Adding QPushButton object from variable + treeWidget.setItemWidget(item, 0, p) + w = treeWidget.itemWidget(treeWidget.itemAt(0, 0), 0) + self.assertIsInstance(w, QPushButton) + + +if __name__ == '__main__': + unittest.main() diff --git a/sources/pyside6/tests/QtWidgets/qtreewidgetitem_test.py b/sources/pyside6/tests/QtWidgets/qtreewidgetitem_test.py new file mode 100644 index 000000000..432aba2ed --- /dev/null +++ b/sources/pyside6/tests/QtWidgets/qtreewidgetitem_test.py @@ -0,0 +1,47 @@ +#!/usr/bin/python +# Copyright (C) 2022 The Qt Company Ltd. +# SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0 + +""" +Unit tests for QTreeWidgetItem +------------------------------ + +This test is actually meant for all types which provide `tp_richcompare` +but actually define something without providing `==` or `!=` operators. +QTreeWidgetItem for instance defines `<` only. + +PYSIDE-74: We redirect to type `object`s handling which is anyway the default + when `tp_richcompare` is undefined. +""" + +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 QTimer +from PySide6.QtWidgets import QApplication, QTreeWidget, QTreeWidgetItem + + +class QTreeWidgetItemTest(unittest.TestCase): + def testClass(self): + app = QApplication([]) + treewidget = QTreeWidget() + item = QTreeWidgetItem(["Words and stuff"]) + item2 = QTreeWidgetItem(["More words!"]) + treewidget.insertTopLevelItem(0, item) + + dummy_list = ["Numbers", "Symbols", "Spam"] + self.assertFalse(item in dummy_list) + self.assertTrue(item not in dummy_list) + self.assertFalse(item == item2) + self.assertTrue(item != item2) + + +if __name__ == "__main__": + unittest.main() + diff --git a/sources/pyside6/tests/QtWidgets/qvariant_test.py b/sources/pyside6/tests/QtWidgets/qvariant_test.py new file mode 100644 index 000000000..fe0266309 --- /dev/null +++ b/sources/pyside6/tests/QtWidgets/qvariant_test.py @@ -0,0 +1,142 @@ +# Copyright (C) 2022 The Qt Company Ltd. +# SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0 + +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 Qt, QObject +from PySide6.QtWidgets import (QComboBox, QGraphicsScene, + QGraphicsRectItem) + +from helper.usesqapplication import UsesQApplication + + +class MyDiagram(QGraphicsScene): + pass + + +class MyItem(QGraphicsRectItem): + def itemChange(self, change, value): + return value + + +class Sequence(object): + # Having the __getitem__ method on a class transform the Python + # type to a PySequence. + # Before the patch: aa75437f9119d997dd290471ac3e2cc88ca88bf1 + # "Fix QVariant conversions when using PySequences" + # one could not use an object from this class, because internally + # we were requiring that the PySequence was finite. + def __getitem__(self, key): + raise IndexError() + + +class QGraphicsSceneOnQVariantTest(UsesQApplication): + """Test storage ot QGraphicsScene into QVariants""" + def setUp(self): + super(QGraphicsSceneOnQVariantTest, self).setUp() + self.s = MyDiagram() + self.i = MyItem() + self.combo = QComboBox() + + def tearDown(self): + del self.s + del self.i + del self.combo + # PYSIDE-535: Need to collect garbage in PyPy to trigger deletion + gc.collect() + super(QGraphicsSceneOnQVariantTest, self).tearDown() + + def testIt(self): + self.s.addItem(self.i) + self.assertEqual(len(self.s.items()), 1) + + def testSequence(self): + # PYSIDE-641 + self.combo.addItem("test", userData=Sequence()) + self.assertTrue(isinstance(self.combo.itemData(0), Sequence)) + + +class QVariantConversionTest(UsesQApplication): + """ + Tests conversion from QVariant to supported type held by QVariant + """ + def setUp(self): + super(QVariantConversionTest, self).setUp() + self.obj = QObject() + + def tearDown(self): + del self.obj + super(QVariantConversionTest, self).tearDown() + + def testEnum(self): + """ + PYSIDE-1798: Test enum is obtained correctly when return through QVariant + """ + self.obj.setProperty("test", Qt.SolidLine) + self.assertTrue(isinstance(self.obj.property("test"), Qt.PenStyle)) + self.assertEqual(self.obj.property("test"), Qt.SolidLine) + + def testString(self): + self.obj.setProperty("test", "test") + self.assertEqual(self.obj.property("test"), "test") + self.assertTrue(isinstance(self.obj.property("test"), str)) + + def testBytes(self): + byte_message = bytes("test", 'utf-8') + self.obj.setProperty("test", byte_message) + self.assertEqual(self.obj.property("test"), byte_message) + self.assertTrue(isinstance(self.obj.property("test"), bytes)) + + def testBasicTypes(self): + #bool + self.obj.setProperty("test", True) + self.assertEqual(self.obj.property("test"), True) + self.assertTrue(isinstance(self.obj.property("test"), bool)) + #long + self.obj.setProperty("test", 2) + self.assertEqual(self.obj.property("test"), 2) + self.assertTrue(isinstance(self.obj.property("test"), int)) + #float + self.obj.setProperty("test", 2.5) + self.assertEqual(self.obj.property("test"), 2.5) + self.assertTrue(isinstance(self.obj.property("test"), float)) + #None + self.obj.setProperty("test", None) + self.assertEqual(self.obj.property("test"), None) + + def testContainerTypes(self): + #list + self.obj.setProperty("test", [1, 2, 3]) + self.assertEqual(self.obj.property("test"), [1, 2, 3]) + self.assertTrue(isinstance(self.obj.property("test"), list)) + #dict + self.obj.setProperty("test", {1: "one"}) + self.assertEqual(self.obj.property("test"), {1: "one"}) + self.assertTrue(isinstance(self.obj.property("test"), dict)) + + def testPyObject(self): + class Test: + pass + test = Test() + self.obj.setProperty("test", test) + self.assertEqual(self.obj.property("test"), test) + self.assertTrue(isinstance(self.obj.property("test"), Test)) + + def testQMetaPropertyWrite(self): + combo_box = QComboBox() + meta_obj = combo_box.metaObject() + i = meta_obj.indexOfProperty("sizeAdjustPolicy") + success = meta_obj.property(i).write(combo_box, QComboBox.SizeAdjustPolicy.AdjustToContents) + self.assertTrue(success) + + +if __name__ == '__main__': + unittest.main() diff --git a/sources/pyside6/tests/QtWidgets/qwidget_setlayout_test.py b/sources/pyside6/tests/QtWidgets/qwidget_setlayout_test.py new file mode 100644 index 000000000..1d9128789 --- /dev/null +++ b/sources/pyside6/tests/QtWidgets/qwidget_setlayout_test.py @@ -0,0 +1,44 @@ +#!/usr/bin/python +# Copyright (C) 2022 The Qt Company Ltd. +# SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0 + +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.QtWidgets import QWidget, QVBoxLayout, QPushButton, QApplication, QHBoxLayout +from helper.usesqapplication import UsesQApplication + + +class QWidgetTest(UsesQApplication): + + def test_setLayout(self): + layout = QVBoxLayout() + btn1 = QPushButton("button_v1") + layout.addWidget(btn1) + + btn2 = QPushButton("button_v2") + layout.addWidget(btn2) + + layout2 = QHBoxLayout() + + btn1 = QPushButton("button_h1") + layout2.addWidget(btn1) + + btn2 = QPushButton("button_h2") + layout2.addWidget(btn2) + + layout.addLayout(layout2) + + widget = QWidget() + widget.setLayout(layout) + + +if __name__ == '__main__': + unittest.main() + diff --git a/sources/pyside6/tests/QtWidgets/qwidget_test.py b/sources/pyside6/tests/QtWidgets/qwidget_test.py new file mode 100644 index 000000000..2d503f0d4 --- /dev/null +++ b/sources/pyside6/tests/QtWidgets/qwidget_test.py @@ -0,0 +1,61 @@ +# Copyright (C) 2022 The Qt Company Ltd. +# SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0 + +import sys +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.QtWidgets import QWidget, QMainWindow +from helper.usesqapplication import UsesQApplication + + +class QWidgetInherit(QMainWindow): + def __init__(self): + QWidget.__init__(self) # Intended: Initialize QWidget instead of base + + +class NativeEventTestWidget(QWidget): + + nativeEventCount = 0 + + def __init__(self): + super().__init__() + + def nativeEvent(self, eventType, message): + self.nativeEventCount = self.nativeEventCount + 1 + return [False, 0] + + +class QWidgetTest(UsesQApplication): + + def testInheritance(self): + self.assertRaises(TypeError, QWidgetInherit) + + +class QWidgetVisible(UsesQApplication): + + def testBasic(self): + # Also related to bug #244, on existence of setVisible''' + widget = NativeEventTestWidget() + self.assertTrue(not widget.isVisible()) + widget.setVisible(True) + self.assertTrue(widget.isVisible()) + self.assertTrue(widget.winId() != 0) + # skip this test on macOS since no native events are received + if sys.platform == 'darwin': + return + for i in range(10): + if widget.nativeEventCount > 0: + break + self.app.processEvents() + self.assertTrue(widget.nativeEventCount > 0) + + +if __name__ == '__main__': + unittest.main() diff --git a/sources/pyside6/tests/QtWidgets/reference_count_test.py b/sources/pyside6/tests/QtWidgets/reference_count_test.py new file mode 100644 index 000000000..b7d3908dd --- /dev/null +++ b/sources/pyside6/tests/QtWidgets/reference_count_test.py @@ -0,0 +1,84 @@ +# 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 Reference count when the object is created in c++ side''' + +import gc +import os +import sys +import unittest +import weakref + +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 Qt, QPointF +from PySide6.QtGui import QPolygonF +from PySide6.QtWidgets import QApplication, QGraphicsScene, QGraphicsRectItem, QGraphicsPolygonItem, QGraphicsRectItem + +from helper.usesqapplication import UsesQApplication + +destroyedRect = False +destroyedPol = False + + +def rect_del(o): + global destroyedRect + destroyedRect = True + + +def pol_del(o): + global destroyedPol + destroyedPol = True + + +class ReferenceCount(UsesQApplication): + + def setUp(self): + super(ReferenceCount, self).setUp() + self.scene = QGraphicsScene() + + def tearDown(self): + super(ReferenceCount, self).tearDown() + + @unittest.skipUnless(hasattr(sys, "getrefcount"), f"{sys.implementation.name} has no refcount") + def beforeTest(self): + points = [QPointF(0, 0), QPointF(100, 100), QPointF(0, 100)] + pol = self.scene.addPolygon(QPolygonF(points)) + self.assertTrue(isinstance(pol, QGraphicsPolygonItem)) + self.wrp = weakref.ref(pol, pol_del) + + # refcount need be 3 because one ref for QGraphicsScene, and one to rect obj + self.assertEqual(sys.getrefcount(pol), 3) + + @unittest.skipUnless(hasattr(sys, "getrefcount"), f"{sys.implementation.name} has no refcount") + def testReferenceCount(self): + global destroyedRect + global destroyedPol + + self.beforeTest() + + rect = self.scene.addRect(10.0, 10.0, 10.0, 10.0) + self.assertTrue(isinstance(rect, QGraphicsRectItem)) + + self.wrr = weakref.ref(rect, rect_del) + + # refcount need be 3 because one ref for QGraphicsScene, and one to rect obj + self.assertEqual(sys.getrefcount(rect), 3) + + del rect + # not destroyed because one ref continue in QGraphicsScene + self.assertEqual(destroyedRect, False) + self.assertEqual(destroyedPol, False) + + del self.scene + + # QGraphicsScene was destroyed and this destroy internal ref to rect + self.assertEqual(destroyedRect, True) + self.assertEqual(destroyedPol, True) + + +if __name__ == '__main__': + unittest.main() diff --git a/sources/pyside6/tests/QtWidgets/sample.png b/sources/pyside6/tests/QtWidgets/sample.png Binary files differnew file mode 100644 index 000000000..60450f0dc --- /dev/null +++ b/sources/pyside6/tests/QtWidgets/sample.png diff --git a/sources/pyside6/tests/QtWidgets/signature_test.py b/sources/pyside6/tests/QtWidgets/signature_test.py new file mode 100644 index 000000000..f156b6717 --- /dev/null +++ b/sources/pyside6/tests/QtWidgets/signature_test.py @@ -0,0 +1,59 @@ +# Copyright (C) 2022 The Qt Company Ltd. +# SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only + +import inspect +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) + +import PySide6.QtCore +import PySide6.QtWidgets +from PySide6.support.signature import get_signature + + +class PySideSignatureTest(unittest.TestCase): + def testSignatureExist(self): + t1 = type(get_signature(PySide6.QtCore.QObject.children)) + self.assertEqual(t1, inspect.Signature) + t2 = type(get_signature(PySide6.QtCore.QObject.__dict__["children"])) + self.assertEqual(t2, t1) + obj = PySide6.QtWidgets.QApplication.palette + t3 = type(get_signature(obj)) + self.assertEqual(t3, list) + self.assertEqual(len(get_signature(obj)), 3) + for thing in get_signature(obj): + self.assertEqual(type(thing), inspect.Signature) + sm = PySide6.QtWidgets.QApplication.__dict__["palette"] + # PYSIDE-1436: staticmethod is a callable since Python 3.10 + # Instead of checking callable(sm), we check the type: + self.assertEqual(type(sm), staticmethod) + self.assertTrue(get_signature(sm) is not None) + + def testSignatureIsCached(self): + # see if we get the same object + ob1 = get_signature(PySide6.QtCore.QObject.children) + ob2 = get_signature(PySide6.QtCore.QObject.children) + self.assertTrue(ob1 is ob2) + # same with multi signature + ob1 = get_signature(PySide6.QtWidgets.QApplication.palette) + ob2 = get_signature(PySide6.QtWidgets.QApplication.palette) + self.assertTrue(ob1 is ob2) + + def testModuleIsInitialized(self): + self.assertTrue(get_signature(PySide6.QtWidgets.QApplication) is not None) + + def test_NotCalled_is_callable_and_correct(self): + # A signature that has a default value with some "Default(...)" + # wrapper is callable and creates an object of the right type. + sig = get_signature(PySide6.QtCore.QByteArray().toPercentEncoding) + called_default = sig.parameters["exclude"].default() + self.assertEqual(type(called_default), PySide6.QtCore.QByteArray) + + +if __name__ == "__main__": + unittest.main() diff --git a/sources/pyside6/tests/QtWidgets/standardpixmap_test.py b/sources/pyside6/tests/QtWidgets/standardpixmap_test.py new file mode 100644 index 000000000..564f3ff2e --- /dev/null +++ b/sources/pyside6/tests/QtWidgets/standardpixmap_test.py @@ -0,0 +1,27 @@ +# Copyright (C) 2022 The Qt Company Ltd. +# SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0 + +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.QtGui import QPixmap +from PySide6.QtWidgets import QStyle + +from helper.usesqapplication import UsesQApplication + + +class StandardPixmapTest(UsesQApplication): + def testDefaultOptions(self): # Bug 253 + pixmap = self.app.style().standardPixmap(QStyle.SP_DirClosedIcon) + self.assertTrue(isinstance(pixmap, QPixmap)) + + +if __name__ == '__main__': + unittest.main() + diff --git a/sources/pyside6/tests/QtWidgets/test_module_template.py b/sources/pyside6/tests/QtWidgets/test_module_template.py new file mode 100644 index 000000000..92661cdff --- /dev/null +++ b/sources/pyside6/tests/QtWidgets/test_module_template.py @@ -0,0 +1,27 @@ +# Copyright (C) 2022 The Qt Company Ltd. +# SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0 + +import os +import sys + +from pathlib import Path +sys.path.append(os.fspath(Path(__file__).resolve().parents[1])) +sys.path.append(os.fspath(Path(__file__).resolve().parents[1] / "util")) +from init_paths import init_test_paths +init_test_paths() + +from PySide6.QtWidgets import QWidget +from PySide6.QtCore import QObject + + +class MyQObject(QObject): + pass + + +class MyQWidget(QWidget): + pass + + +class Sentinel(): + value = 10 + diff --git a/sources/pyside6/tests/QtWidgets/virtual_protected_inheritance_test.py b/sources/pyside6/tests/QtWidgets/virtual_protected_inheritance_test.py new file mode 100644 index 000000000..911fed475 --- /dev/null +++ b/sources/pyside6/tests/QtWidgets/virtual_protected_inheritance_test.py @@ -0,0 +1,84 @@ +# 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 overriding inherited protected virtual methods''' + +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 QTimerEvent +from PySide6.QtWidgets import QApplication, QSpinBox + +from helper.usesqapplication import UsesQApplication + + +class MySpinButton(QSpinBox): + '''Simple example class of overriding QObject.timerEvent''' + + def __init__(self, max_runs=5, app=None): + # Creates a new spinbox that will run <max_runs> and quit <app> + super().__init__() + + if app is None: + app = QApplication([]) + + self.app = app + self.max_runs = max_runs + self.runs = 0 + + def timerEvent(self, event): + # Timer event method + self.runs += 1 + + self.setValue(self.runs) + + if self.runs == self.max_runs: + self.app.quit() + + if not isinstance(event, QTimerEvent): + raise TypeError('Invalid event type. Must be TimerEvent') + + +class TimerEventTest(UsesQApplication): + '''Test case for running QObject.timerEvent from inherited class''' + + qapplication = True + + def setUp(self): + # Acquire resources + super(TimerEventTest, self).setUp() + self.widget = MySpinButton(app=self.app) + + def tearDown(self): + # Release resources + del self.widget + # PYSIDE-535: Need to collect garbage in PyPy to trigger deletion + gc.collect() + super(TimerEventTest, self).tearDown() + + def testMethod(self): + # QWidget.timerEvent overrinding (protected inherited) + timer_id = self.widget.startTimer(0) + + self.app.exec() + + self.widget.killTimer(timer_id) + + self.assertTrue(self.widget.runs >= self.widget.max_runs) + + +if __name__ == '__main__': + unittest.main() + #app = QApplication([]) + #widget = MySpinButton(app=app) + #widget.startTimer(500) + #widget.show() + #app.exec() + diff --git a/sources/pyside6/tests/QtWidgets/virtual_pure_override_test.py b/sources/pyside6/tests/QtWidgets/virtual_pure_override_test.py new file mode 100644 index 000000000..b7d1e4f3f --- /dev/null +++ b/sources/pyside6/tests/QtWidgets/virtual_pure_override_test.py @@ -0,0 +1,61 @@ +#!/usr/bin/python +# Copyright (C) 2022 The Qt Company Ltd. +# SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0 + +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.QtWidgets import QGraphicsScene, QGraphicsRectItem, QGraphicsView, QApplication +from PySide6.QtGui import QBrush, QColor +from PySide6.QtCore import QTimer +from helper.usesqapplication import UsesQApplication + +qgraphics_item_painted = False + + +class RoundRectItem(QGraphicsRectItem): + + def __init__(self, x, y, w, h): + QGraphicsRectItem.__init__(self, x, y, w, h) + + def paint(self, painter, qstyleoptiongraphicsitem, qwidget): + global qgraphics_item_painted + qgraphics_item_painted = True + view = self.scene().views()[0] + QTimer.singleShot(20, view.close) + + +class QGraphicsItemTest(UsesQApplication): + + def createRoundRect(self, scene): + item = RoundRectItem(10, 10, 100, 100) + item.setBrush(QBrush(QColor(255, 0, 0))) + scene.addItem(item) + return item + + def quit_app(self): + self.app.quit() + + def test_setParentItem(self): + global qgraphics_item_painted + + scene = QGraphicsScene() + scene.addText("test") + view = QGraphicsView(scene) + view.setWindowTitle("virtual_pure_override_test") + + rect = self.createRoundRect(scene) + view.show() + self.app.exec() + self.assertTrue(qgraphics_item_painted) + + +if __name__ == '__main__': + unittest.main() + diff --git a/sources/pyside6/tests/QtWidgets/wrong_return_test.py b/sources/pyside6/tests/QtWidgets/wrong_return_test.py new file mode 100644 index 000000000..009078ac1 --- /dev/null +++ b/sources/pyside6/tests/QtWidgets/wrong_return_test.py @@ -0,0 +1,39 @@ +# 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 Virtual functions with wrong return type''' + +import os +import sys +import unittest +import warnings + +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.QtWidgets import QWidget +from helper.usesqapplication import UsesQApplication + + +warnings.simplefilter('error') + + +class MyWidget(QWidget): + def __init__(self, parent=None): + super().__init__(parent) + + def sizeHint(self): + pass + + +class testCase(UsesQApplication): + + def testVirtualReturn(self): + w = MyWidget() + self.assertWarns(RuntimeWarning, w.show) + + +if __name__ == '__main__': + unittest.main() |