diff options
Diffstat (limited to 'sources/pyside6/tests/QtCore')
48 files changed, 714 insertions, 191 deletions
diff --git a/sources/pyside6/tests/QtCore/CMakeLists.txt b/sources/pyside6/tests/QtCore/CMakeLists.txt index 59f4161cb..f0228d943 100644 --- a/sources/pyside6/tests/QtCore/CMakeLists.txt +++ b/sources/pyside6/tests/QtCore/CMakeLists.txt @@ -1,3 +1,6 @@ +# Copyright (C) 2023 The Qt Company Ltd. +# SPDX-License-Identifier: BSD-3-Clause + PYSIDE_TEST(attr_cache_py3k.py) PYSIDE_TEST(bug_278_test.py) PYSIDE_TEST(bug_300_test.py) @@ -31,6 +34,7 @@ PYSIDE_TEST(bug_1313.py) PYSIDE_TEST(bug_PYSIDE-41.py) PYSIDE_TEST(bug_PYSIDE-42.py) PYSIDE_TEST(bug_PYSIDE-164.py) +PYSIDE_TEST(bug_PYSIDE-2745.py) PYSIDE_TEST(blocking_signals_test.py) PYSIDE_TEST(classinfo_test.py) PYSIDE_TEST(child_event_test.py) @@ -126,6 +130,7 @@ PYSIDE_TEST(quuid_test.py) PYSIDE_TEST(qversionnumber_test.py) PYSIDE_TEST(repr_test.py) PYSIDE_TEST(setprop_on_ctor_test.py) +PYSIDE_TEST(signal_sender.py) PYSIDE_TEST(snake_prop_feature_test.py) PYSIDE_TEST(staticMetaObject_test.py) PYSIDE_TEST(static_method_test.py) @@ -136,6 +141,7 @@ PYSIDE_TEST(unaryoperator_test.py) PYSIDE_TEST(unicode_test.py) PYSIDE_TEST(versioninfo_test.py) PYSIDE_TEST(loggingcategorymacros_test.py) +PYSIDE_TEST(qrunnable_test.py) if(X11) PYSIDE_TEST(qhandle_test.py) diff --git a/sources/pyside6/tests/QtCore/blocking_signals_test.py b/sources/pyside6/tests/QtCore/blocking_signals_test.py index d8159c2ef..493abb071 100644 --- a/sources/pyside6/tests/QtCore/blocking_signals_test.py +++ b/sources/pyside6/tests/QtCore/blocking_signals_test.py @@ -14,7 +14,12 @@ 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, QFile, QSignalBlocker +from PySide6.QtCore import QObject, Signal, QFile, QSignalBlocker + + +class Sender(QObject): + mysignal = Signal() + mysignal_int_int = Signal(int, int) class TestSignalsBlockedBasic(unittest.TestCase): @@ -61,7 +66,7 @@ class TestSignalsBlocked(unittest.TestCase): def setUp(self): # Set up the basic resources needed - self.obj = QObject() + self.obj = Sender() self.args = tuple() self.called = False @@ -81,27 +86,28 @@ class TestSignalsBlocked(unittest.TestCase): def testShortCircuitSignals(self): # Blocking of Python short-circuit signals - QObject.connect(self.obj, SIGNAL('mysignal()'), self.callback) + self.obj.mysignal.connect(self.callback) - self.obj.emit(SIGNAL('mysignal()')) + self.obj.mysignal.emit() self.assertTrue(self.called) self.called = False self.obj.blockSignals(True) - self.obj.emit(SIGNAL('mysignal()')) + self.obj.mysignal.emit() self.assertTrue(not self.called) def testPythonSignals(self): # Blocking of Python typed signals - QObject.connect(self.obj, SIGNAL('mysignal(int,int)'), self.callback) + + self.obj.mysignal_int_int.connect(self.callback) self.args = (1, 3) - self.obj.emit(SIGNAL('mysignal(int,int)'), *self.args) + self.obj.mysignal_int_int.emit(*self.args) self.assertTrue(self.called) self.called = False self.obj.blockSignals(True) - self.obj.emit(SIGNAL('mysignal(int,int)'), *self.args) + self.obj.mysignal_int_int.emit(*self.args) self.assertTrue(not self.called) @@ -130,7 +136,7 @@ class TestQFileSignalBlocking(unittest.TestCase): def testAboutToCloseBlocking(self): # QIODevice.aboutToClose() blocking - QObject.connect(self.qfile, SIGNAL('aboutToClose()'), self.callback) + self.qfile.aboutToClose.connect(self.callback) self.assertTrue(self.qfile.open(QFile.ReadOnly)) self.qfile.close() diff --git a/sources/pyside6/tests/QtCore/bug_1019.py b/sources/pyside6/tests/QtCore/bug_1019.py index 89e400428..4a35956b1 100644 --- a/sources/pyside6/tests/QtCore/bug_1019.py +++ b/sources/pyside6/tests/QtCore/bug_1019.py @@ -30,6 +30,7 @@ class MyTimer2 (MyTimer): pass def start(self): + """ 'Overrides' non-virtual slot QTimer.start().""" self.startCalled = True QCoreApplication.instance().quit() diff --git a/sources/pyside6/tests/QtCore/bug_462.py b/sources/pyside6/tests/QtCore/bug_462.py index 2f13bb531..04a42fe08 100644 --- a/sources/pyside6/tests/QtCore/bug_462.py +++ b/sources/pyside6/tests/QtCore/bug_462.py @@ -16,7 +16,7 @@ from PySide6.QtCore import QObject, QCoreApplication, QEvent, QThread class MyEvent(QEvent): def __init__(self, i): print("TYPE:", type(QEvent.User)) - super().__init__(QEvent.Type(QEvent.User + (0 if sys.pyside63_option_python_enum else 100))) + super().__init__(QEvent.Type(QEvent.User)) self.i = i diff --git a/sources/pyside6/tests/QtCore/bug_515.py b/sources/pyside6/tests/QtCore/bug_515.py index 52293b808..4e270a441 100644 --- a/sources/pyside6/tests/QtCore/bug_515.py +++ b/sources/pyside6/tests/QtCore/bug_515.py @@ -26,7 +26,7 @@ def _cleanup(): def _checkCleanup(): global callCleanup - assert(callCleanup) + assert (callCleanup) app = QCoreApplication([]) diff --git a/sources/pyside6/tests/QtCore/bug_826.py b/sources/pyside6/tests/QtCore/bug_826.py index 65b237d24..95edc0a7c 100644 --- a/sources/pyside6/tests/QtCore/bug_826.py +++ b/sources/pyside6/tests/QtCore/bug_826.py @@ -33,11 +33,6 @@ class TestEnums(unittest.TestCase): self.assertTrue(QEvent.User <= TestEvent.TestEventType <= QEvent.MaxUser) self.assertTrue(QEvent.User <= TEST_EVENT_TYPE <= QEvent.MaxUser) - @unittest.skipIf(sys.pyside63_option_python_enum, "makes no sense for tested Python enums") - def testUserTypesRepr(self): - self.assertEqual(eval(repr(TestEvent.TestEventType)), TestEvent.TestEventType) - self.assertEqual(eval(repr(TEST_EVENT_TYPE)), TEST_EVENT_TYPE) - if __name__ == '__main__': unittest.main() diff --git a/sources/pyside6/tests/QtCore/bug_927.py b/sources/pyside6/tests/QtCore/bug_927.py index 1ecea61b2..c15a7014b 100644 --- a/sources/pyside6/tests/QtCore/bug_927.py +++ b/sources/pyside6/tests/QtCore/bug_927.py @@ -24,7 +24,7 @@ class thread_function(): class Task(QRunnable): def run(self): - QThread.sleep(2) # Sleep 2 seconds + QThread.msleep(100) class QThreadPoolTest(unittest.TestCase): @@ -34,15 +34,15 @@ class QThreadPoolTest(unittest.TestCase): for i in range(3): task = Task() QThreadPool.globalInstance().start(task) - time.sleep(1) # Sleep 1 second + time.sleep(0.05) - QThreadPool.globalInstance().waitForDone() + self.assertTrue(QThreadPool.globalInstance().waitForDone()) def testCallable(self): global thread_function_called tp = QThreadPool.globalInstance() tp.start(thread_function) - tp.waitForDone() + self.assertTrue(tp.waitForDone()) self.assertTrue(thread_function_called) diff --git a/sources/pyside6/tests/QtCore/bug_987.py b/sources/pyside6/tests/QtCore/bug_987.py index bc92e5736..a8c9799e0 100644 --- a/sources/pyside6/tests/QtCore/bug_987.py +++ b/sources/pyside6/tests/QtCore/bug_987.py @@ -19,7 +19,7 @@ class TestBug987(unittest.TestCase): def testInvalidDisconnection(self): o = QObject() - self.assertRaises(RuntimeError, o.destroyed.disconnect, self.callback) + self.assertFalse(o.destroyed.disconnect(self.callback)) if __name__ == '__main__': diff --git a/sources/pyside6/tests/QtCore/bug_PYSIDE-164.py b/sources/pyside6/tests/QtCore/bug_PYSIDE-164.py index c5a6736a8..84859af84 100644 --- a/sources/pyside6/tests/QtCore/bug_PYSIDE-164.py +++ b/sources/pyside6/tests/QtCore/bug_PYSIDE-164.py @@ -10,16 +10,19 @@ 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, QEventLoop, QObject, Qt, QThread, QTimer, SIGNAL +from PySide6.QtCore import QCoreApplication, QEventLoop, QObject, Qt, QThread, Signal class Emitter(QThread): + + signal = Signal(int) + def __init__(self): super().__init__() def run(self): print("Before emit.") - self.emit(SIGNAL("signal(int)"), 0) + self.signal.emit(0) print("After emit.") @@ -36,12 +39,11 @@ class Receiver(QObject): class TestBugPYSIDE164(unittest.TestCase): def testBlockingSignal(self): - app = QCoreApplication.instance() or QCoreApplication([]) + app = QCoreApplication.instance() or QCoreApplication([]) # noqa: F841 eventloop = QEventLoop() emitter = Emitter() receiver = Receiver(eventloop) - emitter.connect(emitter, SIGNAL("signal(int)"), - receiver.receive, Qt.BlockingQueuedConnection) + emitter.signal.connect(receiver.receive, Qt.BlockingQueuedConnection) emitter.start() retval = eventloop.exec() emitter.wait(2000) diff --git a/sources/pyside6/tests/QtCore/bug_PYSIDE-2745.py b/sources/pyside6/tests/QtCore/bug_PYSIDE-2745.py new file mode 100644 index 000000000..3d6c603b7 --- /dev/null +++ b/sources/pyside6/tests/QtCore/bug_PYSIDE-2745.py @@ -0,0 +1,37 @@ +# 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 +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 helper.usesqapplication import UsesQApplication + + +class TestBugPYSIDE2745(UsesQApplication): + + def setUp(self): + UsesQApplication.setUp(self) + self.counter = 0 + + def fail(self): + self.counter += 1 + raise Exception() + + def test_fail(self): + QTimer.singleShot(0, self.fail) + QTimer.singleShot(0, self.fail) + QTimer.singleShot(1, self.app.quit) + self.app.exec() + self.assertEqual(self.counter, 2) + + +if __name__ == '__main__': + unittest.main() diff --git a/sources/pyside6/tests/QtCore/child_event_test.py b/sources/pyside6/tests/QtCore/child_event_test.py index 356bf0f72..6b17ddc93 100644 --- a/sources/pyside6/tests/QtCore/child_event_test.py +++ b/sources/pyside6/tests/QtCore/child_event_test.py @@ -14,7 +14,7 @@ from init_paths import init_test_paths init_test_paths(False) from PySide6.QtCore import QObject, QTimer, QCoreApplication -from helper.usesqcoreapplication import UsesQCoreApplication +from helper.usesqapplication import UsesQApplication class ExtQObject(QObject): @@ -37,14 +37,14 @@ class ExtQTimer(QTimer): self.child_event_received = True -class TestChildEvent(UsesQCoreApplication): +class TestChildEvent(UsesQApplication): '''Test case for QObject::childEvent and QTimer::childEvent''' def setUp(self): - UsesQCoreApplication.setUp(self) + UsesQApplication.setUp(self) def tearDown(self): - UsesQCoreApplication.tearDown(self) + UsesQApplication.tearDown(self) def testQObject(self): parent = ExtQObject() diff --git a/sources/pyside6/tests/QtCore/classinfo_test.py b/sources/pyside6/tests/QtCore/classinfo_test.py index 30d141acf..0b0a0b4b6 100644 --- a/sources/pyside6/tests/QtCore/classinfo_test.py +++ b/sources/pyside6/tests/QtCore/classinfo_test.py @@ -33,7 +33,7 @@ class TestClassInfo(unittest.TestCase): self.assertEqual(ci.value(), 'http://www.pyside.org') def test_dictionary(self): - @ClassInfo({'author':'pyside', 'author company':'The Qt Company'}) + @ClassInfo({'author': 'pyside', 'author company': 'The Qt Company'}) class MyObject(QObject): pass @@ -50,11 +50,11 @@ class TestClassInfo(unittest.TestCase): self.assertEqual(ci.value(), 'The Qt Company') def test_verify_metadata_types(self): - valid_dict = { '123': '456' } + valid_dict = {'123': '456'} - invalid_dict_1 = { '123': 456 } - invalid_dict_2 = { 123: 456 } - invalid_dict_3 = { 123: '456' } + invalid_dict_1 = {'123': 456} + invalid_dict_2 = {123: 456} + invalid_dict_3 = {123: '456'} ClassInfo(**valid_dict) @@ -88,6 +88,7 @@ class TestClassInfo(unittest.TestCase): def test_can_only_be_used_on_qobjects(self): def make_info(): return ClassInfo(author='pyside') + def test_function(): pass self.assertRaises(TypeError, make_info(), test_function) diff --git a/sources/pyside6/tests/QtCore/deletelater_test.py b/sources/pyside6/tests/QtCore/deletelater_test.py index 18e7dea09..0ee078428 100644 --- a/sources/pyside6/tests/QtCore/deletelater_test.py +++ b/sources/pyside6/tests/QtCore/deletelater_test.py @@ -15,10 +15,10 @@ from init_paths import init_test_paths init_test_paths(False) from PySide6.QtCore import QObject, QTimer, QCoreApplication, SIGNAL -from helper.usesqcoreapplication import UsesQCoreApplication +from helper.usesqapplication import UsesQApplication -class TestDeleteLater(UsesQCoreApplication): +class TestDeleteLater(UsesQApplication): '''Test case for function DeleteLater''' def testCase(self): diff --git a/sources/pyside6/tests/QtCore/destroysignal_test.py b/sources/pyside6/tests/QtCore/destroysignal_test.py index 34aaded9e..ad087b489 100644 --- a/sources/pyside6/tests/QtCore/destroysignal_test.py +++ b/sources/pyside6/tests/QtCore/destroysignal_test.py @@ -11,7 +11,7 @@ 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, QObject +from PySide6.QtCore import QTimer, QObject, Signal class TestDestroySignal(unittest.TestCase): @@ -43,6 +43,36 @@ class TestDestroySignal(unittest.TestCase): self.assertTrue(self._destroyed) +class Foo(QObject): + s = Signal(int) + + def __init__(self): + QObject.__init__(self) + sys.stderr.write(f"__init__ {id(self):x}\n") + + def __del__(self): + sys.stderr.write(f"__del__ {id(self):x}\n") + + def send(self, i): + self.s.emit(i) + + +# PYSIDE-2201/2328: This crashed until we introduced a weak reference. +class TestDestroyNoConnect(unittest.TestCase): + + def testSignalDestroyedMissingReference(self): + # This works since it has one reference more to Foo + Foo().send(43) + # This crashed because we have no reference in the signal. + with self.assertRaises(RuntimeError): + Foo().s.emit(44) + + def testSignalDestroyedinConnect(self): + # PYSIDE-2328: Connect to signal of temporary + with self.assertRaises(RuntimeError): + Foo().s.connect(None) + + if __name__ == '__main__': unittest.main() diff --git a/sources/pyside6/tests/QtCore/duck_punching_test.py b/sources/pyside6/tests/QtCore/duck_punching_test.py index 668ca5751..145863c3e 100644 --- a/sources/pyside6/tests/QtCore/duck_punching_test.py +++ b/sources/pyside6/tests/QtCore/duck_punching_test.py @@ -16,7 +16,7 @@ from init_paths import init_test_paths init_test_paths(False) from PySide6.QtCore import QObject -from helper.usesqcoreapplication import UsesQCoreApplication +from helper.usesqapplication import UsesQApplication def MethodType(func, instance, instanceType): @@ -31,20 +31,20 @@ class Duck(QObject): QObject.childEvent(self, event) -class TestDuckPunchingOnQObjectInstance(UsesQCoreApplication): +class TestDuckPunchingOnQObjectInstance(UsesQApplication): '''Test case for duck punching new implementations of C++ virtual methods into object instances.''' def setUp(self): # Acquire resources self.duck_childEvent_called = False - UsesQCoreApplication.setUp(self) + UsesQApplication.setUp(self) def tearDown(self): # Release resources del self.duck_childEvent_called # PYSIDE-535: Need to collect garbage in PyPy to trigger deletion gc.collect() - UsesQCoreApplication.tearDown(self) + UsesQApplication.tearDown(self) def testChildEventMonkeyPatch(self): # Test if the new childEvent injected on QObject instance is called from C++ diff --git a/sources/pyside6/tests/QtCore/errormessages_with_features_test.py b/sources/pyside6/tests/QtCore/errormessages_with_features_test.py index 8cb38882a..97c4f942e 100644 --- a/sources/pyside6/tests/QtCore/errormessages_with_features_test.py +++ b/sources/pyside6/tests/QtCore/errormessages_with_features_test.py @@ -34,7 +34,6 @@ This test is in its own file because combining it with @unittest.skipIf(is_pypy, "__feature__ cannot yet be used with PyPy") class ErrormessagesWithFeatures(unittest.TestCase): probe = "called with wrong argument types" - probe_miss = "missing signature" def setUp(self): qApp or QApplication() @@ -76,20 +75,20 @@ class ErrormessagesWithFeatures(unittest.TestCase): with self.assertRaises(TypeError) as cm: QApplication.quitOnLastWindowClosed = object print("\n\n" + cm.exception.args[0]) - self.assertTrue(self.probe_miss in cm.exception.args[0]) + self.assertTrue(self.probe in cm.exception.args[0]) with self.assertRaises(TypeError) as cm: qApp.quitOnLastWindowClosed = object - self.assertTrue(self.probe_miss in cm.exception.args[0]) + self.assertTrue(self.probe in cm.exception.args[0]) def testCorrectErrorMessagesClassSnakeProp(self): from __feature__ import snake_case, true_property with self.assertRaises(TypeError) as cm: QApplication.quit_on_last_window_closed = object print("\n\n" + cm.exception.args[0]) - self.assertTrue(self.probe_miss in cm.exception.args[0]) + self.assertTrue(self.probe in cm.exception.args[0]) with self.assertRaises(TypeError) as cm: qApp.quit_on_last_window_closed = object - self.assertTrue(self.probe_miss in cm.exception.args[0]) + self.assertTrue(self.probe in cm.exception.args[0]) def testDocIsWorking(self): """ diff --git a/sources/pyside6/tests/QtCore/feature_with_uic/window.py b/sources/pyside6/tests/QtCore/feature_with_uic/window.py index 6632fbaf9..c55bcaf92 100644 --- a/sources/pyside6/tests/QtCore/feature_with_uic/window.py +++ b/sources/pyside6/tests/QtCore/feature_with_uic/window.py @@ -28,7 +28,6 @@ class Ui_MainWindow(object): self.verticalLayout.addWidget(self.pushButton) - self.horizontalLayout.addLayout(self.verticalLayout) MainWindow.setCentralWidget(self.centralwidget) diff --git a/sources/pyside6/tests/QtCore/hash_test.py b/sources/pyside6/tests/QtCore/hash_test.py index acd100786..aee2f516c 100644 --- a/sources/pyside6/tests/QtCore/hash_test.py +++ b/sources/pyside6/tests/QtCore/hash_test.py @@ -15,13 +15,17 @@ from PySide6.QtCore import QDate, QDateTime, QTime, QUrl from PySide6.QtCore import QLine, QPoint, QRect, QSize +URL = "https://qt.io/" + + class HashTest(unittest.TestCase): def testInsert(self): myHash = {} qdate = QDate.currentDate() qdatetime = QDateTime.currentDateTime() qtime = QTime.currentTime() - qurl = QUrl("http://www.pyside.org") + qurl = QUrl(URL) + self.assertTrue(qurl.isValid()) qpoint = QPoint(12, 42) myHash[qdate] = "QDate" @@ -64,7 +68,34 @@ class HashTest(unittest.TestCase): self.assertEqual(l1, l2) self.assertEqual(hash(l1), hash(l2)) + def testQTimeHash(self): + t1 = QTime(5, 5, 5) + t2 = QTime(5, 5, 5) + self.assertFalse(t1 is t2) + self.assertEqual(t1, t2) + self.assertEqual(hash(t1), hash(t2)) + + def testQDateHash(self): + d1 = QDate(1968, 3, 9) + d2 = QDate(1968, 3, 9) + self.assertFalse(d1 is d2) + self.assertEqual(d1, d2) + self.assertEqual(hash(d1), hash(d2)) + + def testQDateTimeHash(self): + d1 = QDateTime(QDate(1968, 3, 9), QTime(5, 5, 5)) + d2 = QDateTime(QDate(1968, 3, 9), QTime(5, 5, 5)) + self.assertFalse(d1 is d2) + self.assertEqual(d1, d2) + self.assertEqual(hash(d1), hash(d2)) + + def testQUrlHash(self): + u1 = QUrl(URL) + u2 = QUrl(URL) + self.assertFalse(u1 is u2) + self.assertEqual(u1, u2) + self.assertEqual(hash(u1), hash(u2)) + if __name__ == '__main__': unittest.main() - diff --git a/sources/pyside6/tests/QtCore/loggingcategorymacros_test.py b/sources/pyside6/tests/QtCore/loggingcategorymacros_test.py index fa85d95ef..a808f0c3d 100644 --- a/sources/pyside6/tests/QtCore/loggingcategorymacros_test.py +++ b/sources/pyside6/tests/QtCore/loggingcategorymacros_test.py @@ -17,6 +17,7 @@ from PySide6.QtCore import (QLoggingCategory, QtMsgType, qCDebug, qCWarning, qCI param = None + def handler(msgt, ctx, msg): global param param = ctx.category + ": " + msg.strip() @@ -70,7 +71,6 @@ class TestQLoggingCategory(unittest.TestCase): qCWarning(self.criticalCategory, f"devices: {self.no_devices}") self.assertEqual(param, "warning.log: devices: 2") - def test_qCritical(self): qCCritical(self.defaultCategory, "no device") self.assertEqual(param, "default: no device") diff --git a/sources/pyside6/tests/QtCore/multiple_feature_test.py b/sources/pyside6/tests/QtCore/multiple_feature_test.py index d9f4bb8b2..0f51ace6b 100644 --- a/sources/pyside6/tests/QtCore/multiple_feature_test.py +++ b/sources/pyside6/tests/QtCore/multiple_feature_test.py @@ -31,6 +31,11 @@ There is much more to come. MethodDescriptorType = type(str.split) +def xprint(*args, **kw): + if "-v" in sys.argv: + print(*args, **kw) + + @unittest.skipIf(is_pypy, "__feature__ cannot yet be used with PyPy") class FeaturesTest(unittest.TestCase): @@ -93,14 +98,14 @@ class FeaturesTest(unittest.TestCase): for idx in range(0x100): feature.reset() config = f"feature_{idx:02x}" - print() - print(f"--- Feature Test Config `{config}` ---") - print("Imports:") + xprint() + xprint(f"--- Feature Test Config `{config}` ---") + xprint("Imports:") for bit in range(8): if idx & 1 << bit: cur_feature = feature_list[bit] text = f"from __feature__ import {cur_feature}" - print(text) + xprint(text) eval(compile(text, "<string>", "exec"), globals(), edict) for bit in range(8): value = idx & 1 << bit diff --git a/sources/pyside6/tests/QtCore/qbytearray_test.py b/sources/pyside6/tests/QtCore/qbytearray_test.py index c00674859..cb8f9a431 100644 --- a/sources/pyside6/tests/QtCore/qbytearray_test.py +++ b/sources/pyside6/tests/QtCore/qbytearray_test.py @@ -6,6 +6,7 @@ import ctypes import os import pickle +import struct import sys import unittest @@ -15,7 +16,8 @@ from init_paths import init_test_paths init_test_paths(False) -from PySide6.QtCore import QByteArray, QSettings, QObject, QDataStream, QIODevice +from PySide6.QtCore import (QByteArray, QSettings, QObject, QDataStream, + QIODevice, qCompress, qUncompress) class QByteArrayTestToNumber(unittest.TestCase): @@ -255,6 +257,34 @@ class QByteArraySliceAssignment(unittest.TestCase): actual_bytes = bytes(byte_array) self.assertEqual(orig_bytes, actual_bytes) + def testUnpack(self): + b = QByteArray(b'\x19\x00\x00\x00\xc4\t\x00\x00') + t = struct.unpack('<ii', b) + self.assertEqual(len(t), 2) + self.assertEqual(t[0], 25) + self.assertEqual(t[1], 2500) + + +class QCompressTest(unittest.TestCase): + def testQByteArrayCompression(self): + """Compress/uncompress a QByteArray.""" + data = bytes(10 * 'long redundant sentence bla bla', "UTF8") + ba = QByteArray(data) + compressed = qCompress(ba) + self.assertTrue(len(compressed) < len(data)) + uncompressed = qUncompress(compressed) + self.assertEqual(uncompressed, data) + + def testBufferCompression(self): + """Compress/uncompress portions of bytes without converting to + QByteArray.""" + data = bytes(10 * 'long redundant sentence bla bla', "UTF8") + used_len = int(len(data) / 2) + compressed = qCompress(data, used_len, -1) + self.assertTrue(len(compressed) < used_len) + uncompressed = qUncompress(compressed.data(), len(compressed)) + self.assertEqual(uncompressed, data[:used_len]) + if __name__ == '__main__': unittest.main() diff --git a/sources/pyside6/tests/QtCore/qcbor_test.py b/sources/pyside6/tests/QtCore/qcbor_test.py index edcac6c4b..312c9e5c7 100644 --- a/sources/pyside6/tests/QtCore/qcbor_test.py +++ b/sources/pyside6/tests/QtCore/qcbor_test.py @@ -15,7 +15,7 @@ from init_paths import init_test_paths init_test_paths(False) from PySide6.QtCore import (QByteArray, QCborStreamReader, QCborStreamWriter, - QCborTag, QCborValue) + QCborTag, QCborValue) class TestCbor(unittest.TestCase): @@ -56,11 +56,6 @@ class TestCbor(unittest.TestCase): value = QCborValue('hello') self.assertTrue(value.isString()) self.assertEqual(value.toString(), 'hello') - if sys.pyside63_option_python_enum: - # PYSIDE-1735: Undefined enums are not possible - return - tag = value.tag(QCborTag(32)) - self.assertEqual(int(tag), 32) if __name__ == '__main__': diff --git a/sources/pyside6/tests/QtCore/qdatastream_test.py b/sources/pyside6/tests/QtCore/qdatastream_test.py index 9ec69076b..517f466aa 100644 --- a/sources/pyside6/tests/QtCore/qdatastream_test.py +++ b/sources/pyside6/tests/QtCore/qdatastream_test.py @@ -296,6 +296,16 @@ class QDataStreamBuffer(unittest.TestCase): data = QDataStream(ba) self.assertEqual(data.readRawData(4), bytes('AB\x00C', "UTF-8")) + def testRawDataBytes(self): + test_data = b'AB\0' + data = QDataStream() + ba = QByteArray() + data = QDataStream(ba, QIODevice.WriteOnly) + data.writeRawData(test_data) + self.assertEqual(ba.data(), test_data) + data = QDataStream(ba) + self.assertEqual(data.readRawData(3), test_data) + def testBytes(self): dataOne = QDataStream() self.assertEqual(dataOne.readBytes(4), None) diff --git a/sources/pyside6/tests/QtCore/qenum_test.py b/sources/pyside6/tests/QtCore/qenum_test.py index adcdcbacd..45a8e9124 100644 --- a/sources/pyside6/tests/QtCore/qenum_test.py +++ b/sources/pyside6/tests/QtCore/qenum_test.py @@ -19,21 +19,6 @@ from PySide6.QtCore import Qt, QIODevice, QObject, QEnum, QFlag class TestEnum(unittest.TestCase): - @unittest.skipIf(sys.pyside63_option_python_enum, "not adequate for new enums to ask the value") - def testToInt(self): - self.assertEqual(QIODevice.NotOpen, 0) - self.assertEqual(QIODevice.ReadOnly, 1) - self.assertEqual(QIODevice.WriteOnly, 2) - self.assertEqual(QIODevice.ReadWrite, 1 | 2) - self.assertEqual(QIODevice.Append, 4) - self.assertEqual(QIODevice.Truncate, 8) - self.assertEqual(QIODevice.Text, 16) - self.assertEqual(QIODevice.Unbuffered, 32) - - @unittest.skipIf(sys.pyside63_option_python_enum, "not adequate for new enums to ask the value") - def testToIntInFunction(self): - self.assertEqual(str(int(QIODevice.WriteOnly)), "2") - def testOperations(self): k = Qt.Key.Key_1 @@ -42,24 +27,6 @@ class TestEnum(unittest.TestCase): self.assertEqual(k - 2, -(2 - k)) self.assertEqual(k * 2, 2 * k) - if not sys.pyside63_option_python_enum: - # Floats work fine with new enums - with self.assertRaises(TypeError): - a = k + 2.0 - - with self.assertRaises(TypeError): - a = k - 2.0 - - with self.assertRaises(TypeError): - a = k * 2.0 - - @unittest.skipIf(sys.pyside63_option_python_enum, "inheritance forbidden for Python enums") - def testInherit(self): - class A(Qt.Key): - pass - - self.assertEqual(A.Key_1, Qt.Key.Key_1) - @unittest.skipUnless(getattr(sys, "getobjects", None), "requires --with-trace-refs") @unittest.skipUnless(getattr(sys, "gettotalrefcount", None), "requires --with-pydebug") def testEnumNew_NoLeak(self): @@ -80,11 +47,10 @@ class TestEnum(unittest.TestCase): class TestQFlags(unittest.TestCase): - newenum = sys.pyside63_option_python_enum def testToItn(self): om = QIODevice.NotOpen - omcmp = om.value if self.newenum else om + omcmp = om.value self.assertEqual(om, QIODevice.NotOpen) self.assertTrue(omcmp == 0) @@ -94,7 +60,7 @@ class TestQFlags(unittest.TestCase): def testToIntInFunction(self): om = QIODevice.WriteOnly - self.assertEqual(int(om.value if self.newenum else om), 2) + self.assertEqual(int(om.value), 2) def testNonExtensibleEnums(self): try: diff --git a/sources/pyside6/tests/QtCore/qflags_test.py b/sources/pyside6/tests/QtCore/qflags_test.py index 3b97e649f..2a5306685 100644 --- a/sources/pyside6/tests/QtCore/qflags_test.py +++ b/sources/pyside6/tests/QtCore/qflags_test.py @@ -112,18 +112,6 @@ class QFlagsOnQVariant(unittest.TestCase): self.assertEqual(type(o.property("foo")), QIODevice.OpenMode) -class QFlagsWrongType(unittest.TestCase): - @unittest.skipIf(sys.pyside63_option_python_enum, "Qt.ItemFlag is no longer an IntEnum") - def testWrongType(self): - '''Wrong type passed to QFlags binary operators''' - for op in operator.or_, operator.and_, operator.xor: - for x in '43', 'jabba', QObject, object: - self.assertRaises(TypeError, op, Qt.NoItemFlags, x) - self.assertRaises(TypeError, op, x, Qt.NoItemFlags) - # making sure this actually does not fail all the time - self.assertEqual(operator.or_(Qt.NoItemFlags, 43), 43) - - class QEnumFlagDefault(unittest.TestCase): """ Check that old flag and enum syntax can be used. @@ -136,11 +124,7 @@ class QEnumFlagDefault(unittest.TestCase): oldEnum = Qt.AlignmentFlag() self.assertEqual(type(oldFlag), Qt.Alignment) self.assertEqual(type(oldEnum), Qt.AlignmentFlag) - if sys.pyside63_option_python_enum: - self.assertEqual(type(oldFlag), type(oldEnum)) - else: - with self.assertRaises(AssertionError): - self.assertEqual(type(oldFlag), type(oldEnum)) + self.assertEqual(type(oldFlag), type(oldEnum)) if __name__ == '__main__': diff --git a/sources/pyside6/tests/QtCore/qiodevice_buffered_read_test.py b/sources/pyside6/tests/QtCore/qiodevice_buffered_read_test.py new file mode 100644 index 000000000..ea735112a --- /dev/null +++ b/sources/pyside6/tests/QtCore/qiodevice_buffered_read_test.py @@ -0,0 +1,78 @@ +# Copyright (C) 2023 The Qt Company Ltd. +# SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0 + +'''Test cases for buffered read methods of QIODevice''' + +from PySide6.QtCore import QBuffer + +import enum +import unittest + + +class TestQIODeviceBufferedRead(unittest.TestCase): + class TestType(enum.Enum): + Read = enum.auto() + ReadLine = enum.auto() + Peek = enum.auto() + + def setUp(self) -> None: + self.buffer = QBuffer() + self.text = "Tomato juice\nPotato salad\n" + + self.assertTrue( + self.buffer.open(QBuffer.OpenModeFlag.ReadWrite), self.buffer.errorString()) + self.assertGreaterEqual( + self.buffer.write(self.text.encode("utf-8")), 0, self.buffer.errorString()) + + self.buffer.seek(0) + + def tearDown(self) -> None: + self.buffer.close() + + def test_read(self) -> None: + response1 = self.buffer.read(1024).data().decode("utf-8") + self.assertEqual(response1, self.text) + + self.buffer.seek(0) + response2 = bytearray(1024) + bytes_read = self.buffer.read(response2, 1024) + + self.assertGreaterEqual(bytes_read, 0, self.buffer.errorString()) + self.assertEqual(response2[:bytes_read].decode("utf-8"), response1) + + def test_readLine(self) -> None: + response1 = self.buffer.readLine(1024).data().decode("utf-8") + # Only read until the first line (including the line break) + self.assertEqual(response1, self.text.split("\n", 1)[0] + "\n") + + self.buffer.seek(0) + response2 = bytearray(1024) + bytes_read = self.buffer.readLine(response2, 1024) + + self.assertGreaterEqual(bytes_read, 0, self.buffer.errorString()) + self.assertEqual(response2[:bytes_read].decode("utf-8"), response1) + + def test_peek(self) -> None: + response1 = self.buffer.peek(1024).data().decode("utf-8") + self.assertEqual(response1, self.text) + + # Test that peek has no side effects + response_again1 = self.buffer.read(1024).data().decode("utf-8") + self.assertEqual(response_again1, response1) + + self.buffer.seek(0) + response2 = bytearray(1024) + bytes_read = self.buffer.peek(response2, 1024) + + self.assertGreaterEqual(bytes_read, 0, self.buffer.errorString()) + self.assertEqual(response2[:bytes_read].decode("utf-8"), response1) + + # Test that peek has no side effects + response_again2 = bytearray(1024) + bytes_read_again2 = self.buffer.read(response_again2, 1024) + self.assertEqual(bytes_read, bytes_read_again2) + self.assertEqual(response_again2, response2) + + +if __name__ == "__main__": + unittest.main() diff --git a/sources/pyside6/tests/QtCore/qiopipe_test.py b/sources/pyside6/tests/QtCore/qiopipe_test.py new file mode 100644 index 000000000..53a6ba70a --- /dev/null +++ b/sources/pyside6/tests/QtCore/qiopipe_test.py @@ -0,0 +1,36 @@ +# Copyright (C) 2024 The Qt Company Ltd. +# SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0 + +'''Test cases for the QIOPipe class''' + +from PySide6.QtCore import QIODevice, QIOPipe + +import unittest + + +class QIOPipeTest(unittest.TestCase): + def setUp(self) -> None: + self.pipe = QIOPipe() + self.pipe.open(QIODevice.OpenModeFlag.ReadWrite) + return super().setUp() + + def tearDown(self) -> None: + super().tearDown() + + def ready_read_bytes_written(self): + received_data = self.pipe.end2().readAll().data() + self.assertEqual(received_data, self.data) + + def test_readyRead(self): + self.data = b"Hello, World!" + self.pipe.end2().readyRead.connect(self.ready_read_bytes_written) + self.pipe.end1().write(self.data) + + def test_bytesWritten(self): + self.data = b"Hello, World!" + self.pipe.end2().bytesWritten.connect(self.ready_read_bytes_written) + self.pipe.end1().write(self.data) + + +if __name__ == '__main__': + unittest.main() diff --git a/sources/pyside6/tests/QtCore/qlocale_test.py b/sources/pyside6/tests/QtCore/qlocale_test.py index 3d3425445..05b0d3219 100644 --- a/sources/pyside6/tests/QtCore/qlocale_test.py +++ b/sources/pyside6/tests/QtCore/qlocale_test.py @@ -37,6 +37,11 @@ class QLocaleTestToNumber(unittest.TestCase): self.assertEqual((ctypes.c_short(37).value, True), obj.toShort('37')) + def testToNumberLong(self): + obj = QLocale(QLocale.C) + self.assertEqual((ctypes.c_long(37).value, True), + obj.toLong('37')) + def testToNumberULongLong(self): obj = QLocale(QLocale.C) self.assertEqual((ctypes.c_ulonglong(37).value, True), @@ -52,6 +57,17 @@ class QLocaleTestToNumber(unittest.TestCase): value = en_locale.toCurrencyString(1234.56) self.assertEqual(value, "$1,234.56") + def testToString(self): + """PYSIDE-2168, check negative values""" + en_locale = QLocale("en_US") + value = en_locale.toString(-4) + self.assertEqual(value, "-4") + # Verify that large types (long long/double) are used. + value = en_locale.toString(3000000000) + self.assertEqual(value, "3,000,000,000") + value = en_locale.toString(10e40) + self.assertEqual(value, "1E+41") + if __name__ == '__main__': unittest.main() diff --git a/sources/pyside6/tests/QtCore/qlockfile_test.py b/sources/pyside6/tests/QtCore/qlockfile_test.py index 106bca02a..6dca9235c 100644 --- a/sources/pyside6/tests/QtCore/qlockfile_test.py +++ b/sources/pyside6/tests/QtCore/qlockfile_test.py @@ -32,6 +32,9 @@ class TestQMessageAuthenticationCode (unittest.TestCase): lockFile = QLockFile(self._fileName) self.assertTrue(lockFile.lock()) self.assertTrue(lockFile.isLocked()) + lock_info = lockFile.getLockInfo(); + self.assertEqual(len(lock_info), 3) + self.assertEqual(lock_info[0], os.getpid()) lockFile.unlock() diff --git a/sources/pyside6/tests/QtCore/qmetaobject_test.py b/sources/pyside6/tests/QtCore/qmetaobject_test.py index ff320b050..4b3051711 100644 --- a/sources/pyside6/tests/QtCore/qmetaobject_test.py +++ b/sources/pyside6/tests/QtCore/qmetaobject_test.py @@ -13,8 +13,8 @@ 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, QFile, QMetaObject, QObject, - QModelIndex, QPoint, QTimer, QSemaphore, +from PySide6.QtCore import (QCoreApplication, QFile, QMetaMethod, QMetaObject, + QObject, QModelIndex, QPoint, QTimer, QSemaphore, QStringListModel, Qt, Signal, Slot, SIGNAL, Q_ARG, Q_RETURN_ARG) @@ -105,15 +105,6 @@ class qmetaobject_test(unittest.TestCase): o.connect(o2, SIGNAL("bars()"), o.slot) self.assertTrue(o2.metaObject().indexOfMethod("bars()") > -1) - #self.assertTrue(o.metaObject().indexOfMethod("bar()") == -1) - #self.assertTrue(o.metaObject().indexOfMethod("slot()") > -1) - - #slot_index = o.metaObject().indexOfMethod("slot()") - - #o.connect(o, SIGNAL("foo()"), o2, SIGNAL("bar()")) - #signal_index = o.metaObject().indexOfMethod("foo()"); - - #self.assertTrue(slot_index != signal_index) # PYSIDE-784, plain Qt objects should not have intermediary # metaObjects. @@ -125,7 +116,7 @@ class qmetaobject_test(unittest.TestCase): # PYSIDE-1827, slots with non-QObject object types should work # (metatypes are registered) def test_ObjectSlotSignal(self): - app = QCoreApplication() + app = QCoreApplication() # noqa: F841 sender = SemaphoreSender() receiver = SemaphoreReceiver() sender.signal.connect(receiver.receiverSlot, Qt.QueuedConnection) @@ -143,6 +134,17 @@ class qmetaobject_test(unittest.TestCase): Q_ARG(int, 2), Q_ARG(int, 3)) self.assertEqual(sum, 5) + # Same with QMetaMethod + mo = tester.metaObject() + method = mo.method(mo.indexOfMethod("add(int,int)")) + self.assertTrue(method.isValid()) + sum = method.invoke(tester, Qt.ConnectionType.AutoConnection, + Q_RETURN_ARG(int), Q_ARG(int, 2), Q_ARG(int, 3)) + self.assertEqual(sum, 5) + sum = method.invoke(tester, Q_RETURN_ARG(int), Q_ARG(int, 2), + Q_ARG(int, 3)) + self.assertEqual(sum, 5) + concatenated = QMetaObject.invokeMethod(tester, "concatenate", Q_RETURN_ARG(str), Q_ARG(str, "bla"), @@ -190,6 +192,22 @@ class qmetaobject_test(unittest.TestCase): Q_ARG("QVariant", "bla")) self.assertEqual(model.data(index), "bla") + # Same with QMetaMethod + mo = model.metaObject() + method = mo.method(mo.indexOfMethod("setData(QModelIndex,QVariant)")) + self.assertTrue(method.isValid()) + method.invoke(model, Qt.ConnectionType.AutoConnection, + Q_ARG(QModelIndex, index), Q_ARG("QVariant", "blub")) + self.assertEqual(model.data(index), "blub") + method.invoke(model, Q_ARG(QModelIndex, index), Q_ARG("QVariant", "blip")) + self.assertEqual(model.data(index), "blip") + + def test_QMetaMethod(self): + o = QObject() + m = QMetaMethod.fromSignal(o.destroyed) + self.assertTrue(m.isValid) + self.assertEqual(m.methodSignature(), b"destroyed()") + if __name__ == '__main__': unittest.main() diff --git a/sources/pyside6/tests/QtCore/qmimedatabase_test.py b/sources/pyside6/tests/QtCore/qmimedatabase_test.py index 90c99edb4..6a63edb85 100644 --- a/sources/pyside6/tests/QtCore/qmimedatabase_test.py +++ b/sources/pyside6/tests/QtCore/qmimedatabase_test.py @@ -4,7 +4,6 @@ '''Unit tests for QMimeDatabase''' -import ctypes import os import sys import unittest @@ -24,8 +23,7 @@ class QMimeDatabaseTest(unittest.TestCase): s0 = db.mimeTypeForName("application/x-zerosize") self.assertTrue(s0.isValid()) self.assertEqual(s0.name(), "application/x-zerosize") - if "en" in QLocale().name(): - self.assertEqual(s0.comment(), "empty document") + self.assertTrue(s0.comment()) s0Again = db.mimeTypeForName("application/x-zerosize") self.assertEqual(s0Again.name(), s0.name()) @@ -40,13 +38,13 @@ class QMimeDatabaseTest(unittest.TestCase): rdf = db.mimeTypeForName("application/rdf+xml") self.assertTrue(rdf.isValid()) self.assertEqual(rdf.name(), "application/rdf+xml") + self.assertTrue(rdf.comment()) if "en" in QLocale().name(): self.assertEqual(rdf.comment(), "RDF file") bzip2 = db.mimeTypeForName("application/x-bzip2") self.assertTrue(bzip2.isValid()) - if "en" in QLocale().name(): - self.assertEqual(bzip2.comment(), "Bzip archive") + self.assertTrue(bzip2.comment()) defaultMime = db.mimeTypeForName("application/octet-stream") self.assertTrue(defaultMime.isValid()) diff --git a/sources/pyside6/tests/QtCore/qobject_connect_notify_test.py b/sources/pyside6/tests/QtCore/qobject_connect_notify_test.py index 409b06c3c..b3bfaf007 100644 --- a/sources/pyside6/tests/QtCore/qobject_connect_notify_test.py +++ b/sources/pyside6/tests/QtCore/qobject_connect_notify_test.py @@ -12,8 +12,8 @@ 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, SLOT -from helper.usesqcoreapplication import UsesQCoreApplication +from PySide6.QtCore import QObject, Signal, SIGNAL, SLOT +from helper.usesqapplication import UsesQApplication def cute_slot(): @@ -21,6 +21,9 @@ def cute_slot(): class Obj(QObject): + + foo = Signal() + def __init__(self): super().__init__() self.con_notified = False @@ -39,49 +42,56 @@ class Obj(QObject): self.dis_notified = False -class TestQObjectConnectNotify(UsesQCoreApplication): +class TestQObjectConnectNotify(UsesQApplication): '''Test case for QObject::connectNotify''' def setUp(self): - UsesQCoreApplication.setUp(self) + UsesQApplication.setUp(self) self.called = False def tearDown(self): - UsesQCoreApplication.tearDown(self) + UsesQApplication.tearDown(self) def testBasic(self): sender = Obj() receiver = QObject() + sender.destroyed.connect(receiver.deleteLater) + self.assertTrue(sender.con_notified) + self.assertEqual(sender.signal.methodSignature(), "destroyed()") + self.assertTrue(sender.destroyed.disconnect(receiver.deleteLater)) + self.assertTrue(sender.dis_notified) + + def testBasicString(self): + sender = Obj() + receiver = QObject() sender.connect(SIGNAL("destroyed()"), receiver, SLOT("deleteLater()")) self.assertTrue(sender.con_notified) # When connecting to a regular slot, and not a python callback function, QObject::connect # will use the non-cloned method signature, so connecting to destroyed() will actually # connect to destroyed(QObject*). self.assertEqual(sender.signal.methodSignature(), "destroyed(QObject*)") - sender.disconnect(SIGNAL("destroyed()"), receiver, SLOT("deleteLater()")) + self.assertTrue(sender.disconnect(SIGNAL("destroyed()"), receiver, SLOT("deleteLater()"))) self.assertTrue(sender.dis_notified) def testPySignal(self): sender = Obj() receiver = QObject() - sender.connect(SIGNAL("foo()"), receiver, SLOT("deleteLater()")) + sender.foo.connect(receiver.deleteLater) self.assertTrue(sender.con_notified) - sender.disconnect(SIGNAL("foo()"), receiver, SLOT("deleteLater()")) + self.assertTrue(sender.foo.disconnect(receiver.deleteLater)) self.assertTrue(sender.dis_notified) def testPySlots(self): sender = Obj() - receiver = QObject() - sender.connect(SIGNAL("destroyed()"), cute_slot) + sender.destroyed.connect(cute_slot) self.assertTrue(sender.con_notified) - sender.disconnect(SIGNAL("destroyed()"), cute_slot) + self.assertTrue(sender.destroyed.disconnect(cute_slot)) self.assertTrue(sender.dis_notified) def testpyAll(self): sender = Obj() - receiver = QObject() - sender.connect(SIGNAL("foo()"), cute_slot) + sender.foo.connect(cute_slot) self.assertTrue(sender.con_notified) - sender.disconnect(SIGNAL("foo()"), cute_slot) + self.assertTrue(sender.foo.disconnect(cute_slot)) self.assertTrue(sender.dis_notified) diff --git a/sources/pyside6/tests/QtCore/qobject_event_filter_test.py b/sources/pyside6/tests/QtCore/qobject_event_filter_test.py index a2870221d..ab7a1b6ad 100644 --- a/sources/pyside6/tests/QtCore/qobject_event_filter_test.py +++ b/sources/pyside6/tests/QtCore/qobject_event_filter_test.py @@ -16,7 +16,7 @@ init_test_paths(False) from PySide6.QtCore import QObject, QTimerEvent -from helper.usesqcoreapplication import UsesQCoreApplication +from helper.usesqapplication import UsesQApplication class FilterObject(QObject): @@ -63,14 +63,25 @@ class FilteredObject(QObject): self.app.quit() -class TestQObjectEventFilterPython(UsesQCoreApplication): +class PolymorphicIdFilterObject(QObject): + """PYSIDE-2675: Check whether QChildEvent.added() is accessible via PolymorphicId""" + def __init__(self, parent=None): + super().__init__(parent) + self.added = False + + def event(self, event): + self.added = event.added() + return False + + +class TestQObjectEventFilterPython(UsesQApplication): '''QObject.eventFilter - Reimplemented in python Filters 5 TimerEvents and then bypasses the other events to the timerEvent method. After 5 runs, the timerEvent method will ask the core application to exit''' def setUp(self): # Acquire resources - UsesQCoreApplication.setUp(self) + UsesQApplication.setUp(self) self.obj_filter = FilterObject(event_type=QTimerEvent) def tearDown(self): @@ -78,7 +89,7 @@ class TestQObjectEventFilterPython(UsesQCoreApplication): del self.obj_filter # PYSIDE-535: Need to collect garbage in PyPy to trigger deletion gc.collect() - UsesQCoreApplication.tearDown(self) + UsesQApplication.tearDown(self) def testEventFilter(self): # QObject.eventFilter reimplemented in python @@ -93,6 +104,11 @@ class TestQObjectEventFilterPython(UsesQCoreApplication): self.assertEqual(filtered.times_called, 5) self.assertEqual(self.obj_filter.events_handled, 5) + def testPolymorphicId(self): + testObject = PolymorphicIdFilterObject() + t2 = QObject(testObject) # noqa: F841 + self.assertTrue(testObject.added) + @unittest.skipUnless(hasattr(sys, "getrefcount"), f"{sys.implementation.name} has no refcount") def testInstallEventFilterRefCountAfterDelete(self): '''Bug 910 - installEventFilter() increments reference count on target object diff --git a/sources/pyside6/tests/QtCore/qobject_parent_test.py b/sources/pyside6/tests/QtCore/qobject_parent_test.py index 160426b01..6265f77b1 100644 --- a/sources/pyside6/tests/QtCore/qobject_parent_test.py +++ b/sources/pyside6/tests/QtCore/qobject_parent_test.py @@ -105,10 +105,9 @@ class ParentCase(unittest.TestCase): for i, child in enumerate(children): self.assertEqual(child, parent.findChild(QObject, f'object{i}')) - def testFindChildOptions(self): parent = QObject() - child = QObject(parent) + child = QObject(parent) nested_child_name = 'nestedChild' nested_child = QObject(child) nested_child.setObjectName(nested_child_name) diff --git a/sources/pyside6/tests/QtCore/qobject_timer_event_test.py b/sources/pyside6/tests/QtCore/qobject_timer_event_test.py index f93d036b4..9e657c27f 100644 --- a/sources/pyside6/tests/QtCore/qobject_timer_event_test.py +++ b/sources/pyside6/tests/QtCore/qobject_timer_event_test.py @@ -15,7 +15,7 @@ init_test_paths(False) from PySide6.QtCore import QObject, QCoreApplication -from helper.usesqcoreapplication import UsesQCoreApplication +from helper.usesqapplication import UsesQApplication class Dummy(QObject): @@ -34,7 +34,7 @@ class Dummy(QObject): self.app.exit(0) -class QObjectTimerEvent(UsesQCoreApplication): +class QObjectTimerEvent(UsesQApplication): def setUp(self): # Acquire resources diff --git a/sources/pyside6/tests/QtCore/qobject_tr_as_instance_test.py b/sources/pyside6/tests/QtCore/qobject_tr_as_instance_test.py index 83e8ae1af..9123c5155 100644 --- a/sources/pyside6/tests/QtCore/qobject_tr_as_instance_test.py +++ b/sources/pyside6/tests/QtCore/qobject_tr_as_instance_test.py @@ -17,7 +17,7 @@ init_test_paths(False) from PySide6.QtCore import QObject -#from helper.usesqcoreapplication import UsesQCoreApplication +#from helper.usesqapplication import UsesQApplication class QObjectTrTest(unittest.TestCase): diff --git a/sources/pyside6/tests/QtCore/qresource_test.py b/sources/pyside6/tests/QtCore/qresource_test.py index 67285adcc..1cdd2c785 100644 --- a/sources/pyside6/tests/QtCore/qresource_test.py +++ b/sources/pyside6/tests/QtCore/qresource_test.py @@ -31,7 +31,7 @@ class ResourcesUsage(unittest.TestCase): if carriage_return != -1: orig.remove(carriage_return, 1) - f = QFile(':/quote.txt') #|QIODevice.Text + f = QFile(':/quote.txt') # |QIODevice.Text self.assertTrue(f.open(QIODevice.ReadOnly), f.errorString()) copy = f.readAll() f.close() diff --git a/sources/pyside6/tests/QtCore/qrunnable_test.py b/sources/pyside6/tests/QtCore/qrunnable_test.py new file mode 100644 index 000000000..d52f50ce1 --- /dev/null +++ b/sources/pyside6/tests/QtCore/qrunnable_test.py @@ -0,0 +1,45 @@ +# Copyright (C) 2023 The Qt Company Ltd. +# SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0 + +'''Test cases for QRunnable''' + +import os +import sys +import unittest +from io import StringIO + +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, QRunnable, QThreadPool, QThread, qDebug +from helper.usesqapplication import UsesQApplication +test_result = "" + + +def check_test(): + global test_result + test_result = "test works" + + +class QRunnableTest(UsesQApplication): + def testCreateWithAutoDelete(self): + global test_result + test_result = "" # reset + runnable = QRunnable.create(check_test) + runnable.run() + self.assertEqual(test_result, "test works") + + def testwithQThreadPool(self): + global test_result + test_result = "" # reset + runnable = QRunnable.create(check_test) + tp = QThreadPool.globalInstance() + tp.start(runnable) + self.assertTrue(tp.waitForDone()) + self.assertEqual(test_result, "test works") + + +if __name__ == '__main__': + unittest.main() diff --git a/sources/pyside6/tests/QtCore/qsettings_test.py b/sources/pyside6/tests/QtCore/qsettings_test.py index 5bae79355..64ceffd70 100644 --- a/sources/pyside6/tests/QtCore/qsettings_test.py +++ b/sources/pyside6/tests/QtCore/qsettings_test.py @@ -51,8 +51,12 @@ class TestQSettings(unittest.TestCase): self.assertTrue(dir.isValid()) file_name = dir.filePath('foo.ini') settings = QSettings(file_name, QSettings.IniFormat) + sample_list = ["a", "b"] + string_list_of_empty = [""] settings.setValue('zero_value', 0) settings.setValue('empty_list', []) + settings.setValue('some_strings', sample_list) + settings.setValue('string_list_of_empty', string_list_of_empty) settings.setValue('bool1', False) settings.setValue('bool2', True) del settings @@ -66,6 +70,10 @@ class TestQSettings(unittest.TestCase): r = settings.value("variable") self.assertEqual(type(r), type(None)) + r = settings.value("variable", type=list) + self.assertEqual(type(r), list) + self.assertEqual(len(r), 0) + # Handling zero value r = settings.value('zero_value') self.assertEqual(type(r), int) @@ -82,6 +90,15 @@ class TestQSettings(unittest.TestCase): self.assertTrue(len(r) == 0) self.assertEqual(type(r), list) + r = settings.value('some_strings') + self.assertEqual(r, sample_list) + + r = settings.value('some_strings', type=list) + self.assertEqual(r, sample_list) + + r = settings.value('string_list_of_empty', type=list) + self.assertEqual(r, string_list_of_empty) + # Booleans r = settings.value('bool1') self.assertEqual(type(r), bool) diff --git a/sources/pyside6/tests/QtCore/qslot_object_test.py b/sources/pyside6/tests/QtCore/qslot_object_test.py index 061ce9160..a95afb090 100644 --- a/sources/pyside6/tests/QtCore/qslot_object_test.py +++ b/sources/pyside6/tests/QtCore/qslot_object_test.py @@ -11,7 +11,7 @@ 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, QObject, QTimer, SIGNAL, SLOT +from PySide6.QtCore import QCoreApplication, QObject, QTimer """ This is a simple slot test that was updated to use the qApp "macro". @@ -28,24 +28,23 @@ class objTest(QObject): def slot(self): self.ok = True - qApp.quit() + qApp.quit() # noqa: F821 class slotTest(unittest.TestCase): def quit_app(self): - qApp.quit() + qApp.quit() # noqa: F821 def testBasic(self): timer = QTimer() timer.setInterval(100) my_obj = objTest() - my_slot = SLOT("slot()") - QObject.connect(timer, SIGNAL("timeout()"), my_obj, my_slot) + timer.timeout.connect(my_obj.slot) timer.start(100) QTimer.singleShot(1000, self.quit_app) - qApp.exec() + qApp.exec() # noqa: F821 self.assertTrue(my_obj.ok) diff --git a/sources/pyside6/tests/QtCore/qsysinfo_test.py b/sources/pyside6/tests/QtCore/qsysinfo_test.py index a25f7d115..602852fab 100644 --- a/sources/pyside6/tests/QtCore/qsysinfo_test.py +++ b/sources/pyside6/tests/QtCore/qsysinfo_test.py @@ -14,15 +14,14 @@ from PySide6.QtCore import QSysInfo class TestQSysInfo(unittest.TestCase): - newenum = sys.pyside63_option_python_enum def testEnumEndian(self): - self.assertEqual(QSysInfo.BigEndian.value if self.newenum else QSysInfo.BigEndian, 0) - self.assertEqual(QSysInfo.LittleEndian.value if self.newenum else QSysInfo.LittleEndian, 1) - self.assertTrue((QSysInfo.ByteOrder.value if self.newenum else QSysInfo.ByteOrder) > -1) + self.assertEqual(QSysInfo.BigEndian.value, 0) + self.assertEqual(QSysInfo.LittleEndian.value, 1) + self.assertTrue(QSysInfo.ByteOrder.value > -1) def testEnumSizes(self): - self.assertTrue((QSysInfo.WordSize.value if self.newenum else QSysInfo.WordSize) > 0) + self.assertTrue(QSysInfo.WordSize.value > 0) if __name__ == '__main__': diff --git a/sources/pyside6/tests/QtCore/qthread_test.py b/sources/pyside6/tests/QtCore/qthread_test.py index d81d36db0..4d26e0597 100644 --- a/sources/pyside6/tests/QtCore/qthread_test.py +++ b/sources/pyside6/tests/QtCore/qthread_test.py @@ -16,7 +16,7 @@ init_test_paths(False) from PySide6.QtCore import QThread, QCoreApplication, QObject, QTimer, Slot from PySide6.QtCore import QEventLoop -from helper.usesqcoreapplication import UsesQCoreApplication +from helper.usesqapplication import UsesQApplication class Dummy(QThread): @@ -31,10 +31,10 @@ class Dummy(QThread): self.called = True -class QThreadSimpleCase(UsesQCoreApplication): +class QThreadSimpleCase(UsesQApplication): def setUp(self): - UsesQCoreApplication.setUp(self) + UsesQApplication.setUp(self) self._started_called = False self._finished_called = False self.called = False diff --git a/sources/pyside6/tests/QtCore/qtimer_singleshot_test.py b/sources/pyside6/tests/QtCore/qtimer_singleshot_test.py index e702f4792..2ccaa300e 100644 --- a/sources/pyside6/tests/QtCore/qtimer_singleshot_test.py +++ b/sources/pyside6/tests/QtCore/qtimer_singleshot_test.py @@ -14,8 +14,8 @@ 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, QCoreApplication, Signal -from helper.usesqcoreapplication import UsesQCoreApplication +from PySide6.QtCore import QObject, QThread, QTimer, Signal, Slot, SLOT +from helper.usesqapplication import UsesQApplication class WatchDog(QObject): @@ -32,14 +32,28 @@ class WatchDog(QObject): self.watched.exit_app_cb() -class TestSingleShot(UsesQCoreApplication): +class ThreadForContext(QThread): + def __init__(self): + super().__init__() + self.called = False + self.qthread = None + self.context = QObject() + + def run(self): + self.called = True + self.qthread = QThread.currentThread() + self.exec() + + +class TestSingleShot(UsesQApplication): '''Test case for QTimer.singleShot''' def setUp(self): # Acquire resources - UsesQCoreApplication.setUp(self) + UsesQApplication.setUp(self) self.watchdog = WatchDog(self) self.called = False + self.qthread = None def tearDown(self): # Release resources @@ -47,10 +61,12 @@ class TestSingleShot(UsesQCoreApplication): del self.called # PYSIDE-535: Need to collect garbage in PyPy to trigger deletion gc.collect() - UsesQCoreApplication.tearDown(self) + UsesQApplication.tearDown(self) def callback(self): self.called = True + self.qthread = QThread.currentThread() + self.qthread.exit() self.app.quit() def testSingleShot(self): @@ -58,17 +74,94 @@ class TestSingleShot(UsesQCoreApplication): self.app.exec() self.assertTrue(self.called) + def testSingleShotZero(self): + QTimer.singleShot(0, self.callback) + self.app.exec() + self.assertTrue(self.called) + + def testSingleShotWithContext(self): + thread = ThreadForContext() + thread.start() + thread.context.moveToThread(thread) + QTimer.singleShot(100, thread.context, self.callback) + self.app.exec() + thread.wait() + self.assertTrue(self.called) + self.assertTrue(thread.called) + self.assertEqual(self.qthread, thread.qthread) + + def testSingleShotWithContextZero(self): + thread = ThreadForContext() + thread.start() + thread.context.moveToThread(thread) + QTimer.singleShot(0, thread.context, self.callback) + self.app.exec() + thread.wait() + self.assertTrue(self.called) + self.assertTrue(thread.called) + self.assertEqual(self.qthread, thread.qthread) + + +class TestSingleShotCallableObject(UsesQApplication): + '''Test case for QTimer.singleShot with callable inside an object''' + + def setUp(self): + # Acquire resources + UsesQApplication.setUp(self) + self.watchdog = WatchDog(self) + + def tearDown(self): + # Release resources + del self.watchdog + # PYSIDE-535: Need to collect garbage in PyPy to trigger deletion + gc.collect() + UsesQApplication.tearDown(self) + + class CallbackObject(QObject): + def __init__(self, app) -> None: + super().__init__() + self.app = app + + @Slot() + def func(self): + self.called = True + self.app.quit() + + def testSingleShotWithObjectAndMember(self): + callback = self.CallbackObject(self.app) + QTimer.singleShot(100, callback, SLOT("func()")) + self.app.exec() + self.assertTrue(callback.called) + + def testSingleShotWithObjectAndMemberZero(self): + callback = self.CallbackObject(self.app) + QTimer.singleShot(0, callback, SLOT("func()")) + self.app.exec() + self.assertTrue(callback.called) + + def testSingleShotWithCallableInObject(self): + callback = self.CallbackObject(self.app) + QTimer.singleShot(100, callback.func) + self.app.exec() + self.assertTrue(callback.called) + + def testSingleShotWithCallableInObjectZero(self): + callback = self.CallbackObject(self.app) + QTimer.singleShot(0, callback.func) + self.app.exec() + self.assertTrue(callback.called) + class SigEmitter(QObject): sig1 = Signal() -class TestSingleShotSignal(UsesQCoreApplication): +class TestSingleShotSignal(UsesQApplication): '''Test case for QTimer.singleShot connecting to signals''' def setUp(self): - UsesQCoreApplication.setUp(self) + UsesQApplication.setUp(self) self.watchdog = WatchDog(self) self.called = False @@ -77,7 +170,7 @@ class TestSingleShotSignal(UsesQCoreApplication): del self.called # PYSIDE-535: Need to collect garbage in PyPy to trigger deletion gc.collect() - UsesQCoreApplication.tearDown(self) + UsesQApplication.tearDown(self) def callback(self): self.called = True @@ -90,7 +183,13 @@ class TestSingleShotSignal(UsesQCoreApplication): self.app.exec() self.assertTrue(self.called) + def testSingleShotSignalZero(self): + emitter = SigEmitter() + emitter.sig1.connect(self.callback) + QTimer.singleShot(0, emitter.sig1) + self.app.exec() + self.assertTrue(self.called) + if __name__ == '__main__': unittest.main() - diff --git a/sources/pyside6/tests/QtCore/qtimer_timeout_test.py b/sources/pyside6/tests/QtCore/qtimer_timeout_test.py index b853ee85d..70f151989 100644 --- a/sources/pyside6/tests/QtCore/qtimer_timeout_test.py +++ b/sources/pyside6/tests/QtCore/qtimer_timeout_test.py @@ -14,7 +14,7 @@ from init_paths import init_test_paths init_test_paths(False) from PySide6.QtCore import QObject, QTimer, SIGNAL -from helper.usesqcoreapplication import UsesQCoreApplication +from helper.usesqapplication import UsesQApplication class WatchDog(QObject): @@ -31,12 +31,12 @@ class WatchDog(QObject): self.watched.exit_app_cb() -class TestTimeoutSignal(UsesQCoreApplication): +class TestTimeoutSignal(UsesQApplication): '''Test case to check if the signals are really being caught''' def setUp(self): # Acquire resources - UsesQCoreApplication.setUp(self) + super().setUp() self.watchdog = WatchDog(self) self.timer = QTimer() self.called = False @@ -48,7 +48,7 @@ class TestTimeoutSignal(UsesQCoreApplication): del self.called # PYSIDE-535: Need to collect garbage in PyPy to trigger deletion gc.collect() - UsesQCoreApplication.tearDown(self) + super().tearDown() def callback(self, *args): # Default callback diff --git a/sources/pyside6/tests/QtCore/signal_sender.py b/sources/pyside6/tests/QtCore/signal_sender.py new file mode 100644 index 000000000..2552591e5 --- /dev/null +++ b/sources/pyside6/tests/QtCore/signal_sender.py @@ -0,0 +1,91 @@ +# 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 (QCoreApplication, QObject, QStringListModel, + QTimer, Signal, Slot, Qt) + + +class Sender(QObject): + testSignal = Signal() + + def emitSignal(self): + self.testSignal.emit() + + +class Receiver(QObject): + + def __init__(self, parent=None): + super().__init__() + self._sender = None + self._slot_count = 0 + + @Slot() + def testSlot(self): + self._sender = self.sender() + self._slot_count += 1 + + +class DerivedReceiver(Receiver): + pass + + +class TestSignalSender(UsesQApplication): + """Test PYSIDE-2144/1295, check that QObject::sender() works also if it is + routed via GlobalReceiverV2 in case of a non-C++ slot (Python callback, + as for derived classes).""" + def testSignalSender(self): + sender = Sender() + receiver = Receiver() + sender.testSignal.connect(receiver.testSlot) + derived_receiver = DerivedReceiver() + sender.testSignal.connect(derived_receiver.testSlot) + sender.emitSignal() + + QTimer.singleShot(100, self.app.quit) + while derived_receiver._slot_count == 0: + QCoreApplication.processEvents() + + self.assertEqual(receiver._sender, sender) + self.assertEqual(derived_receiver._sender, sender) + + +class TestConstructorConnection(UsesQApplication): + """PYSIDE-2329: Check constructor connections for signals from the + base as well as signals with arguments.""" + def testConstructorConnection(self): + + was_destroyed = False + was_changed = False + + def destroyed_handler(): + nonlocal was_destroyed + was_destroyed = True + + def changed_handler(): + nonlocal was_changed + was_changed = True + + data_list = ["blub"] + model = QStringListModel(data_list, + destroyed=destroyed_handler, + dataChanged=changed_handler) + model.setData(model.index(0, 0), "bla", Qt.EditRole) + del model + + self.assertTrue(was_changed) + self.assertTrue(was_destroyed) + + +if __name__ == '__main__': + unittest.main() diff --git a/sources/pyside6/tests/QtCore/snake_prop_feature_test.py b/sources/pyside6/tests/QtCore/snake_prop_feature_test.py index 4178c7a10..82087ab9a 100644 --- a/sources/pyside6/tests/QtCore/snake_prop_feature_test.py +++ b/sources/pyside6/tests/QtCore/snake_prop_feature_test.py @@ -60,7 +60,7 @@ class FeatureTest(unittest.TestCase): window.modal from __feature__ import snake_case, true_property - #PYSIDE-1548: Make sure that another import does not clear the features. + # PYSIDE-1548: Make sure that another import does not clear the features. import sys self.assertTrue(isinstance(QWidget.modal, property)) diff --git a/sources/pyside6/tests/QtCore/thread_signals_test.py b/sources/pyside6/tests/QtCore/thread_signals_test.py index 80cda6b92..a453d1ac1 100644 --- a/sources/pyside6/tests/QtCore/thread_signals_test.py +++ b/sources/pyside6/tests/QtCore/thread_signals_test.py @@ -12,17 +12,19 @@ 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, QFile, QThread, QTimer, Qt -from helper.usesqcoreapplication import UsesQCoreApplication +from PySide6.QtCore import Signal, QThread +from helper.usesqapplication import UsesQApplication class MyThread(QThread): + test = Signal(str) + def run(self): - self.emit(SIGNAL("test(const QString&)"), "INdT - PySide") + self.test.emit("INdT - PySide") -class TestThreadSignal(UsesQCoreApplication): +class TestThreadSignal(UsesQApplication): __called__ = True @@ -33,7 +35,7 @@ class TestThreadSignal(UsesQCoreApplication): def testThread(self): t = MyThread() - QObject.connect(t, SIGNAL("test(const QString&)"), self._callback) + t.test.connect(self._callback) t.start() self.app.exec() diff --git a/sources/pyside6/tests/QtCore/translation_test.py b/sources/pyside6/tests/QtCore/translation_test.py index aad0ce7c8..da09e47b6 100644 --- a/sources/pyside6/tests/QtCore/translation_test.py +++ b/sources/pyside6/tests/QtCore/translation_test.py @@ -15,10 +15,10 @@ init_test_paths(False) from PySide6.QtCore import QObject, QTranslator, QCoreApplication -from helper.usesqcoreapplication import UsesQCoreApplication +from helper.usesqapplication import UsesQApplication -class TranslationTest(UsesQCoreApplication): +class TranslationTest(UsesQApplication): '''Test case for Qt translation facilities.''' def setUp(self): |