diff options
Diffstat (limited to 'sources/pyside6/tests/pysidetest')
26 files changed, 477 insertions, 61 deletions
diff --git a/sources/pyside6/tests/pysidetest/CMakeLists.txt b/sources/pyside6/tests/pysidetest/CMakeLists.txt index 76a8e02f5..38f42f342 100644 --- a/sources/pyside6/tests/pysidetest/CMakeLists.txt +++ b/sources/pyside6/tests/pysidetest/CMakeLists.txt @@ -1,3 +1,6 @@ +# Copyright (C) 2023 The Qt Company Ltd. +# SPDX-License-Identifier: BSD-3-Clause + project(pysidetest) project(testbinding) @@ -17,12 +20,15 @@ add_definitions(-DRXX_ALLOCATOR_INIT_0) find_package(Qt6 REQUIRED COMPONENTS Widgets) set(pysidetest_SRC -containertest.cpp -flagstest.cpp -testobject.cpp -testview.cpp -hiddenobject.cpp -sharedpointertestbench.cpp +containertest.cpp containertest.h +flagstest.cpp flagstest.h +hiddenobject.cpp hiddenobject.h +pysidetest_global.h +pysidetest_macros.h +sharedpointertestbench.cpp sharedpointertestbench.h +testobject.cpp testobject.h +testview.cpp testview.h +testqvariantenum.cpp testqvariantenum.h ) set(testbinding_SRC @@ -39,6 +45,8 @@ ${CMAKE_CURRENT_BINARY_DIR}/testbinding/qsharedpointer_int_wrapper.cpp ${CMAKE_CURRENT_BINARY_DIR}/testbinding/sharedpointertestbench_wrapper.cpp ${CMAKE_CURRENT_BINARY_DIR}/testbinding/testview_wrapper.cpp ${CMAKE_CURRENT_BINARY_DIR}/testbinding/testbinding_module_wrapper.cpp +${CMAKE_CURRENT_BINARY_DIR}/testbinding/testqvariantenum_wrapper.cpp +${CMAKE_CURRENT_BINARY_DIR}/testbinding/qvariantholder_wrapper.cpp ) # Get per module include dirs. @@ -140,6 +148,7 @@ PYSIDE_TEST(iterable_test.py) PYSIDE_TEST(list_signal_test.py) PYSIDE_TEST(mixin_signal_slots_test.py) PYSIDE_TEST(modelview_test.py) +PYSIDE_TEST(multiple_inheritance_test.py) PYSIDE_TEST(new_inherited_functions_test.py) PYSIDE_TEST(notify_id.py) PYSIDE_TEST(properties_test.py) diff --git a/sources/pyside6/tests/pysidetest/constructor_properties_test.py b/sources/pyside6/tests/pysidetest/constructor_properties_test.py index 9f1a9d43c..ec6e39821 100644 --- a/sources/pyside6/tests/pysidetest/constructor_properties_test.py +++ b/sources/pyside6/tests/pysidetest/constructor_properties_test.py @@ -36,7 +36,7 @@ class ConstructorPropertiesTest(unittest.TestCase): def testCallConstructor(self): label = QLabel( frameStyle=QFrame.Panel | QFrame.Sunken, # QFrame attr, no property - lineWidth = 2, # QFrame property + lineWidth=2, # QFrame property text="first line\nsecond line", # QLabel property alignment=Qt.AlignBottom | Qt.AlignRight # QLabel property ) @@ -52,13 +52,13 @@ class ConstructorPropertiesTest(unittest.TestCase): label = QLabel( frame_style=QFrame.Panel | QFrame.Sunken, # QFrame attr, no property - line_width = 2, # QFrame property + line_width=2, # QFrame property text="first line\nsecond line", # QLabel property alignment=Qt.AlignBottom | Qt.AlignRight # QLabel property ) self.assertEqual(label.line_width(), 2) self.assertRaises(AttributeError, lambda: QLabel( - lineWidth = 2, # QFrame property + lineWidth=2, # QFrame property )) # PYSIDE-1705: The same with true_property @@ -68,13 +68,13 @@ class ConstructorPropertiesTest(unittest.TestCase): label = QLabel( frameStyle=QFrame.Panel | QFrame.Sunken, # QFrame attr, no property - lineWidth = 2, # QFrame property + lineWidth=2, # QFrame property text="first line\nsecond line", # QLabel property alignment=Qt.AlignBottom | Qt.AlignRight # QLabel property ) self.assertEqual(label.lineWidth, 2) self.assertRaises(AttributeError, lambda: QLabel( - line_width = 2, # QFrame property + line_width=2, # QFrame property )) # PYSIDE-1705: The same with snake_case and true_property @@ -84,13 +84,13 @@ class ConstructorPropertiesTest(unittest.TestCase): label = QLabel( frame_style=QFrame.Panel | QFrame.Sunken, # QFrame attr, no property - line_width = 2, # QFrame property + line_width=2, # QFrame property text="first line\nsecond line", # QLabel property alignment=Qt.AlignBottom | Qt.AlignRight # QLabel property ) self.assertEqual(label.line_width, 2) self.assertRaises(AttributeError, lambda: QLabel( - lineWidth = 2, # QFrame property + lineWidth=2, # QFrame property )) diff --git a/sources/pyside6/tests/pysidetest/container_test.py b/sources/pyside6/tests/pysidetest/container_test.py index 68c3638cd..c83e1f26c 100644 --- a/sources/pyside6/tests/pysidetest/container_test.py +++ b/sources/pyside6/tests/pysidetest/container_test.py @@ -44,13 +44,13 @@ class ContainerTestTest(unittest.TestCase): self.assertEqual(sort_values(m2), EXPECTED_DICT) def testList(self): - l1 = ContainerTest.createList(); + l1 = ContainerTest.createList() self.assertEqual(l1, EXPECTED_LIST) l2 = ContainerTest.passThroughList(l1) self.assertEqual(l2, EXPECTED_LIST) def testSet(self): - s1 = ContainerTest.createSet(); # Order is not predictable + s1 = ContainerTest.createSet() # Order is not predictable s2 = ContainerTest.passThroughSet(s1) self.assertEqual(sorted(list(s1)), sorted(list(s2))) diff --git a/sources/pyside6/tests/pysidetest/enum_test.py b/sources/pyside6/tests/pysidetest/enum_test.py index 158faf37c..832834530 100644 --- a/sources/pyside6/tests/pysidetest/enum_test.py +++ b/sources/pyside6/tests/pysidetest/enum_test.py @@ -15,6 +15,7 @@ from testbinding import Enum1, TestObjectWithoutNamespace import dis + class ListConnectionTest(unittest.TestCase): def testEnumVisibility(self): @@ -45,6 +46,7 @@ class ListConnectionTest(unittest.TestCase): self.assertFalse(Qt.AlignBottom < Qt.AlignHCenter) self.assertTrue(Qt.AlignBottom > Qt.AlignHCenter) + # PYSIDE-1735: We are testing that opcodes do what they are supposed to do. # This is needed in the PyEnum forgiveness mode where we need # to introspect the code if an Enum was called with no args. @@ -68,7 +70,11 @@ class InvestigateOpcodesTest(unittest.TestCase): res.append((ops[idx - 1][0], ops[idx][1] - ops[idx - 1][1])) return sorted(res, key=lambda x: (x[1], x[0])) + _sin = sys.implementation.name + + @unittest.skipIf(hasattr(sys.flags, "nogil"), f"{_sin} has different opcodes") def testByteCode(self): + import dis # opname, opcode, arg result_1 = [('LOAD_GLOBAL', 116, 0), ('LOAD_ATTR', 106, 1), @@ -92,7 +98,7 @@ class InvestigateOpcodesTest(unittest.TestCase): ('LOAD_CONST', 100, 0), ('RETURN_VALUE', 83, None)] - if sys.version_info[:2] >= (3, 11): + if sys.version_info[:2] == (3, 11): # Note: Python 3.11 is a bit more complex because it can optimize itself. # Opcodes are a bit different, and a hidden second code object is used. # We investigate this a bit, because we want to be warned when things change. @@ -131,7 +137,7 @@ class InvestigateOpcodesTest(unittest.TestCase): for _ in range(times): f() - code_quicken(self.probe_function2, QUICKENING_WARMUP_DELAY-1) + code_quicken(self.probe_function2, QUICKENING_WARMUP_DELAY - 1) self.assertEqual(self.read_code(self.probe_function2, adaptive=True), result_2) self.assertEqual(self.get_sizes(self.probe_function2, adaptive=True), sizes_2) @@ -156,6 +162,21 @@ class InvestigateOpcodesTest(unittest.TestCase): self.assertEqual(self.read_code(self.probe_function2, adaptive=True), result_3) self.assertEqual(self.get_sizes(self.probe_function2, adaptive=True), sizes_3) + if sys.version_info[:2] >= (3, 12): + + result_1 = [('RESUME', 151, 0), + ('LOAD_GLOBAL', 116, 0), + ('LOAD_ATTR', 106, 2), + ('STORE_FAST', 125, 1), + ('RETURN_CONST', 121, 0)] + + result_2 = [('RESUME', 151, 0), + ('LOAD_GLOBAL', 116, 1), + ('LOAD_ATTR', 106, 2), + ('CALL', 171, 0), + ('STORE_FAST', 125, 1), + ('RETURN_CONST', 121, 0)] + self.assertEqual(self.read_code(self.probe_function1), result_1) self.assertEqual(self.read_code(self.probe_function2), result_2) diff --git a/sources/pyside6/tests/pysidetest/flagstest.h b/sources/pyside6/tests/pysidetest/flagstest.h index 9058561f6..b5c73c9bd 100644 --- a/sources/pyside6/tests/pysidetest/flagstest.h +++ b/sources/pyside6/tests/pysidetest/flagstest.h @@ -23,8 +23,10 @@ class PYSIDETEST_API ClassForEnum : public QObject { Q_OBJECT public: + Q_DISABLE_COPY_MOVE(ClassForEnum) + ClassForEnum(FlagsNamespace::Options opt = FlagsNamespace::Option::NoOptions); - virtual ~ClassForEnum(); + virtual ~ClassForEnum() override; }; } // namespace FlagsNamespace diff --git a/sources/pyside6/tests/pysidetest/hiddenobject.cpp b/sources/pyside6/tests/pysidetest/hiddenobject.cpp index bba0de2ee..d4feabb66 100644 --- a/sources/pyside6/tests/pysidetest/hiddenobject.cpp +++ b/sources/pyside6/tests/pysidetest/hiddenobject.cpp @@ -8,7 +8,7 @@ void HiddenObject::callMe() m_called = true; } -bool HiddenObject::wasCalled() +bool HiddenObject::wasCalled() const { return m_called; } diff --git a/sources/pyside6/tests/pysidetest/hiddenobject.h b/sources/pyside6/tests/pysidetest/hiddenobject.h index e3d0abbef..f399be985 100644 --- a/sources/pyside6/tests/pysidetest/hiddenobject.h +++ b/sources/pyside6/tests/pysidetest/hiddenobject.h @@ -13,12 +13,12 @@ class HiddenObject : public QObject { Q_OBJECT public: - HiddenObject() : m_called(false) {} + HiddenObject() noexcept = default; Q_INVOKABLE void callMe(); public Q_SLOTS: - bool wasCalled(); + bool wasCalled() const; private: - bool m_called; + bool m_called = false; }; // Return a instance of HiddenObject diff --git a/sources/pyside6/tests/pysidetest/homonymoussignalandmethod_test.py b/sources/pyside6/tests/pysidetest/homonymoussignalandmethod_test.py index 52c65e541..b58232a1b 100644 --- a/sources/pyside6/tests/pysidetest/homonymoussignalandmethod_test.py +++ b/sources/pyside6/tests/pysidetest/homonymoussignalandmethod_test.py @@ -99,8 +99,8 @@ class HomonymousMultipleInheritanceTest(unittest.TestCase): def testHomonymousMultipleInheritance(self): c = C() - self.assertEqual(c.method(), "M::method") # okay - self.assertEqual(c.signal(), "M::signal") # problem on PySide6 6.2.2 + self.assertEqual(c.method(), "M::method") # okay + self.assertEqual(c.signal(), "M::signal") # problem on PySide6 6.2.2 self.assertEqual(type(c.signal), SignalInstance) diff --git a/sources/pyside6/tests/pysidetest/multiple_inheritance_test.py b/sources/pyside6/tests/pysidetest/multiple_inheritance_test.py new file mode 100644 index 000000000..49550ba55 --- /dev/null +++ b/sources/pyside6/tests/pysidetest/multiple_inheritance_test.py @@ -0,0 +1,189 @@ +# Copyright (C) 2023 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 import QtCore, QtGui, QtWidgets +from PySide6.QtWidgets import QMainWindow, QLabel, QWidget + + +def xprint(*args, **kw): + if "-v" in sys.argv: + print(*args, **kw) + + +# This is the original testcase of PYSIDE-1564 +class Age(object): + def __init__(self, age=0, **kwds): + super().__init__(**kwds) + + self.age = age + + +class Person(QtCore.QObject, Age): + def __init__(self, name, **kwds): + super().__init__(**kwds) + + self.name = name + + +class OriginalMultipleInheritanceTest(unittest.TestCase): + + def testIt(self): + xprint() + p = Person("Joe", age=38) + xprint(f"p.age = {p.age}") + # This would crash if MI does not work. + +# More tests follow: + + +# mro ('C', 'A', 'QObject', 'Object', 'B', 'object') +class A(QtCore.QObject): + def __init__(self, anna=77, **kw): + xprint(f'A: before init kw = {kw}') + super().__init__(**kw) + xprint('A: after init') + + +class B: + def __init__(self, otto=6, age=7, **kw): + xprint(f'B: before init kw = {kw}') + if "killme" in kw: + raise AssertionError("asdf") + super().__init__(**kw) + self.age = age + xprint('B: after init') + + +class C(A, B): + def __init__(self, **kw): + xprint(f'C: before init kw = {kw}') + super().__init__(**kw) + xprint('C: after init') + + +# mro ('F', 'D', 'QCursor', 'E', 'QLabel', 'QFrame', 'QWidget', 'QObject', +# 'QPaintDevice', 'Object', 'object') +class D(QtGui.QCursor): + def __init__(self, anna=77, **kw): + xprint(f'D: before init kw = {kw}') + super().__init__(**kw) + xprint('D: after init') + + +class E: + def __init__(self, age=7, **kw): + xprint(f'E: before init kw = {kw}') + super().__init__(**kw) + self.age = age + xprint('E: after init') + + +class F(D, E, QtWidgets.QLabel): + def __init__(self, **kw): + xprint(f'F: before init kw = {kw}') + super().__init__(**kw) + xprint('F: after init') + + +# mro ('I', 'G', 'QTextDocument', 'H', 'QLabel', 'QFrame', 'QWidget', 'QObject', +# 'QPaintDevice', 'Object', 'object') +# Similar, but this time we want to reach `H` without support from `super`. +class G(QtGui.QTextDocument): + pass + + +class H: + def __init__(self, age=7, **kw): + xprint(f'H: before init kw = {kw}') + super().__init__(**kw) + self.age = age + xprint('H: after init') + + +class II(G, H, QtWidgets.QLabel): + pass + + +# PYSIDE-2294: Friedemann's test adapted. +# We need to ignore positional args in mixin classes. +class Ui_X_MainWindow(object): # Emulating uic + def setupUi(self, MainWindow): + MainWindow.resize(400, 300) + self.lbl = QLabel(self) + + +class MainWindow(QMainWindow, Ui_X_MainWindow): + def __init__(self, parent=None): + super().__init__(parent) + self.setupUi(self) + + +class AdditionalMultipleInheritanceTest(UsesQApplication): + + def testABC(self): + xprint() + res = C(otto=3, anna=5) + self.assertEqual(res.age, 7) + xprint() + with self.assertRaises(AssertionError): + res = C(killme=42) + xprint() + + def testDEF(self): + xprint() + res = F(anna=5) + self.assertEqual(res.age, 7) + xprint() + + def testGHI(self): + xprint() + res = II(age=7) + self.assertEqual(res.age, 7) + xprint() + + def testParentDoesNotCrash(self): + # This crashed with + # TypeError: object.__init__() takes exactly one argument (the instance to initialize) + MainWindow() + + +# PYSIDE-2654: Additional missing init test. +# This must work if no __init__ is defined (Ui_Form) +class Ui_Form(object): + pass + + +class Mixin: + def __init__(self, **kwargs) -> None: + super().__init__(**kwargs) + + +class Card(Mixin, QWidget): + def __init__(self, parent=None) -> None: + super().__init__(parent=parent) + + +class Demo(Card, Ui_Form): + def __init__(self) -> None: + super().__init__() + + +class MissingInitFunctionTest(UsesQApplication): + def testMissing(self): + Demo() + # Tests if this works. Would crash without the extra + # check for object.__init__ + + +if __name__ == "__main__": + unittest.main() diff --git a/sources/pyside6/tests/pysidetest/pyenum_relax_options_test.py b/sources/pyside6/tests/pysidetest/pyenum_relax_options_test.py index 0dcec5a4c..625f9cdc5 100644 --- a/sources/pyside6/tests/pysidetest/pyenum_relax_options_test.py +++ b/sources/pyside6/tests/pysidetest/pyenum_relax_options_test.py @@ -49,46 +49,52 @@ def runtest(program): finally: os.unlink(fp.name) + def testprog2(option): return runtest(dedent(f""" - sys.pyside63_option_python_enum = {option} + sys.pyside6_option_python_enum = {option} from PySide6 import QtCore from enum import IntEnum assert(issubclass(QtCore.Qt.DateFormat, IntEnum)) """)) + def testprog4(option): return runtest(dedent(f""" - sys.pyside63_option_python_enum = {option} + sys.pyside6_option_python_enum = {option} from PySide6 import QtCore QtCore.QtDebugMsg """)) + def testprog8_16(option): # this test needs flag 16, or the effect would be hidden by forgiving mode return runtest(dedent(f""" - sys.pyside63_option_python_enum = {option} + sys.pyside6_option_python_enum = {option} from PySide6 import QtCore QtCore.Qt.AlignTop """)) + def testprog32(option): return runtest(dedent(f""" - sys.pyside63_option_python_enum = {option} + sys.pyside6_option_python_enum = {option} from PySide6 import QtCore QtCore.Qt.Alignment """)) + def testprog64(option): return runtest(dedent(f""" - sys.pyside63_option_python_enum = {option} + sys.pyside6_option_python_enum = {option} from PySide6 import QtCore QtCore.Qt.AlignmentFlag() """)) + def testprog128(option): return runtest(dedent(f""" - sys.pyside63_option_python_enum = {option} + sys.pyside6_option_python_enum = {option} from PySide6 import QtCore QtCore.Qt.Key(1234567) """)) @@ -110,8 +116,8 @@ class TestPyEnumRelaxOption(unittest.TestCase): self.assertTrue(testprog4(12)) def test_localDefault(self): - self.assertTrue(testprog8_16(8+16)) - self.assertFalse(testprog8_16(0+16)) + self.assertTrue(testprog8_16(8 + 16)) + self.assertFalse(testprog8_16(0 + 16)) def test_fakeRenames(self): self.assertTrue(testprog32(1)) diff --git a/sources/pyside6/tests/pysidetest/pysidetest_global.h b/sources/pyside6/tests/pysidetest/pysidetest_global.h index 461b6f56f..6f784dc58 100644 --- a/sources/pyside6/tests/pysidetest/pysidetest_global.h +++ b/sources/pyside6/tests/pysidetest/pysidetest_global.h @@ -11,5 +11,6 @@ #include "flagstest.h" #include "hiddenobject.h" #include "sharedpointertestbench.h" +#include "testqvariantenum.h" #endif // PYSIDETEST_GLOBAL_H diff --git a/sources/pyside6/tests/pysidetest/qvariant_test.py b/sources/pyside6/tests/pysidetest/qvariant_test.py index 5addb00e0..faefc8169 100644 --- a/sources/pyside6/tests/pysidetest/qvariant_test.py +++ b/sources/pyside6/tests/pysidetest/qvariant_test.py @@ -1,6 +1,7 @@ # 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 enum import os import sys import unittest @@ -10,13 +11,25 @@ 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 testbinding import TestObject, TestQVariantEnum from PySide6.QtCore import Qt, QKeyCombination from PySide6.QtGui import QKeySequence, QAction from helper.usesqapplication import UsesQApplication +class PyTestQVariantEnum(TestQVariantEnum): + def __init__(self, var_enum): + super().__init__(var_enum) + + def getRValEnum(self): + return Qt.Orientation.Vertical + + def channelingEnum(self, rval_enum): + return (isinstance(rval_enum, enum.Enum) + and rval_enum == Qt.Orientation.Vertical) + + class QVariantTest(UsesQApplication): def testQKeySequenceQVariantOperator(self): @@ -24,16 +37,30 @@ class QVariantTest(UsesQApplication): ks = QKeySequence(Qt.ShiftModifier, Qt.ControlModifier, Qt.Key_P, Qt.Key_R) self.assertEqual(TestObject.checkType(ks), 4107) - # PYSIDE-1735: Test the new way to address QKeyCombination after moving IntEnum to Enum - @unittest.skipUnless(sys.pyside63_option_python_enum, "only implemented for new enums") def testQKeySequenceMoreVariations(self): QAction().setShortcut(Qt.CTRL | Qt.Key_B) QAction().setShortcut(Qt.CTRL | Qt.ALT | Qt.Key_B) QAction().setShortcut(Qt.CTRL | Qt.AltModifier | Qt.Key_B) QAction().setShortcut(QKeySequence(QKeyCombination(Qt.CTRL | Qt.Key_B))) QKeySequence(Qt.CTRL | Qt.Key_Q) - # Issues a warning but works as well - QKeySequence(Qt.CTRL + Qt.Key_Q) + + def testEnum(self): + # Testing C++ class + testqvariant = TestQVariantEnum(Qt.CheckState.Checked) + self.assertEqual(testqvariant.getLValEnum(), Qt.CheckState.Checked) + self.assertIsInstance(testqvariant.getLValEnum(), enum.Enum) + # in the case where we return a QVariant of C++ enum, it returns a + # QVariant(int) to Python unless explicitly handled manually by Shiboken + self.assertEqual(testqvariant.getRValEnum(), 1) + self.assertEqual(testqvariant.isEnumChanneled(), False) + + # Testing Python child class + pytestqvariant = PyTestQVariantEnum(Qt.CheckState.Checked) + self.assertEqual(pytestqvariant.isEnumChanneled(), True) + # check toInt() conversion works for PyObjectWrapper + self.assertEqual(PyTestQVariantEnum.getNumberFromQVarEnum(Qt.Orientation.Vertical), 2) + # check toInt() conversion for IntEnum + self.assertEqual(PyTestQVariantEnum.getNumberFromQVarEnum(Qt.GestureType.TapGesture), 1) if __name__ == '__main__': diff --git a/sources/pyside6/tests/pysidetest/repr_test.py b/sources/pyside6/tests/pysidetest/repr_test.py index 01cc36b37..863f17657 100644 --- a/sources/pyside6/tests/pysidetest/repr_test.py +++ b/sources/pyside6/tests/pysidetest/repr_test.py @@ -49,6 +49,15 @@ class QObjectDerivedReprTest(unittest.TestCase): # __repr__ should use the operator<<(QDebug,...) implementation self.assertEqual(str(t), "TestObject2WithNamespace(injected_repr)") + def testLatin1StringField(self): + self.assertEqual(TestObject.LATIN1_TEST_FIELD, "test") + + def testLatin1Setter(self): + to = TestObject(123) + value = "test" + to.setQLatin1String(value) + self.assertEqual(to.qLatin1String(), value) + if __name__ == '__main__': unittest.main() diff --git a/sources/pyside6/tests/pysidetest/signalinstance_equality_test.py b/sources/pyside6/tests/pysidetest/signalinstance_equality_test.py index 732420c4d..5faaa38d4 100644 --- a/sources/pyside6/tests/pysidetest/signalinstance_equality_test.py +++ b/sources/pyside6/tests/pysidetest/signalinstance_equality_test.py @@ -12,7 +12,7 @@ init_test_paths(False) from helper.usesqapplication import UsesQApplication -from PySide6.QtCore import QFile, QObject, QTimer, Signal, Slot +from PySide6.QtCore import QFile, QObject, QTimer, Signal, SignalInstance, Slot from PySide6.QtWidgets import QSlider @@ -41,6 +41,17 @@ class TestSignalInstance(unittest.TestCase): o = D() self.assertTrue(o.custom_signal == o.custom_signal) + # additional tests of old errors from 2010 or so + def test_uninitialized_SignalInstance(self): + # This will no longer crash + print(SignalInstance()) + with self.assertRaises(RuntimeError): + SignalInstance().connect(lambda: None) + with self.assertRaises(RuntimeError): + SignalInstance().disconnect() + with self.assertRaises(RuntimeError): + SignalInstance().emit() + class MyWidget(QSlider): valueChanged = Signal(tuple) diff --git a/sources/pyside6/tests/pysidetest/signalwithdefaultvalue_test.py b/sources/pyside6/tests/pysidetest/signalwithdefaultvalue_test.py index cf09b2964..744b8c503 100644 --- a/sources/pyside6/tests/pysidetest/signalwithdefaultvalue_test.py +++ b/sources/pyside6/tests/pysidetest/signalwithdefaultvalue_test.py @@ -13,7 +13,7 @@ from init_paths import init_test_paths init_test_paths(True) from testbinding import TestObject -from PySide6.QtCore import QObject, SIGNAL +from PySide6.QtCore import Qt '''Tests the behaviour of signals with default values.''' @@ -56,6 +56,17 @@ class SignalWithDefaultValueTest(unittest.TestCase): self.assertTrue(self.void_called) self.assertTrue(self.bool_called) + def testFlagsSignal(self): + test_value = Qt.AlignmentFlag.AlignLeft | Qt.AlignmentFlag.AlignBottom + + def callbackAlignmentFlags(alignment): + self.alignment_flags_called = alignment + + self.obj.flagsSignal.connect(callbackAlignmentFlags) + self.obj.emitFlagsSignal(test_value) + self.assertTrue(self.alignment_flags_called) + self.assertEqual(self.alignment_flags_called, test_value) + def testConnectOldStyleEmitVoidSignal(self): def callbackVoid(): self.void_called = True @@ -83,4 +94,3 @@ class SignalWithDefaultValueTest(unittest.TestCase): if __name__ == '__main__': unittest.main() - diff --git a/sources/pyside6/tests/pysidetest/snake_case_sub.py b/sources/pyside6/tests/pysidetest/snake_case_sub.py index 5056d50bb..4a482c35a 100644 --- a/sources/pyside6/tests/pysidetest/snake_case_sub.py +++ b/sources/pyside6/tests/pysidetest/snake_case_sub.py @@ -16,6 +16,7 @@ PYSIDE-2029: Tests that snake_case is isolated from imported modules from PySide6.QtWidgets import QWidget + def test_no_snake_case(): print(__name__) widget = QWidget() diff --git a/sources/pyside6/tests/pysidetest/snake_case_test.py b/sources/pyside6/tests/pysidetest/snake_case_test.py index aaa3d3f2a..14e035773 100644 --- a/sources/pyside6/tests/pysidetest/snake_case_test.py +++ b/sources/pyside6/tests/pysidetest/snake_case_test.py @@ -13,14 +13,17 @@ init_test_paths(False) """ PYSIDE-2029: Tests that snake_case is isolated from imported modules """ +is_pypy = hasattr(sys, "pypy_version_info") from PySide6.QtCore import QSize from PySide6.QtWidgets import QWidget, QSpinBox -from __feature__ import snake_case +if not is_pypy: + from __feature__ import snake_case from helper.usesqapplication import UsesQApplication import snake_case_sub +@unittest.skipIf(is_pypy, "__feature__ cannot yet be used with PyPy") class SnakeCaseNoPropagateTest(UsesQApplication): def testSnakeCase(self): @@ -30,5 +33,6 @@ class SnakeCaseNoPropagateTest(UsesQApplication): snake_case_sub.test_no_snake_case() + if __name__ == '__main__': unittest.main() diff --git a/sources/pyside6/tests/pysidetest/testobject.cpp b/sources/pyside6/tests/pysidetest/testobject.cpp index 2233bad62..fe4ec98f7 100644 --- a/sources/pyside6/tests/pysidetest/testobject.cpp +++ b/sources/pyside6/tests/pysidetest/testobject.cpp @@ -30,6 +30,26 @@ void TestObject::emitSignalWithTypedefValue(int value) emit signalWithTypedefValue(TypedefValue(value)); } +void TestObject::emitSignalWithContainerTypedefValue(const IntList &il) +{ + emit signalWithContainerTypedefValue(il); +} + +void TestObject::emitFlagsSignal(Qt::Alignment alignment) +{ + emit flagsSignal(alignment); +} + +void TestObject::setQLatin1String(QLatin1String v) +{ + m_qLatin1String = v; +} + +QString TestObject::qLatin1String() const +{ + return m_qLatin1String; +} + QDebug operator<<(QDebug dbg, TestObject& testObject) { QDebugStateSaver saver(dbg); diff --git a/sources/pyside6/tests/pysidetest/testobject.h b/sources/pyside6/tests/pysidetest/testobject.h index 88652bcca..a095a382e 100644 --- a/sources/pyside6/tests/pysidetest/testobject.h +++ b/sources/pyside6/tests/pysidetest/testobject.h @@ -8,12 +8,15 @@ #include <QtWidgets/QApplication> +#include <QtCore/QList> #include <QtCore/QObject> #include <QtCore/QMetaType> #include <QtCore/QVariant> QT_FORWARD_DECLARE_CLASS(QDebug) +using IntList = QList<int>; + class IntValue { public: @@ -23,16 +26,16 @@ public: int value; }; -typedef IntValue TypedefValue; +using TypedefValue = IntValue; class PYSIDETEST_API TestObject : public QObject { Q_OBJECT public: - static void createApp() { int argc=0; new QApplication(argc, 0); }; + static void createApp() { int argc=0; new QApplication(argc, nullptr); }; static int checkType(const QVariant& var) { return var.metaType().id(); } - TestObject(int idValue, QObject* parent = 0) : QObject(parent), m_idValue(idValue) {} + TestObject(int idValue, QObject* parent = nullptr) : QObject(parent), m_idValue(idValue) {} int idValue() const { return m_idValue; } static int staticMethodDouble(int value) { return value * 2; } void addChild(QObject* c) { m_children.append(c); emit childrenChanged(m_children); } @@ -44,6 +47,14 @@ public: void emitSignalWithDefaultValue_bool(); void emitSignalWithTypedefValue(int value); + void emitSignalWithContainerTypedefValue(const IntList &il); + + void emitFlagsSignal(Qt::Alignment alignment); + + static constexpr auto LATIN1_TEST_FIELD = QLatin1StringView("test"); + + void setQLatin1String(QLatin1String v); + QString qLatin1String() const; signals: void idValue(int newValue); @@ -52,16 +63,18 @@ signals: void childrenChanged(const QList<QObject*>&); void signalWithDefaultValue(bool value = false); void signalWithTypedefValue(TypedefValue value); + void signalWithContainerTypedefValue(const IntList &il); + void flagsSignal(Qt::Alignment alignment); private: int m_idValue; QList<QObject*> m_children; + QString m_qLatin1String; }; PYSIDETEST_API QDebug operator<<(QDebug dbg, TestObject &testObject); -typedef int PySideInt; - +using PySideInt = int; namespace PySideCPP { @@ -100,8 +113,7 @@ namespace PySideCPP2 { enum Enum1 { Option1 = 1, Option2 = 2 }; - -typedef long PySideLong; +using PySideLong = long; class PYSIDETEST_API TestObjectWithoutNamespace : public QObject { diff --git a/sources/pyside6/tests/pysidetest/testqvariantenum.cpp b/sources/pyside6/tests/pysidetest/testqvariantenum.cpp new file mode 100644 index 000000000..7135e422a --- /dev/null +++ b/sources/pyside6/tests/pysidetest/testqvariantenum.cpp @@ -0,0 +1,29 @@ +// Copyright (C) 2023 The Qt Company Ltd. +// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0 + +#include "testqvariantenum.h" + +QVariant TestQVariantEnum::getLValEnum() const +{ + return this->m_enum; +} + +QVariant TestQVariantEnum::getRValEnum() const +{ + return QVariant(Qt::Orientation::Horizontal); +} + +int TestQVariantEnum::getNumberFromQVarEnum(QVariant variantEnum) +{ + return variantEnum.toInt(); +} + +bool TestQVariantEnum::channelingEnum([[maybe_unused]] QVariant rvalEnum) const +{ + return false; +} + +bool TestQVariantEnum::isEnumChanneled() const +{ + return this->channelingEnum(this->getRValEnum()); +} diff --git a/sources/pyside6/tests/pysidetest/testqvariantenum.h b/sources/pyside6/tests/pysidetest/testqvariantenum.h new file mode 100644 index 000000000..4b729e3dd --- /dev/null +++ b/sources/pyside6/tests/pysidetest/testqvariantenum.h @@ -0,0 +1,35 @@ +// Copyright (C) 2023 The Qt Company Ltd. +// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0 + +#ifndef TESTQVARIANT_H +#define TESTQVARIANT_H + +#include "pysidetest_macros.h" + +#include <QtCore/QVariant> + +class PYSIDETEST_API TestQVariantEnum +{ +public: + TestQVariantEnum(QVariant lvalue_enum) : m_enum(lvalue_enum) {} + QVariant getLValEnum() const; + static int getNumberFromQVarEnum(QVariant variantEnum = QVariant()); + bool isEnumChanneled() const; + virtual QVariant getRValEnum() const; + virtual bool channelingEnum(QVariant rvalEnum) const; + virtual ~TestQVariantEnum() = default; +private: + QVariant m_enum; +}; + +class PYSIDETEST_API QVariantHolder // modeled after Q3DParameter, test QVariant conversion +{ +public: + void setValue(QVariant v) { m_variant = v; } + QVariant value() const { return m_variant; } + +private: + QVariant m_variant; +}; + +#endif // TESTQVARIANT_H diff --git a/sources/pyside6/tests/pysidetest/testview.cpp b/sources/pyside6/tests/pysidetest/testview.cpp index ade60682f..362239112 100644 --- a/sources/pyside6/tests/pysidetest/testview.cpp +++ b/sources/pyside6/tests/pysidetest/testview.cpp @@ -18,7 +18,7 @@ TestView::getData() QWidget* TestView::getEditorWidgetFromItemDelegate() const { - if (!m_delegate) + if (m_delegate == nullptr) return nullptr; QModelIndex index; diff --git a/sources/pyside6/tests/pysidetest/testview.h b/sources/pyside6/tests/pysidetest/testview.h index ee9ca9ce0..746def83e 100644 --- a/sources/pyside6/tests/pysidetest/testview.h +++ b/sources/pyside6/tests/pysidetest/testview.h @@ -18,7 +18,8 @@ class PYSIDETEST_API TestView : public QObject { Q_OBJECT public: - TestView(QAbstractListModel* model, QObject* parent = 0) : QObject(parent), m_model(model) {} + TestView(QAbstractListModel* model, QObject* parent = nullptr) : + QObject(parent), m_model(model) {} QAbstractListModel* model() { return m_model; } QVariant getData(); @@ -27,7 +28,7 @@ public: private: QAbstractListModel* m_model; - QAbstractItemDelegate* m_delegate; + QAbstractItemDelegate* m_delegate = nullptr; }; #endif // TESTVIEW_H diff --git a/sources/pyside6/tests/pysidetest/true_property_test.py b/sources/pyside6/tests/pysidetest/true_property_test.py index 671cc4571..62f6505dc 100644 --- a/sources/pyside6/tests/pysidetest/true_property_test.py +++ b/sources/pyside6/tests/pysidetest/true_property_test.py @@ -13,13 +13,16 @@ init_test_paths(False) """ PYSIDE-2042: Tests true_property with inheritance """ +is_pypy = hasattr(sys, "pypy_version_info") from PySide6.QtCore import QSize from PySide6.QtWidgets import QWidget, QSpinBox -from __feature__ import true_property +if not is_pypy: + from __feature__ import true_property from helper.usesqapplication import UsesQApplication +@unittest.skipIf(is_pypy, "__feature__ cannot yet be used with PyPy") class TruePropertyInheritanceTest(UsesQApplication): def testTrueProperty(self): @@ -33,6 +36,23 @@ class TruePropertyInheritanceTest(UsesQApplication): check = spin_box.sizeHint self.assertEqual(type(check), QSize) + def testHiddenMethods(self): + # PYSIDE-1889: setVisible is no longer a meta function but comes from the Property + widget = QWidget() + self.assertTrue("visible" in QWidget.__dict__) + self.assertFalse("isVisible" in QWidget.__dict__) + self.assertFalse("setVisible" in QWidget.__dict__) + self.assertTrue(hasattr(widget, "isVisible")) + self.assertTrue(hasattr(widget, "setVisible")) + self.assertEqual(widget.isVisible, QWidget.visible.fget) + self.assertEqual(widget.setVisible, QWidget.visible.fset) + + # This works with inheritance as well: + class SubClass(QWidget): + pass + sub_widget = SubClass() + self.assertEqual(sub_widget.isVisible, QWidget.visible.fget) + if __name__ == '__main__': unittest.main() diff --git a/sources/pyside6/tests/pysidetest/typedef_signal_test.py b/sources/pyside6/tests/pysidetest/typedef_signal_test.py index dfe5311e8..d0bdc880b 100644 --- a/sources/pyside6/tests/pysidetest/typedef_signal_test.py +++ b/sources/pyside6/tests/pysidetest/typedef_signal_test.py @@ -10,7 +10,7 @@ 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 QObject +from PySide6.QtCore import QObject, Slot from testbinding import TestObject @@ -23,6 +23,10 @@ class Receiver(QObject): def slot(self, value): self.received = value + @Slot("IntList") + def containerSlot(self, value): + self.received = value + class TypedefSignal(unittest.TestCase): @@ -34,6 +38,15 @@ class TypedefSignal(unittest.TestCase): obj.emitSignalWithTypedefValue(2) self.assertEqual(receiver.received.value, 2) + def testContainerTypedef(self): + obj = TestObject(0) + receiver = Receiver() + + test_list = [1, 2] + obj.signalWithContainerTypedefValue.connect(receiver.containerSlot) + obj.emitSignalWithContainerTypedefValue(test_list) + self.assertEqual(receiver.received, test_list) + if __name__ == '__main__': unittest.main() diff --git a/sources/pyside6/tests/pysidetest/typesystem_pysidetest.xml b/sources/pyside6/tests/pysidetest/typesystem_pysidetest.xml index 7f1170466..592d90a83 100644 --- a/sources/pyside6/tests/pysidetest/typesystem_pysidetest.xml +++ b/sources/pyside6/tests/pysidetest/typesystem_pysidetest.xml @@ -63,6 +63,8 @@ </modify-function> </object-type> + <value-type name="TestQVariantEnum"/> + <namespace-type name="FlagsNamespace" visible="no"> <enum-type name="Option" flags="Options"/> <object-type name="ClassForEnum" /> @@ -70,15 +72,9 @@ <object-type name="SharedPointerTestbench"/> + <value-type name="QVariantHolder"/> + <smart-pointer-type name="QSharedPointer" type="shared" getter="data" reset-method="reset"/> - <suppress-warning text="type 'QPyTextObject' is specified in typesystem, but not defined. This could potentially lead to compilation errors." /> - <!-- Qt5: I never really understood this warning. Probably it is because there - is no way to instantiate the class. Anyway, why must this class emit this warning? - I am not a C++ warrior, so I'd prefer if it would say "it is ok if you see this warning!". - Well, maybe somebody will enlighten me, and I'll change this comment. - I'd actually prefer an implementation that avoids generating this message, but I still failed - doing so :-( - --> </typesystem> |