diff options
Diffstat (limited to 'sources/pyside6/tests/pysidetest')
31 files changed, 802 insertions, 75 deletions
diff --git a/sources/pyside6/tests/pysidetest/CMakeLists.txt b/sources/pyside6/tests/pysidetest/CMakeLists.txt index ee2a295fe..38f42f342 100644 --- a/sources/pyside6/tests/pysidetest/CMakeLists.txt +++ b/sources/pyside6/tests/pysidetest/CMakeLists.txt @@ -1,7 +1,10 @@ +# Copyright (C) 2023 The Qt Company Ltd. +# SPDX-License-Identifier: BSD-3-Clause + project(pysidetest) project(testbinding) -cmake_minimum_required(VERSION 3.16) +cmake_minimum_required(VERSION 3.18) set(QT_USE_QTCORE 1) # no more supported: include(${QT_USE_FILE}) @@ -14,15 +17,18 @@ set(CMAKE_AUTOMOC ON) add_definitions(-DQT_SHARED) add_definitions(-DRXX_ALLOCATOR_INIT_0) -find_package(Qt${QT_MAJOR_VERSION}Widgets) +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. @@ -73,10 +81,15 @@ make_path(testbinding_include_dirs ${pyside6_BINARY_DIR} make_path(testbinding_typesystem_path ${pyside6_SOURCE_DIR} ${pyside6_BINARY_DIR}) +shiboken_get_tool_shell_wrapper(shiboken tool_wrapper) + add_custom_command( -OUTPUT "${CMAKE_CURRENT_BINARY_DIR}/mjb_rejected_classes.log" - BYPRODUCTS ${testbinding_SRC} - COMMAND Shiboken6::shiboken6 ${GENERATOR_EXTRA_FLAGS} + OUTPUT "${CMAKE_CURRENT_BINARY_DIR}/mjb_rejected_classes.log" + BYPRODUCTS ${testbinding_SRC} + COMMAND + ${tool_wrapper} + $<TARGET_FILE:Shiboken6::shiboken6> + ${GENERATOR_EXTRA_FLAGS} ${CMAKE_CURRENT_SOURCE_DIR}/pysidetest_global.h --include-paths=${testbinding_include_dirs} ${shiboken_framework_include_dirs_option} @@ -84,8 +97,8 @@ OUTPUT "${CMAKE_CURRENT_BINARY_DIR}/mjb_rejected_classes.log" --output-directory=${CMAKE_CURRENT_BINARY_DIR} ${CMAKE_CURRENT_SOURCE_DIR}/typesystem_pysidetest.xml --api-version=${SUPPORTED_QT_VERSION} -WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR} -COMMENT "Running generator for test binding..." + WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR} + COMMENT "Running generator for test binding..." ) include_directories(${CMAKE_CURRENT_SOURCE_DIR} @@ -105,10 +118,7 @@ set_target_properties(pysidetest PROPERTIES target_link_libraries(pysidetest Shiboken6::libshiboken - ${Qt${QT_MAJOR_VERSION}Core_LIBRARIES} - ${Qt${QT_MAJOR_VERSION}Gui_LIBRARIES} - ${Qt${QT_MAJOR_VERSION}Widgets_LIBRARIES} - ) + Qt::Core Qt::Gui Qt::Widgets) add_library(testbinding MODULE ${testbinding_SRC}) set_property(TARGET testbinding PROPERTY PREFIX "") @@ -121,9 +131,7 @@ target_link_libraries(testbinding pysidetest pyside6 Shiboken6::libshiboken - ${Qt${QT_MAJOR_VERSION}Core_LIBRARIES} - ${Qt${QT_MAJOR_VERSION}Gui_LIBRARIES} - ${Qt${QT_MAJOR_VERSION}Widgets_LIBRARIES}) + Qt::Core Qt::Gui Qt::Widgets) add_dependencies(testbinding pyside6 QtCore QtGui QtWidgets pysidetest) create_generator_target(testbinding) @@ -140,10 +148,13 @@ 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) PYSIDE_TEST(property_python_test.py) +PYSIDE_TEST(snake_case_test.py) +PYSIDE_TEST(true_property_test.py) PYSIDE_TEST(qapp_like_a_macro_test.py) PYSIDE_TEST(qvariant_test.py) PYSIDE_TEST(repr_test.py) @@ -157,3 +168,4 @@ PYSIDE_TEST(signalwithdefaultvalue_test.py) PYSIDE_TEST(typedef_signal_test.py) PYSIDE_TEST(version_test.py) PYSIDE_TEST(mock_as_slot_test.py) +PYSIDE_TEST(pyenum_relax_options_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/containertest.cpp b/sources/pyside6/tests/pysidetest/containertest.cpp index 4bbb29cbc..da8729af3 100644 --- a/sources/pyside6/tests/pysidetest/containertest.cpp +++ b/sources/pyside6/tests/pysidetest/containertest.cpp @@ -3,15 +3,17 @@ #include "containertest.h" +using namespace Qt::StringLiterals; + ContainerTest::ContainerTest() = default; QMultiMap<int, QString> ContainerTest::createMultiMap() { static const QMultiMap<int, QString> - result{{1, u"v1"_qs}, - {2, u"v2_1"_qs}, {2, u"v2_2"_qs}, - {3, u"v3"_qs}, - {4, u"v4_1"_qs}, {4, u"v4_2"_qs}}; + result{{1, u"v1"_s}, + {2, u"v2_1"_s}, {2, u"v2_2"_s}, + {3, u"v3"_s}, + {4, u"v4_1"_s}, {4, u"v4_2"_s}}; return result; } @@ -23,10 +25,10 @@ QMultiMap<int, QString> ContainerTest::passThroughMultiMap(const QMultiMap<int, QMultiHash<int, QString> ContainerTest::createMultiHash() { static const QMultiHash<int, QString> - result{{1, u"v1"_qs}, - {2, u"v2_1"_qs}, {2, u"v2_2"_qs}, - {3, u"v3"_qs}, - {4, u"v4_1"_qs}, {4, u"v4_2"_qs}}; + result{{1, u"v1"_s}, + {2, u"v2_1"_s}, {2, u"v2_2"_s}, + {3, u"v3"_s}, + {4, u"v4_1"_s}, {4, u"v4_2"_s}}; return result; } diff --git a/sources/pyside6/tests/pysidetest/enum_test.py b/sources/pyside6/tests/pysidetest/enum_test.py index 158faf37c..7afc5b948 100644 --- a/sources/pyside6/tests/pysidetest/enum_test.py +++ b/sources/pyside6/tests/pysidetest/enum_test.py @@ -1,4 +1,4 @@ -# Copyright (C) 2022 The Qt Company Ltd. +# Copyright (C) 2024 The Qt Company Ltd. # SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0 import os @@ -15,6 +15,7 @@ from testbinding import Enum1, TestObjectWithoutNamespace import dis + class ListConnectionTest(unittest.TestCase): def testEnumVisibility(self): @@ -45,9 +46,12 @@ 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. + +# flake8: noqa class InvestigateOpcodesTest(unittest.TestCase): def probe_function1(self): @@ -68,7 +72,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 +100,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 +139,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,10 +164,40 @@ 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)] + + if sys.version_info[:2] >= (3, 13): + + result_1 = [('RESUME', 149, 0), + ('LOAD_GLOBAL', 91, 0), + ('LOAD_ATTR', 82, 2), + ('STORE_FAST', 110, 1), + ('RETURN_CONST', 103, 0)] + + result_2 = [('RESUME', 149, 0), + ('LOAD_GLOBAL', 91, 0), + ('LOAD_ATTR', 82, 2), + ('PUSH_NULL', 34, None), + ('CALL', 53, 0), + ('STORE_FAST', 110, 1), + ('RETURN_CONST', 103, 0)] + self.assertEqual(self.read_code(self.probe_function1), result_1) self.assertEqual(self.read_code(self.probe_function2), result_2) if __name__ == '__main__': unittest.main() - 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 new file mode 100644 index 000000000..625f9cdc5 --- /dev/null +++ b/sources/pyside6/tests/pysidetest/pyenum_relax_options_test.py @@ -0,0 +1,136 @@ +#!/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 + +""" +PYSIDE-1735: Testing different relax options for Enums + +This test uses different configurations and initializes QtCore with it. +Because re-initialization is not possible, the test uses a subprocess +for it. This makes the test pretty slow. + +Maybe we should implement a way to re-initialize QtCore enums without +using subprocess, just to speed this up?? +""" + +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 subprocess +import tempfile +from textwrap import dedent + + +def runtest(program): + passed_path = os.fspath(Path(__file__).resolve().parents[1]) + with tempfile.NamedTemporaryFile(mode="w+", delete=False, suffix=".py") as fp: + preamble = dedent(f""" + import os + import sys + from pathlib import Path + sys.path.append({passed_path!r}) + from init_paths import init_test_paths + init_test_paths(False) + """) + print(preamble, program, file=fp) + fp.close() + try: + subprocess.run([sys.executable, fp.name], check=True, capture_output=True) + return True + except subprocess.CalledProcessError as e: + print(f"\ninfo: {e.__class__.__name__}: {e.stderr}") + return False + finally: + os.unlink(fp.name) + + +def testprog2(option): + return runtest(dedent(f""" + 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.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.pyside6_option_python_enum = {option} + from PySide6 import QtCore + QtCore.Qt.AlignTop + """)) + + +def testprog32(option): + return runtest(dedent(f""" + sys.pyside6_option_python_enum = {option} + from PySide6 import QtCore + QtCore.Qt.Alignment + """)) + + +def testprog64(option): + return runtest(dedent(f""" + sys.pyside6_option_python_enum = {option} + from PySide6 import QtCore + QtCore.Qt.AlignmentFlag() + """)) + + +def testprog128(option): + return runtest(dedent(f""" + sys.pyside6_option_python_enum = {option} + from PySide6 import QtCore + QtCore.Qt.Key(1234567) + """)) + + +class TestPyEnumRelaxOption(unittest.TestCase): + """ + This test is a bit involved, because we cannot unload QtCore after it is loaded once. + We use subprocess to test different cases, anyway. + """ + + def test_enumIsIntEnum(self): + self.assertTrue(testprog2(2)) + self.assertFalse(testprog2(4)) + + def test_globalDefault(self): + self.assertTrue(testprog4(4)) + self.assertFalse(testprog4(1)) + self.assertTrue(testprog4(12)) + + def test_localDefault(self): + self.assertTrue(testprog8_16(8 + 16)) + self.assertFalse(testprog8_16(0 + 16)) + + def test_fakeRenames(self): + self.assertTrue(testprog32(1)) + self.assertFalse(testprog32(32)) + + def test_zeroDefault(self): + self.assertTrue(testprog64(1)) + self.assertFalse(testprog64(64)) + + def test_Missing(self): + self.assertTrue(testprog128(1)) + self.assertFalse(testprog128(128)) + + +if __name__ == "__main__": + unittest.main() diff --git a/sources/pyside6/tests/pysidetest/pysidetest.pyproject b/sources/pyside6/tests/pysidetest/pysidetest.pyproject new file mode 100644 index 000000000..032d31c6f --- /dev/null +++ b/sources/pyside6/tests/pysidetest/pysidetest.pyproject @@ -0,0 +1,33 @@ +{ + "files": ["all_modules_load_test.py", + "bug_1016.py", + "constructor_properties_test.py", + "container_test.py", + "decoratedslot_test.py", + "delegatecreateseditor_test.py", + "enum_test.py", + "homonymoussignalandmethod_test.py", + "iterable_test.py", + "list_signal_test.py", + "mixin_signal_slots_test.py", + "mock_as_slot_test.py", + "modelview_test.py", + "new_inherited_functions_test.py", + "notify_id.py", + "properties_test.py", + "property_python_test.py", + "pyenum_relax_options_test.py", + "qapp_like_a_macro_test.py", + "qvariant_test.py", + "repr_test.py", + "shared_pointer_test.py", + "signal_slot_warning.py", + "signal_tp_descr_get_test.py", + "signalandnamespace_test.py", + "signalemissionfrompython_test.py", + "signalinstance_equality_test.py", + "signalwithdefaultvalue_test.py", + "typedef_signal_test.py", + "version_test.py", + "typesystem_pysidetest.xml"] +} 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 f68efee63..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,20 +11,57 @@ 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.QtCore import Qt -from PySide6.QtGui import QKeySequence +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): # bug #775 - ks = QKeySequence(Qt.SHIFT, Qt.CTRL, Qt.Key_P, Qt.Key_R) + ks = QKeySequence(Qt.ShiftModifier, Qt.ControlModifier, Qt.Key_P, Qt.Key_R) self.assertEqual(TestObject.checkType(ks), 4107) + 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) + + 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__': unittest.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/shared_pointer_test.py b/sources/pyside6/tests/pysidetest/shared_pointer_test.py index eb0b21007..6f49d69b1 100644 --- a/sources/pyside6/tests/pysidetest/shared_pointer_test.py +++ b/sources/pyside6/tests/pysidetest/shared_pointer_test.py @@ -28,6 +28,8 @@ class SharedPointerTests(unittest.TestCase): p = SharedPointerTestbench.createSharedPointerQObject() self.assertEqual(p.objectName(), "TestObject") SharedPointerTestbench.printSharedPointerQObject(p) + p = SharedPointerTestbench.createSharedPointerConstQObject() + SharedPointerTestbench.printSharedPointerConstQObject(p) def testIntSharedPointer(self): p = SharedPointerTestbench.createSharedPointerInt(42) diff --git a/sources/pyside6/tests/pysidetest/sharedpointertestbench.cpp b/sources/pyside6/tests/pysidetest/sharedpointertestbench.cpp index a901570cc..44c2a4fe0 100644 --- a/sources/pyside6/tests/pysidetest/sharedpointertestbench.cpp +++ b/sources/pyside6/tests/pysidetest/sharedpointertestbench.cpp @@ -6,6 +6,8 @@ #include <QtCore/QObject> #include <QtCore/QDebug> +using namespace Qt::StringLiterals; + SharedPointerTestbench::SharedPointerTestbench() = default; QSharedPointer<int> SharedPointerTestbench::createSharedPointerInt(int v) @@ -21,7 +23,7 @@ void SharedPointerTestbench::printSharedPointerInt(const QSharedPointer<int> &p) QSharedPointer<QObject> SharedPointerTestbench::createSharedPointerQObject() { QSharedPointer<QObject> result(new QObject); - result->setObjectName(u"TestObject"_qs); + result->setObjectName(u"TestObject"_s); return result; } @@ -29,3 +31,16 @@ void SharedPointerTestbench::printSharedPointerQObject(const QSharedPointer<QObj { qDebug() << __FUNCTION__ << p.data(); } + +QSharedPointer<const QObject> SharedPointerTestbench::createSharedPointerConstQObject() +{ + auto *o = new QObject; + o->setObjectName(u"ConstTestObject"_s); + QSharedPointer<const QObject> result(o); + return result; +} + +void SharedPointerTestbench::printSharedPointerConstQObject(const QSharedPointer<const QObject> &p) +{ + qDebug() << __FUNCTION__ << p.data(); +} diff --git a/sources/pyside6/tests/pysidetest/sharedpointertestbench.h b/sources/pyside6/tests/pysidetest/sharedpointertestbench.h index b919acd17..b23fd1b6c 100644 --- a/sources/pyside6/tests/pysidetest/sharedpointertestbench.h +++ b/sources/pyside6/tests/pysidetest/sharedpointertestbench.h @@ -20,6 +20,10 @@ public: static QSharedPointer<QObject> createSharedPointerQObject(); static void printSharedPointerQObject(const QSharedPointer<QObject> &p); + + static QSharedPointer<const QObject> createSharedPointerConstQObject(); + static void printSharedPointerConstQObject(const QSharedPointer<const QObject> &p); + }; #endif // SHAREDPOINTERTESTBENCH_H 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 new file mode 100644 index 000000000..4a482c35a --- /dev/null +++ b/sources/pyside6/tests/pysidetest/snake_case_sub.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) + +""" +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() + check = widget.sizeHint diff --git a/sources/pyside6/tests/pysidetest/snake_case_test.py b/sources/pyside6/tests/pysidetest/snake_case_test.py new file mode 100644 index 000000000..14e035773 --- /dev/null +++ b/sources/pyside6/tests/pysidetest/snake_case_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) + +""" +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 +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): + # this worked + widget = QWidget() + check = widget.size_hint + + 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 new file mode 100644 index 000000000..62f6505dc --- /dev/null +++ b/sources/pyside6/tests/pysidetest/true_property_test.py @@ -0,0 +1,58 @@ +# 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) + +""" +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 +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): + # this worked + widget = QWidget() + check = widget.sizeHint + self.assertEqual(type(check), QSize) + + # PYSIDE-2042: inheritance did not work + spin_box = QSpinBox() + 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> |