summaryrefslogtreecommitdiffstats
path: root/tests/auto/qobject
diff options
context:
space:
mode:
authorQt by Nokia <qt-info@nokia.com>2011-04-27 12:05:43 +0200
committeraxis <qt-info@nokia.com>2011-04-27 12:05:43 +0200
commit38be0d13830efd2d98281c645c3a60afe05ffece (patch)
tree6ea73f3ec77f7d153333779883e8120f82820abe /tests/auto/qobject
Initial import from the monolithic Qt.
This is the beginning of revision history for this module. If you want to look at revision history older than this, please refer to the Qt Git wiki for how to use Git history grafting. At the time of writing, this wiki is located here: http://qt.gitorious.org/qt/pages/GitIntroductionWithQt If you have already performed the grafting and you don't see any history beyond this commit, try running "git log" with the "--follow" argument. Branched from the monolithic repo, Qt master branch, at commit 896db169ea224deb96c59ce8af800d019de63f12
Diffstat (limited to 'tests/auto/qobject')
-rw-r--r--tests/auto/qobject/.gitignore3
-rw-r--r--tests/auto/qobject/moc_oldnormalizeobject.cpp154
-rw-r--r--tests/auto/qobject/oldnormalizeobject.h69
-rw-r--r--tests/auto/qobject/qobject.pro3
-rw-r--r--tests/auto/qobject/signalbug.cpp151
-rw-r--r--tests/auto/qobject/signalbug.h103
-rw-r--r--tests/auto/qobject/signalbug.pro19
-rw-r--r--tests/auto/qobject/tst_qobject.cpp3958
-rw-r--r--tests/auto/qobject/tst_qobject.pro21
9 files changed, 4481 insertions, 0 deletions
diff --git a/tests/auto/qobject/.gitignore b/tests/auto/qobject/.gitignore
new file mode 100644
index 0000000000..ea4d6d7f06
--- /dev/null
+++ b/tests/auto/qobject/.gitignore
@@ -0,0 +1,3 @@
+tst_qobject
+signalbug
+signalbug.exe
diff --git a/tests/auto/qobject/moc_oldnormalizeobject.cpp b/tests/auto/qobject/moc_oldnormalizeobject.cpp
new file mode 100644
index 0000000000..2dba9ac217
--- /dev/null
+++ b/tests/auto/qobject/moc_oldnormalizeobject.cpp
@@ -0,0 +1,154 @@
+/****************************************************************************
+**
+** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the test suite of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+/****************************************************************************
+** Meta object code from reading C++ file 'oldnormalizeobject.h'
+**
+** Created: Wed Nov 18 11:43:05 2009
+** by: The Qt Meta Object Compiler version 62 (Qt 4.6.0)
+**
+*****************************************************************************/
+
+// Yhis file was generated from moc version 4.6 to test binary compatibility
+// It should *not* be generated by the current moc
+
+#include "oldnormalizeobject.h"
+
+QT_BEGIN_MOC_NAMESPACE
+static const uint qt_meta_data_OldNormalizeObject[] = {
+
+ // content:
+ 4, // revision
+ 0, // classname
+ 0, 0, // classinfo
+ 6, 14, // methods
+ 0, 0, // properties
+ 0, 0, // enums/sets
+ 0, 0, // constructors
+ 0, // flags
+ 3, // signalCount
+
+ // signals: signature, parameters, type, tag, flags
+ 24, 20, 19, 19, 0x05,
+ 57, 20, 19, 19, 0x05,
+ 100, 20, 19, 19, 0x05,
+
+ // slots: signature, parameters, type, tag, flags
+ 149, 20, 19, 19, 0x0a,
+ 180, 20, 19, 19, 0x0a,
+ 221, 20, 19, 19, 0x0a,
+
+ 0 // eod
+};
+
+static const char qt_meta_stringdata_OldNormalizeObject[] = {
+ "OldNormalizeObject\0\0ref\0"
+ "typeRefSignal(Template<Class&>&)\0"
+ "constTypeRefSignal(Template<const Class&>)\0"
+ "typeConstRefSignal(Template<const Class&>const&)\0"
+ "typeRefSlot(Template<Class&>&)\0"
+ "constTypeRefSlot(Template<const Class&>)\0"
+ "typeConstRefSlot(Template<const Class&>const&)\0"
+};
+
+const QMetaObject OldNormalizeObject::staticMetaObject = {
+ { &QObject::staticMetaObject, qt_meta_stringdata_OldNormalizeObject,
+ qt_meta_data_OldNormalizeObject, 0 }
+};
+
+#ifdef Q_NO_DATA_RELOCATION
+const QMetaObject &OldNormalizeObject::getStaticMetaObject() { return staticMetaObject; }
+#endif //Q_NO_DATA_RELOCATION
+
+const QMetaObject *OldNormalizeObject::metaObject() const
+{
+ return QObject::d_ptr->metaObject ? QObject::d_ptr->metaObject : &staticMetaObject;
+}
+
+void *OldNormalizeObject::qt_metacast(const char *_clname)
+{
+ if (!_clname) return 0;
+ if (!strcmp(_clname, qt_meta_stringdata_OldNormalizeObject))
+ return static_cast<void*>(const_cast< OldNormalizeObject*>(this));
+ return QObject::qt_metacast(_clname);
+}
+
+int OldNormalizeObject::qt_metacall(QMetaObject::Call _c, int _id, void **_a)
+{
+ _id = QObject::qt_metacall(_c, _id, _a);
+ if (_id < 0)
+ return _id;
+ if (_c == QMetaObject::InvokeMetaMethod) {
+ switch (_id) {
+ case 0: typeRefSignal((*reinterpret_cast< Template<Class&>(*)>(_a[1]))); break;
+ case 1: constTypeRefSignal((*reinterpret_cast< const Template<const Class&>(*)>(_a[1]))); break;
+ case 2: typeConstRefSignal((*reinterpret_cast< Template<const Class&>const(*)>(_a[1]))); break;
+ case 3: typeRefSlot((*reinterpret_cast< Template<Class&>(*)>(_a[1]))); break;
+ case 4: constTypeRefSlot((*reinterpret_cast< const Template<const Class&>(*)>(_a[1]))); break;
+ case 5: typeConstRefSlot((*reinterpret_cast< Template<const Class&>const(*)>(_a[1]))); break;
+ default: ;
+ }
+ _id -= 6;
+ }
+ return _id;
+}
+
+// SIGNAL 0
+void OldNormalizeObject::typeRefSignal(Template<Class&> & _t1)
+{
+ void *_a[] = { 0, const_cast<void*>(reinterpret_cast<const void*>(&_t1)) };
+ QMetaObject::activate(this, &staticMetaObject, 0, _a);
+}
+
+// SIGNAL 1
+void OldNormalizeObject::constTypeRefSignal(const Template<const Class&> & _t1)
+{
+ void *_a[] = { 0, const_cast<void*>(reinterpret_cast<const void*>(&_t1)) };
+ QMetaObject::activate(this, &staticMetaObject, 1, _a);
+}
+
+// SIGNAL 2
+void OldNormalizeObject::typeConstRefSignal(Template<Class const&> const & _t1)
+{
+ void *_a[] = { 0, const_cast<void*>(reinterpret_cast<const void*>(&_t1)) };
+ QMetaObject::activate(this, &staticMetaObject, 2, _a);
+}
+QT_END_MOC_NAMESPACE
diff --git a/tests/auto/qobject/oldnormalizeobject.h b/tests/auto/qobject/oldnormalizeobject.h
new file mode 100644
index 0000000000..41bce02775
--- /dev/null
+++ b/tests/auto/qobject/oldnormalizeobject.h
@@ -0,0 +1,69 @@
+/****************************************************************************
+**
+** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the QtTest module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef OLDNORMALIZEOBJECT_H
+#define OLDNORMALIZEOBJECT_H
+
+#include <QObject>
+
+struct Struct;
+class Class;
+template <typename T> class Template;
+
+// An object with old moc output that incorrectly normalizes 'T<C> const &' in the function
+// signatures
+class OldNormalizeObject : public QObject
+{
+ /* tmake ignore Q_OBJECT */
+ Q_OBJECT
+
+signals:
+ void typeRefSignal(Template<Class &> &ref);
+ void constTypeRefSignal(const Template<const Class &> &ref);
+ void typeConstRefSignal(Template<Class const &> const &ref);
+
+public slots:
+ void typeRefSlot(Template<Class &> &) {}
+ void constTypeRefSlot(const Template<const Class &> &) {}
+ void typeConstRefSlot(Template<Class const &> const &) {}
+};
+
+#endif // OLDNORMALIZEOBJECT_H
diff --git a/tests/auto/qobject/qobject.pro b/tests/auto/qobject/qobject.pro
new file mode 100644
index 0000000000..113e14a61d
--- /dev/null
+++ b/tests/auto/qobject/qobject.pro
@@ -0,0 +1,3 @@
+TEMPLATE = subdirs
+SUBDIRS = tst_qobject.pro signalbug.pro
+CONFIG += parallel_test
diff --git a/tests/auto/qobject/signalbug.cpp b/tests/auto/qobject/signalbug.cpp
new file mode 100644
index 0000000000..f9c9650ef5
--- /dev/null
+++ b/tests/auto/qobject/signalbug.cpp
@@ -0,0 +1,151 @@
+/****************************************************************************
+**
+** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the test suite of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "signalbug.h"
+
+#include <qcoreapplication.h>
+#include <qstring.h>
+
+#include <stdio.h>
+
+static int Step = 0;
+Sender RandomSender (0, 0);
+
+
+void TRACE (int step, const char *name)
+{
+ for (int t = 0; t < step - 1; t++)
+ fprintf (stderr, "\t");
+ fprintf (stderr, "Step %d: %s\n", step, name);
+ return;
+}
+
+
+Receiver::Receiver ()
+ : QObject ()
+{
+}
+
+void Receiver::received ()
+{
+ ::Step++;
+ const int stepCopy = ::Step;
+ TRACE (stepCopy, "Receiver::received()");
+ Q_ASSERT (::Step == 2 || ::Step == 4);
+
+ if (::Step == 2)
+ s->fire ();
+
+ fprintf (stderr, "Receiver<%s>::received() sender=%s\n",
+ (const char *) objectName ().toAscii (), sender ()->metaObject()->className());
+
+ TRACE (stepCopy, "ends Receiver::received()");
+}
+
+
+Disconnector::Disconnector ()
+ : QObject ()
+{
+}
+
+void Disconnector::received ()
+{
+ ::Step++;
+ const int stepCopy = ::Step;
+ TRACE (stepCopy, "Disconnector::received()");
+ Q_ASSERT (::Step == 5 || ::Step == 6);
+
+ fprintf (stderr, "Disconnector<%s>::received() sender=%s\n",
+ (const char *) objectName ().toAscii (), sender ()->metaObject()->className());
+ if (sender () == 0)
+ fprintf (stderr, "WE SHOULD NOT BE RECEIVING THIS SIGNAL\n");
+
+ if (::Step == 5)
+ {
+ disconnect (s, SIGNAL (fired ()), s->d, SLOT (received ()));
+
+ connect (&RandomSender, SIGNAL (fired ()), s->d, SLOT (received ()));
+ }
+
+ TRACE (stepCopy, "ends Disconnector::received()");
+}
+
+
+Sender::Sender (Receiver *r, Disconnector *d)
+ : QObject ()
+{
+ this->r = r; this->d = d;
+ if (r)
+ connect (this, SIGNAL (fired ()), r, SLOT (received ()));
+ if (d)
+ connect (this, SIGNAL (fired ()), d, SLOT (received ()));
+};
+
+void Sender::fire ()
+{
+ ::Step++;
+ const int stepCopy = ::Step;
+ TRACE (stepCopy, "Sender::fire()");
+ Q_ASSERT (::Step == 1 || ::Step == 3);
+
+ emit fired ();
+ TRACE (stepCopy, "ends Sender::fire()");
+}
+
+
+int main (int argc, char *argv [])
+{
+ QCoreApplication app (argc, argv);
+
+ Receiver r;
+ Disconnector d;
+ Sender s (&r, &d);
+
+ r.s = &s;
+ d.s = &s;
+
+
+ ::Step = 0;
+ s.fire ();
+ return 0;
+}
+
+
diff --git a/tests/auto/qobject/signalbug.h b/tests/auto/qobject/signalbug.h
new file mode 100644
index 0000000000..a84421685b
--- /dev/null
+++ b/tests/auto/qobject/signalbug.h
@@ -0,0 +1,103 @@
+/****************************************************************************
+**
+** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the test suite of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef SIGNAL_BUG_H
+#define SIGNAL_BUG_H
+
+
+#include <QObject>
+
+
+class Sender;
+
+
+class Receiver : public QObject
+{
+Q_OBJECT
+
+public:
+ Receiver ();
+ virtual ~Receiver () {}
+
+protected slots:
+ void received ();
+
+public:
+ Sender *s;
+};
+
+
+class Disconnector : public QObject
+{
+Q_OBJECT
+
+public:
+ Disconnector ();
+ virtual ~Disconnector () {}
+
+protected slots:
+ void received ();
+
+public:
+ Sender *s;
+};
+
+
+class Sender : public QObject
+{
+Q_OBJECT
+
+public:
+ Sender (Receiver *r, Disconnector *d);
+ virtual ~Sender () {}
+
+ void fire ();
+
+signals:
+ void fired ();
+
+public:
+ Receiver *r;
+ Disconnector *d;
+};
+
+
+#endif // SIGNAL_BUG_H
diff --git a/tests/auto/qobject/signalbug.pro b/tests/auto/qobject/signalbug.pro
new file mode 100644
index 0000000000..a835264a93
--- /dev/null
+++ b/tests/auto/qobject/signalbug.pro
@@ -0,0 +1,19 @@
+######################################################################
+# Automatically generated by qmake (2.01a) Tue Aug 15 13:45:41 2006
+######################################################################
+
+TEMPLATE = app
+TARGET =
+DEPENDPATH += .
+INCLUDEPATH += .
+CONFIG -= app_bundle debug_and_release
+DESTDIR=.
+QT -= gui
+wince*: {
+ LIBS += coredll.lib
+}
+# Input
+HEADERS += signalbug.h
+SOURCES += signalbug.cpp
+
+
diff --git a/tests/auto/qobject/tst_qobject.cpp b/tests/auto/qobject/tst_qobject.cpp
new file mode 100644
index 0000000000..4b926e450e
--- /dev/null
+++ b/tests/auto/qobject/tst_qobject.cpp
@@ -0,0 +1,3958 @@
+/****************************************************************************
+**
+** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the test suite of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+
+#define QT3_SUPPORT
+#include <QtTest/QtTest>
+
+
+#include <qcoreapplication.h>
+
+#include <qpointer.h>
+#include <qtimer.h>
+#include <qregexp.h>
+#include <qmetaobject.h>
+#include <qvariant.h>
+
+#include <QTcpServer>
+#include <QTcpSocket>
+#include <QThread>
+#include <QMutex>
+#include <QWaitCondition>
+#include <QProcess>
+
+#include "qobject.h"
+#ifdef QT_BUILD_INTERNAL
+#include <private/qobject_p.h>
+#endif
+
+
+#include <math.h>
+
+//TESTED_CLASS=
+//TESTED_FILES=
+
+class tst_QObject : public QObject
+{
+ Q_OBJECT
+
+public:
+ tst_QObject();
+ virtual ~tst_QObject();
+
+
+public slots:
+ void initTestCase();
+ void cleanupTestCase();
+ void init();
+ void cleanup();
+private slots:
+ void disconnect();
+ void connectByName();
+ void connectSignalsToSignalsWithDefaultArguments();
+ void receivers();
+ void normalize();
+ void qobject_castTemplate();
+ void findChildren();
+ void connectDisconnectNotify_data();
+ void connectDisconnectNotify();
+ void emitInDefinedOrder();
+ void customTypes();
+ void streamCustomTypes();
+ void metamethod();
+ void namespaces();
+ void threadSignalEmissionCrash();
+ void thread();
+ void thread0();
+ void moveToThread();
+ void sender();
+ void declareInterface();
+ void qpointerResetBeforeDestroyedSignal();
+ void testUserData();
+ void childDeletesItsSibling();
+ void dynamicProperties();
+ void floatProperty();
+ void qrealProperty();
+ void property();
+ void recursiveSignalEmission();
+ void blockingQueuedConnection();
+ void compatibilityChildInsertedEvents();
+ void installEventFilter();
+ void deleteSelfInSlot();
+ void disconnectSelfInSlotAndDeleteAfterEmit();
+ void dumpObjectInfo();
+ void connectToSender();
+ void qobjectConstCast();
+ void uniqConnection();
+ void interfaceIid();
+ void deleteQObjectWhenDeletingEvent();
+ void overloads();
+ void isSignalConnected();
+ void qMetaObjectConnect();
+ void qMetaObjectDisconnectOne();
+ void sameName();
+ void connectByMetaMethods();
+ void connectByMetaMethodSlotInsteadOfSignal();
+ void connectConstructorByMetaMethod();
+ void disconnectByMetaMethod();
+ void disconnectNotSignalMetaMethod();
+ void autoConnectionBehavior();
+ void baseDestroyed();
+protected:
+};
+
+tst_QObject::tst_QObject()
+{
+
+}
+
+tst_QObject::~tst_QObject()
+{
+
+}
+
+void tst_QObject::initTestCase()
+{
+}
+
+void tst_QObject::cleanupTestCase()
+{
+}
+
+void tst_QObject::init()
+{
+}
+
+void tst_QObject::cleanup()
+{
+}
+
+class SenderObject : public QObject
+{
+ Q_OBJECT
+
+public:
+ SenderObject() : aPublicSlotCalled(0), recursionCount(0) {}
+
+ void emitSignal1AfterRecursion()
+ {
+ if (recursionCount++ < 100)
+ emitSignal1AfterRecursion();
+ else
+ emitSignal1();
+ }
+
+ void emitSignal1() { emit signal1(); }
+ void emitSignal2() { emit signal2(); }
+ void emitSignal3() { emit signal3(); }
+ void emitSignal4() { emit signal4(); }
+
+signals:
+ void signal1();
+ void signal2();
+ void signal3();
+ void signal4();
+ QT_MOC_COMPAT void signal5();
+
+public slots:
+ void aPublicSlot() { aPublicSlotCalled++; }
+
+public:
+ Q_INVOKABLE void invoke1(){}
+ Q_SCRIPTABLE void sinvoke1(){}
+ int aPublicSlotCalled;
+protected:
+ Q_INVOKABLE QT_MOC_COMPAT void invoke2(){}
+ Q_INVOKABLE QT_MOC_COMPAT void invoke2(int){}
+ Q_SCRIPTABLE QT_MOC_COMPAT void sinvoke2(){}
+private:
+ Q_INVOKABLE void invoke3(int hinz = 0, int kunz = 0){Q_UNUSED(hinz) Q_UNUSED(kunz)}
+ Q_SCRIPTABLE void sinvoke3(){}
+
+ int recursionCount;
+};
+
+class ReceiverObject : public QObject
+{
+ Q_OBJECT
+
+public:
+ ReceiverObject() : sequence_slot1( 0 ),
+ sequence_slot2( 0 ),
+ sequence_slot3( 0 ),
+ sequence_slot4( 0 ) {}
+
+ void reset() {
+ sequence_slot4 = 0;
+ sequence_slot3 = 0;
+ sequence_slot2 = 0;
+ sequence_slot1 = 0;
+ count_slot1 = 0;
+ count_slot2 = 0;
+ count_slot3 = 0;
+ count_slot4 = 0;
+ }
+
+ int sequence_slot1;
+ int sequence_slot2;
+ int sequence_slot3;
+ int sequence_slot4;
+ int count_slot1;
+ int count_slot2;
+ int count_slot3;
+ int count_slot4;
+
+ bool called(int slot) {
+ switch (slot) {
+ case 1: return sequence_slot1;
+ case 2: return sequence_slot2;
+ case 3: return sequence_slot3;
+ case 4: return sequence_slot4;
+ default: return false;
+ }
+ }
+
+ static int sequence;
+
+public slots:
+ void slot1() { sequence_slot1 = ++sequence; count_slot1++; }
+ void slot2() { sequence_slot2 = ++sequence; count_slot2++; }
+ void slot3() { sequence_slot3 = ++sequence; count_slot3++; }
+ void slot4() { sequence_slot4 = ++sequence; count_slot4++; }
+
+};
+
+int ReceiverObject::sequence = 0;
+
+void tst_QObject::disconnect()
+{
+ SenderObject *s = new SenderObject;
+ ReceiverObject *r1 = new ReceiverObject;
+ ReceiverObject *r2 = new ReceiverObject;
+
+ connect( s, SIGNAL( signal1() ), r1, SLOT( slot1() ) );
+
+ connect( s, SIGNAL( signal2() ), r1, SLOT( slot2() ) );
+ connect( s, SIGNAL( signal3() ), r1, SLOT( slot3() ) );
+ connect( s, SIGNAL( signal4() ), r1, SLOT( slot4() ) );
+
+ s->emitSignal1();
+ s->emitSignal2();
+ s->emitSignal3();
+ s->emitSignal4();
+
+ QCOMPARE( r1->called(1), TRUE );
+ QCOMPARE( r1->called(2), TRUE );
+ QCOMPARE( r1->called(3), TRUE );
+ QCOMPARE( r1->called(4), TRUE );
+ r1->reset();
+
+ // usual disconnect with all parameters given
+ bool ret = QObject::disconnect( s, SIGNAL( signal1() ), r1, SLOT( slot1() ) );
+
+ s->emitSignal1();
+
+ QCOMPARE( r1->called(1), FALSE );
+ r1->reset();
+
+ QCOMPARE( ret, TRUE );
+ ret = QObject::disconnect( s, SIGNAL( signal1() ), r1, SLOT( slot1() ) );
+ QCOMPARE( ret, FALSE );
+
+ // disconnect all signals from s from all slots from r1
+ QObject::disconnect( s, 0, r1, 0 );
+
+ s->emitSignal2();
+ s->emitSignal3();
+ s->emitSignal4();
+
+ QCOMPARE( r1->called(2), FALSE );
+ QCOMPARE( r1->called(3), FALSE );
+ QCOMPARE( r1->called(4), FALSE );
+ r1->reset();
+
+ connect( s, SIGNAL( signal1() ), r1, SLOT( slot1() ) );
+ connect( s, SIGNAL( signal1() ), r1, SLOT( slot2() ) );
+ connect( s, SIGNAL( signal1() ), r1, SLOT( slot3() ) );
+ connect( s, SIGNAL( signal2() ), r1, SLOT( slot4() ) );
+
+ // disconnect s's signal1() from all slots of r1
+ QObject::disconnect( s, SIGNAL( signal1() ), r1, 0 );
+
+ s->emitSignal1();
+ s->emitSignal2();
+
+ QCOMPARE( r1->called(1), FALSE );
+ QCOMPARE( r1->called(2), FALSE );
+ QCOMPARE( r1->called(3), FALSE );
+ QCOMPARE( r1->called(4), TRUE );
+ r1->reset();
+ // make sure all is disconnected again
+ QObject::disconnect( s, 0, r1, 0 );
+
+ connect( s, SIGNAL( signal1() ), r1, SLOT( slot1() ) );
+ connect( s, SIGNAL( signal1() ), r2, SLOT( slot1() ) );
+ connect( s, SIGNAL( signal2() ), r1, SLOT( slot2() ) );
+ connect( s, SIGNAL( signal2() ), r2, SLOT( slot2() ) );
+ connect( s, SIGNAL( signal3() ), r1, SLOT( slot3() ) );
+ connect( s, SIGNAL( signal3() ), r2, SLOT( slot3() ) );
+
+ // disconnect signal1() from all receivers
+ QObject::disconnect( s, SIGNAL( signal1() ), 0, 0 );
+ s->emitSignal1();
+ s->emitSignal2();
+ s->emitSignal3();
+
+ QCOMPARE( r1->called(1), FALSE );
+ QCOMPARE( r2->called(1), FALSE );
+ QCOMPARE( r1->called(2), TRUE );
+ QCOMPARE( r2->called(2), TRUE );
+ QCOMPARE( r1->called(2), TRUE );
+ QCOMPARE( r2->called(2), TRUE );
+
+ r1->reset();
+ r2->reset();
+
+ // disconnect all signals of s from all receivers
+ QObject::disconnect( s, 0, 0, 0 );
+
+ QCOMPARE( r1->called(2), FALSE );
+ QCOMPARE( r2->called(2), FALSE );
+ QCOMPARE( r1->called(2), FALSE );
+ QCOMPARE( r2->called(2), FALSE );
+
+ delete r2;
+ delete r1;
+ delete s;
+}
+
+class AutoConnectSender : public QObject
+{
+ Q_OBJECT
+
+public:
+ AutoConnectSender(QObject *parent)
+ : QObject(parent)
+ {}
+
+ void emitSignalNoParams() { emit signalNoParams(); }
+ void emitSignalWithParams(int i) { emit signalWithParams(i); }
+ void emitSignalWithParams(int i, QString string) { emit signalWithParams(i, string); }
+ void emitSignalManyParams(int i1, int i2, int i3, QString string, bool onoff) { emit signalManyParams(i1, i2, i3, string, onoff); }
+ void emitSignalManyParams2(int i1, int i2, int i3, QString string, bool onoff) { emit signalManyParams2(i1, i2, i3, string, onoff); }
+ void emitSignalLoopBack() { emit signalLoopBack(); }
+
+signals:
+ void signalNoParams();
+ void signalWithParams(int i);
+ void signalWithParams(int i, QString string);
+ void signalManyParams(int i1, int i2, int i3, QString string, bool onoff);
+ void signalManyParams(int i1, int i2, int i3, QString string, bool onoff, bool);
+ void signalManyParams2(int i1, int i2, int i3, QString string, bool onoff);
+ void signalLoopBack();
+};
+
+class AutoConnectReceiver : public QObject
+{
+ Q_OBJECT
+
+public:
+ AutoConnectReceiver()
+ {
+ reset();
+
+ connect(this, SIGNAL(on_Sender_signalLoopBack()), this, SLOT(slotLoopBack()));
+ }
+
+ void reset() {
+ called_slot8 = 0;
+ called_slot7 = 0;
+ called_slot6 = 0;
+ called_slot5 = 0;
+ called_slot4 = 0;
+ called_slot3 = 0;
+ called_slot2 = 0;
+ called_slot1 = 0;
+ }
+
+ int called_slot1;
+ int called_slot2;
+ int called_slot3;
+ int called_slot4;
+ int called_slot5;
+ int called_slot6;
+ int called_slot7;
+ int called_slot8;
+
+ bool called(int slot) {
+ switch (slot) {
+ case 1: return called_slot1;
+ case 2: return called_slot2;
+ case 3: return called_slot3;
+ case 4: return called_slot4;
+ case 5: return called_slot5;
+ case 6: return called_slot6;
+ case 7: return called_slot7;
+ case 8: return called_slot8;
+ default: return false;
+ }
+ }
+
+public slots:
+ void on_Sender_signalNoParams() { ++called_slot1; }
+ void on_Sender_signalWithParams(int i = 0) { ++called_slot2; Q_UNUSED(i); }
+ void on_Sender_signalWithParams(int i, QString string) { ++called_slot3; Q_UNUSED(i);Q_UNUSED(string); }
+ void on_Sender_signalManyParams() { ++called_slot4; }
+ void on_Sender_signalManyParams(int i1, int i2, int i3, QString string, bool onoff) { ++called_slot5; Q_UNUSED(i1);Q_UNUSED(i2);Q_UNUSED(i3);Q_UNUSED(string);Q_UNUSED(onoff); }
+ void on_Sender_signalManyParams(int i1, int i2, int i3, QString string, bool onoff, bool dummy)
+ { ++called_slot6; Q_UNUSED(i1);Q_UNUSED(i2);Q_UNUSED(i3);Q_UNUSED(string);Q_UNUSED(onoff); Q_UNUSED(dummy);}
+ void on_Sender_signalManyParams2(int i1, int i2, int i3, QString string, bool onoff)
+ { ++called_slot7; Q_UNUSED(i1);Q_UNUSED(i2);Q_UNUSED(i3);Q_UNUSED(string);Q_UNUSED(onoff); }
+ void slotLoopBack() { ++called_slot8; }
+
+protected slots:
+ void o() { Q_ASSERT(0); }
+ void on() { Q_ASSERT(0); }
+
+signals:
+ void on_Sender_signalLoopBack();
+};
+
+void tst_QObject::connectByName()
+{
+ AutoConnectReceiver receiver;
+ AutoConnectSender sender(&receiver);
+ sender.setObjectName("Sender");
+
+ QMetaObject::connectSlotsByName(&receiver);
+
+ sender.emitSignalNoParams();
+ QCOMPARE(receiver.called(1), true);
+ QCOMPARE(receiver.called(2), false);
+ QCOMPARE(receiver.called(3), false);
+ QCOMPARE(receiver.called(4), false);
+ QCOMPARE(receiver.called(5), false);
+ QCOMPARE(receiver.called(6), false);
+ QCOMPARE(receiver.called(7), false);
+ QCOMPARE(receiver.called(8), false);
+ receiver.reset();
+
+ sender.emitSignalWithParams(0);
+ QCOMPARE(receiver.called(1), false);
+ QCOMPARE(receiver.called(2), true);
+ QCOMPARE(receiver.called(3), false);
+ QCOMPARE(receiver.called(4), false);
+ QCOMPARE(receiver.called(5), false);
+ QCOMPARE(receiver.called(6), false);
+ QCOMPARE(receiver.called(7), false);
+ QCOMPARE(receiver.called(8), false);
+ receiver.reset();
+
+ sender.emitSignalWithParams(0, "string");
+ QCOMPARE(receiver.called(1), false);
+ QCOMPARE(receiver.called(2), false);
+ QCOMPARE(receiver.called(3), true);
+ QCOMPARE(receiver.called(4), false);
+ QCOMPARE(receiver.called(5), false);
+ QCOMPARE(receiver.called(6), false);
+ QCOMPARE(receiver.called(7), false);
+ QCOMPARE(receiver.called(8), false);
+ receiver.reset();
+
+ sender.emitSignalManyParams(1, 2, 3, "string", true);
+ QCOMPARE(receiver.called(1), false);
+ QCOMPARE(receiver.called(2), false);
+ QCOMPARE(receiver.called(3), false);
+ QCOMPARE(receiver.called(4), true);
+ QCOMPARE(receiver.called(5), true);
+ QCOMPARE(receiver.called(6), false);
+ QCOMPARE(receiver.called(7), false);
+ QCOMPARE(receiver.called(8), false);
+ receiver.reset();
+
+ sender.emitSignalManyParams2(1, 2, 3, "string", true);
+ QCOMPARE(receiver.called(1), false);
+ QCOMPARE(receiver.called(2), false);
+ QCOMPARE(receiver.called(3), false);
+ QCOMPARE(receiver.called(4), false);
+ QCOMPARE(receiver.called(5), false);
+ QCOMPARE(receiver.called(6), false);
+ QCOMPARE(receiver.called(7), true);
+ QCOMPARE(receiver.called(8), false);
+ receiver.reset();
+
+ sender.emitSignalLoopBack();
+ QCOMPARE(receiver.called(1), false);
+ QCOMPARE(receiver.called(2), false);
+ QCOMPARE(receiver.called(3), false);
+ QCOMPARE(receiver.called(4), false);
+ QCOMPARE(receiver.called(5), false);
+ QCOMPARE(receiver.called(6), false);
+ QCOMPARE(receiver.called(7), false);
+ QCOMPARE(receiver.called(8), true);
+ receiver.reset();
+}
+
+void tst_QObject::qobject_castTemplate()
+{
+ QObject *o = 0;
+ QVERIFY( !::qobject_cast<QObject*>(o) );
+
+ o = new SenderObject;
+ QVERIFY( ::qobject_cast<SenderObject*>(o) );
+ QVERIFY( ::qobject_cast<QObject*>(o) );
+ QVERIFY( !::qobject_cast<ReceiverObject*>(o) );
+ delete o;
+}
+
+void tst_QObject::findChildren()
+{
+ QObject o;
+ QObject o1(&o);
+ QObject o2(&o);
+ QObject o11(&o1);
+ QObject o12(&o1);
+ QObject o111(&o11);
+ QObject unnamed(&o);
+ QTimer t1(&o);
+ QTimer t121(&o12);
+ QTimer emptyname(&o);
+
+ o.setObjectName("o");
+ o1.setObjectName("o1");
+ o2.setObjectName("o2");
+ o11.setObjectName("o11");
+ o12.setObjectName("o12");
+ o111.setObjectName("o111");
+ t1.setObjectName("t1");
+ t121.setObjectName("t121");
+ emptyname.setObjectName("");
+
+ QObject *op = 0;
+
+ op = qFindChild<QObject*>(&o, "o1");
+ QCOMPARE(op, &o1);
+ op = qFindChild<QObject*>(&o, "o2");
+ QCOMPARE(op, &o2);
+ op = qFindChild<QObject*>(&o, "o11");
+ QCOMPARE(op, &o11);
+ op = qFindChild<QObject*>(&o, "o12");
+ QCOMPARE(op, &o12);
+ op = qFindChild<QObject*>(&o, "o111");
+ QCOMPARE(op, &o111);
+ op = qFindChild<QObject*>(&o, "t1");
+ QCOMPARE(op, static_cast<QObject *>(&t1));
+ op = qFindChild<QObject*>(&o, "t121");
+ QCOMPARE(op, static_cast<QObject *>(&t121));
+ op = qFindChild<QTimer*>(&o, "t1");
+ QCOMPARE(op, static_cast<QObject *>(&t1));
+ op = qFindChild<QTimer*>(&o, "t121");
+ QCOMPARE(op, static_cast<QObject *>(&t121));
+ op = qFindChild<QTimer*>(&o, "o12");
+ QCOMPARE(op, static_cast<QObject *>(0));
+ op = qFindChild<QObject*>(&o, "o");
+ QCOMPARE(op, static_cast<QObject *>(0));
+ op = qFindChild<QObject*>(&o, "harry");
+ QCOMPARE(op, static_cast<QObject *>(0));
+ op = qFindChild<QObject*>(&o, "o1");
+ QCOMPARE(op, &o1);
+
+ QList<QObject*> l;
+ QList<QTimer*> tl;
+
+ l = qFindChildren<QObject*>(&o, "o1");
+ QCOMPARE(l.size(), 1);
+ QCOMPARE(l.at(0), &o1);
+ l = qFindChildren<QObject*>(&o, "o2");
+ QCOMPARE(l.size(), 1);
+ QCOMPARE(l.at(0), &o2);
+ l = qFindChildren<QObject*>(&o, "o11");
+ QCOMPARE(l.size(), 1);
+ QCOMPARE(l.at(0), &o11);
+ l = qFindChildren<QObject*>(&o, "o12");
+ QCOMPARE(l.size(), 1);
+ QCOMPARE(l.at(0), &o12);
+ l = qFindChildren<QObject*>(&o, "o111");
+ QCOMPARE(l.size(), 1);
+ QCOMPARE(l.at(0), &o111);
+ l = qFindChildren<QObject*>(&o, "t1");
+ QCOMPARE(l.size(), 1);
+ QCOMPARE(l.at(0), static_cast<QObject *>(&t1));
+ l = qFindChildren<QObject*>(&o, "t121");
+ QCOMPARE(l.size(), 1);
+ QCOMPARE(l.at(0), static_cast<QObject *>(&t121));
+ tl = qFindChildren<QTimer*>(&o, "t1");
+ QCOMPARE(tl.size(), 1);
+ QCOMPARE(tl.at(0), &t1);
+ tl = qFindChildren<QTimer*>(&o, "t121");
+ QCOMPARE(tl.size(), 1);
+ QCOMPARE(tl.at(0), &t121);
+ l = qFindChildren<QObject*>(&o, "o");
+ QCOMPARE(l.size(), 0);
+ l = qFindChildren<QObject*>(&o, "harry");
+ QCOMPARE(l.size(), 0);
+ tl = qFindChildren<QTimer*>(&o, "o12");
+ QCOMPARE(tl.size(), 0);
+ l = qFindChildren<QObject*>(&o, "o1");
+ QCOMPARE(l.size(), 1);
+ QCOMPARE(l.at(0), &o1);
+
+ l = qFindChildren<QObject*>(&o, QRegExp("o.*"));
+ QCOMPARE(l.size(), 5);
+ QVERIFY(l.contains(&o1));
+ QVERIFY(l.contains(&o2));
+ QVERIFY(l.contains(&o11));
+ QVERIFY(l.contains(&o12));
+ QVERIFY(l.contains(&o111));
+ l = qFindChildren<QObject*>(&o, QRegExp("t.*"));
+ QCOMPARE(l.size(), 2);
+ QVERIFY(l.contains(&t1));
+ QVERIFY(l.contains(&t121));
+ tl = qFindChildren<QTimer*>(&o, QRegExp(".*"));
+ QCOMPARE(tl.size(), 3);
+ QVERIFY(tl.contains(&t1));
+ QVERIFY(tl.contains(&t121));
+ tl = qFindChildren<QTimer*>(&o, QRegExp("o.*"));
+ QCOMPARE(tl.size(), 0);
+ l = qFindChildren<QObject*>(&o, QRegExp("harry"));
+ QCOMPARE(l.size(), 0);
+
+ // empty and null string check
+ op = qFindChild<QObject*>(&o);
+ QCOMPARE(op, &o1);
+ op = qFindChild<QObject*>(&o, "");
+ QCOMPARE(op, &unnamed);
+ op = qFindChild<QObject*>(&o, "unnamed");
+ QCOMPARE(op, static_cast<QObject *>(0));
+
+ l = qFindChildren<QObject*>(&o);
+ QCOMPARE(l.size(), 9);
+ l = qFindChildren<QObject*>(&o, "");
+ QCOMPARE(l.size(), 2);
+ l = qFindChildren<QObject*>(&o, "unnamed");
+ QCOMPARE(l.size(), 0);
+
+ tl = o.findChildren<QTimer *>("t1");
+ QCOMPARE(tl.size(), 1);
+ QCOMPARE(tl.at(0), &t1);
+}
+
+
+class NotifyObject : public SenderObject, public ReceiverObject
+{
+public:
+ NotifyObject() : SenderObject(), ReceiverObject()
+ {}
+
+ QString org_signal;
+ QString nw_signal;
+
+protected:
+ void connectNotify( const char *signal )
+ {
+ org_signal = signal;
+ nw_signal = QMetaObject::normalizedSignature(signal);
+ };
+ void disconnectNotify( const char *signal )
+ {
+ org_signal = signal;
+ nw_signal = QMetaObject::normalizedSignature(signal);
+ };
+};
+
+void tst_QObject::connectDisconnectNotify_data()
+{
+ QTest::addColumn<QString>("a_signal");
+ QTest::addColumn<QString>("a_slot");
+
+ QTest::newRow("combo1") << SIGNAL( signal1() ) << SLOT( slot1() );
+ QTest::newRow("combo2") << SIGNAL( signal2(void) ) << SLOT( slot2( ) );
+ QTest::newRow("combo3") << SIGNAL( signal3( ) ) << SLOT( slot3(void) );
+ QTest::newRow("combo4") << SIGNAL( signal4( void ) )<< SLOT( slot4( void ) );
+}
+
+void tst_QObject::connectDisconnectNotify()
+{
+ NotifyObject *s = new NotifyObject;
+ NotifyObject *r = new NotifyObject;
+
+ QFETCH(QString, a_signal);
+ QFETCH(QString, a_slot);
+
+ // Test connectNotify
+ connect( (SenderObject*)s, a_signal.toLatin1(), (ReceiverObject*)r, a_slot.toLatin1() );
+ QCOMPARE( s->org_signal, s->nw_signal );
+ QCOMPARE( s->org_signal.toLatin1(), QMetaObject::normalizedSignature(a_signal.toLatin1().constData()) );
+
+ // Test disconnectNotify
+ QObject::disconnect( (SenderObject*)s, a_signal.toLatin1(), (ReceiverObject*)r, a_slot.toLatin1() );
+ QCOMPARE( s->org_signal, s->nw_signal );
+ QCOMPARE( s->org_signal.toLatin1(), QMetaObject::normalizedSignature(a_signal.toLatin1().constData()) );
+
+ // Reconnect
+ connect( (SenderObject*)s, a_signal.toLatin1(), (ReceiverObject*)r, a_slot.toLatin1() );
+ // Test disconnectNotify for a complete disconnect
+ ((SenderObject*)s)->disconnect((ReceiverObject*)r);
+
+ // Obtaining meta methods
+ int signalIndx = ((SenderObject*)s)->metaObject()->indexOfSignal(
+ QMetaObject::normalizedSignature(a_signal.toLatin1().constData()+1).constData());
+ int methodIndx = ((ReceiverObject*)r)->metaObject()->indexOfMethod(
+ QMetaObject::normalizedSignature(a_slot.toLatin1().constData()+1).constData());
+ QMetaMethod signal = ((SenderObject*)s)->metaObject()->method(signalIndx);
+ QMetaMethod method = ((ReceiverObject*)r)->metaObject()->method(methodIndx);
+
+ // Test connectNotify when connecting by QMetaMethod
+ connect( (SenderObject*)s, signal, (ReceiverObject*)r, method );
+ QCOMPARE( s->org_signal, s->nw_signal );
+ QCOMPARE( s->org_signal.toLatin1(), QMetaObject::normalizedSignature(a_signal.toLatin1().constData()) );
+
+ // Test disconnectNotify when disconnecting by QMetaMethod
+ QObject::disconnect( (SenderObject*)s, signal, (ReceiverObject*)r, method );
+ QCOMPARE( s->org_signal, s->nw_signal );
+ QCOMPARE( s->org_signal.toLatin1(), QMetaObject::normalizedSignature(a_signal.toLatin1().constData()) );
+
+ delete s;
+ delete r;
+}
+
+class SequenceObject : public ReceiverObject
+{
+ Q_OBJECT
+
+public:
+ QObject *next;
+ SequenceObject() : next(0) { }
+
+public slots:
+ void slot1_disconnectThis()
+ {
+ slot1();
+ disconnect(sender(), SIGNAL(signal1()), this, SLOT(slot1_disconnectThis()));
+ }
+
+ void slot2_reconnectThis()
+ {
+ slot2();
+
+ const QObject *s = sender();
+ disconnect(s, SIGNAL(signal1()), this, SLOT(slot2_reconnectThis()));
+ connect(s, SIGNAL(signal1()), this, SLOT(slot2_reconnectThis()));
+ }
+
+ void slot1_disconnectNext()
+ {
+ slot1();
+ disconnect(sender(), SIGNAL(signal1()), next, SLOT(slot1()));
+ }
+
+ void slot2_reconnectNext()
+ {
+ slot2();
+
+ // modify the connection list in 'this'
+ disconnect(sender(), SIGNAL(signal1()), next, SLOT(slot2()));
+ connect(sender(), SIGNAL(signal1()), next, SLOT(slot2()));
+
+ // modify the sender list in 'this'
+ connect(next, SIGNAL(destroyed()), this, SLOT(deleteLater()));
+ connect(QCoreApplication::instance(), SIGNAL(aboutToQuit()), this, SLOT(deleteLater()));
+ disconnect(next, SIGNAL(destroyed()), this, SLOT(deleteLater()));
+ disconnect(QCoreApplication::instance(), SIGNAL(aboutToQuit()), this, SLOT(deleteLater()));
+ }
+
+ void slot1_deleteNext()
+ {
+ slot1();
+ delete next;
+ }
+
+ void slot2_deleteSender()
+ {
+ slot2();
+ delete sender();
+ }
+};
+
+void tst_QObject::emitInDefinedOrder()
+{
+ SenderObject sender;
+ ReceiverObject receiver1, receiver2, receiver3, receiver4;
+
+ connect(&sender, SIGNAL(signal1()), &receiver1, SLOT(slot1()));
+ connect(&sender, SIGNAL(signal1()), &receiver2, SLOT(slot1()));
+ connect(&sender, SIGNAL(signal1()), &receiver3, SLOT(slot1()));
+ connect(&sender, SIGNAL(signal1()), &receiver4, SLOT(slot1()));
+ connect(&sender, SIGNAL(signal1()), &receiver1, SLOT(slot2()));
+ connect(&sender, SIGNAL(signal1()), &receiver2, SLOT(slot2()));
+ connect(&sender, SIGNAL(signal1()), &receiver3, SLOT(slot2()));
+ connect(&sender, SIGNAL(signal1()), &receiver4, SLOT(slot2()));
+
+ int sequence;
+ ReceiverObject::sequence = sequence = 0;
+ sender.emitSignal1();
+ QCOMPARE(receiver1.sequence_slot1, ++sequence);
+ QCOMPARE(receiver2.sequence_slot1, ++sequence);
+ QCOMPARE(receiver3.sequence_slot1, ++sequence);
+ QCOMPARE(receiver4.sequence_slot1, ++sequence);
+ QCOMPARE(receiver1.sequence_slot2, ++sequence);
+ QCOMPARE(receiver2.sequence_slot2, ++sequence);
+ QCOMPARE(receiver3.sequence_slot2, ++sequence);
+ QCOMPARE(receiver4.sequence_slot2, ++sequence);
+
+ QObject::disconnect(&sender, SIGNAL(signal1()), &receiver2, SLOT(slot1()));
+ connect(&sender, SIGNAL(signal1()), &receiver2, SLOT(slot1()));
+
+ ReceiverObject::sequence = sequence = 0;
+ sender.emitSignal1();
+ QCOMPARE(receiver1.sequence_slot1, ++sequence);
+ QCOMPARE(receiver3.sequence_slot1, ++sequence);
+ QCOMPARE(receiver4.sequence_slot1, ++sequence);
+ QCOMPARE(receiver1.sequence_slot2, ++sequence);
+ QCOMPARE(receiver2.sequence_slot2, ++sequence);
+ QCOMPARE(receiver3.sequence_slot2, ++sequence);
+ QCOMPARE(receiver4.sequence_slot2, ++sequence);
+ QCOMPARE(receiver2.sequence_slot1, ++sequence);
+
+ QObject::disconnect(&sender, SIGNAL(signal1()), &receiver1, SLOT(slot1()));
+ connect(&sender, SIGNAL(signal1()), &receiver1, SLOT(slot1()));
+
+ ReceiverObject::sequence = sequence = 0;
+ sender.emitSignal1();
+ QCOMPARE(receiver3.sequence_slot1, ++sequence);
+ QCOMPARE(receiver4.sequence_slot1, ++sequence);
+ QCOMPARE(receiver1.sequence_slot2, ++sequence);
+ QCOMPARE(receiver2.sequence_slot2, ++sequence);
+ QCOMPARE(receiver3.sequence_slot2, ++sequence);
+ QCOMPARE(receiver4.sequence_slot2, ++sequence);
+ QCOMPARE(receiver2.sequence_slot1, ++sequence);
+ QCOMPARE(receiver1.sequence_slot1, ++sequence);
+
+ // ensure emission order even if the connections change during emission
+ SenderObject *sender2 = new SenderObject;
+ SequenceObject seq1, seq2, *seq3 = new SequenceObject, seq4;
+ seq1.next = &seq2;
+ seq2.next = seq3;
+ seq3->next = &seq4;
+
+ // try 1
+ connect(sender2, SIGNAL(signal1()), &seq1, SLOT(slot1_disconnectThis()));
+ connect(sender2, SIGNAL(signal1()), &seq2, SLOT(slot1_disconnectNext()));
+ connect(sender2, SIGNAL(signal1()), seq3, SLOT(slot1()));
+ connect(sender2, SIGNAL(signal1()), &seq4, SLOT(slot1()));
+ connect(sender2, SIGNAL(signal1()), &seq1, SLOT(slot2_reconnectThis()));
+ connect(sender2, SIGNAL(signal1()), &seq2, SLOT(slot2_reconnectNext()));
+ connect(sender2, SIGNAL(signal1()), seq3, SLOT(slot2()));
+ connect(sender2, SIGNAL(signal1()), &seq4, SLOT(slot2()));
+
+ SequenceObject::sequence = sequence = 0;
+ sender2->emitSignal1();
+ QCOMPARE(seq1.called(1), TRUE);
+ QCOMPARE(seq2.called(1), TRUE);
+ QCOMPARE(seq3->called(1), FALSE);
+ QCOMPARE(seq4.called(1), TRUE);
+ QCOMPARE(seq1.called(2), TRUE);
+ QCOMPARE(seq2.called(2), TRUE);
+ QCOMPARE(seq3->called(2), FALSE);
+ QCOMPARE(seq4.called(2), TRUE);
+ QCOMPARE(seq1.sequence_slot1, ++sequence);
+ QCOMPARE(seq2.sequence_slot1, ++sequence);
+ QCOMPARE(seq4.sequence_slot1, ++sequence);
+ QCOMPARE(seq1.sequence_slot2, ++sequence);
+ QCOMPARE(seq2.sequence_slot2, ++sequence);
+ QCOMPARE(seq4.sequence_slot2, ++sequence);
+
+ QObject::disconnect(sender2, 0, &seq1, 0);
+ QObject::disconnect(sender2, 0, &seq2, 0);
+ QObject::disconnect(sender2, 0, seq3, 0);
+ QObject::disconnect(sender2, 0, &seq4, 0);
+ seq1.reset();
+ seq2.reset();
+ seq3->reset();
+ seq4.reset();
+
+ // try 2
+ connect(sender2, SIGNAL(signal1()), &seq1, SLOT(slot2_reconnectThis()));
+ connect(sender2, SIGNAL(signal1()), &seq2, SLOT(slot2_reconnectNext()));
+ connect(sender2, SIGNAL(signal1()), seq3, SLOT(slot2()));
+ connect(sender2, SIGNAL(signal1()), &seq4, SLOT(slot2()));
+ connect(sender2, SIGNAL(signal1()), &seq1, SLOT(slot1_disconnectThis()));
+ connect(sender2, SIGNAL(signal1()), &seq2, SLOT(slot1_disconnectNext()));
+ connect(sender2, SIGNAL(signal1()), seq3, SLOT(slot1()));
+ connect(sender2, SIGNAL(signal1()), &seq4, SLOT(slot1()));
+
+ SequenceObject::sequence = sequence = 0;
+ sender2->emitSignal1();
+ QCOMPARE(seq1.called(2), TRUE);
+ QCOMPARE(seq2.called(2), TRUE);
+ QCOMPARE(seq3->called(2), FALSE);
+ QCOMPARE(seq4.called(2), TRUE);
+ QCOMPARE(seq1.called(1), TRUE);
+ QCOMPARE(seq2.called(1), TRUE);
+ QCOMPARE(seq3->called(1), FALSE);
+ QCOMPARE(seq4.called(1), TRUE);
+ QCOMPARE(seq1.sequence_slot2, ++sequence);
+ QCOMPARE(seq2.sequence_slot2, ++sequence);
+ QCOMPARE(seq4.sequence_slot2, ++sequence);
+ QCOMPARE(seq1.sequence_slot1, ++sequence);
+ QCOMPARE(seq2.sequence_slot1, ++sequence);
+ QCOMPARE(seq4.sequence_slot1, ++sequence);
+
+ QObject::disconnect(sender2, 0, &seq1, 0);
+ QObject::disconnect(sender2, 0, &seq2, 0);
+ QObject::disconnect(sender2, 0, seq3, 0);
+ QObject::disconnect(sender2, 0, &seq4, 0);
+ seq1.reset();
+ seq2.reset();
+ seq3->reset();
+ seq4.reset();
+
+ // try 3
+ connect(sender2, SIGNAL(signal1()), &seq1, SLOT(slot1()));
+ connect(sender2, SIGNAL(signal1()), &seq2, SLOT(slot1_disconnectNext()));
+ connect(sender2, SIGNAL(signal1()), seq3, SLOT(slot1()));
+ connect(sender2, SIGNAL(signal1()), &seq4, SLOT(slot1()));
+ connect(sender2, SIGNAL(signal1()), &seq1, SLOT(slot2()));
+ connect(sender2, SIGNAL(signal1()), &seq2, SLOT(slot2_reconnectNext()));
+ connect(sender2, SIGNAL(signal1()), seq3, SLOT(slot2()));
+ connect(sender2, SIGNAL(signal1()), &seq4, SLOT(slot2()));
+
+ SequenceObject::sequence = sequence = 0;
+ sender2->emitSignal1();
+ QCOMPARE(seq1.called(1), TRUE);
+ QCOMPARE(seq2.called(1), TRUE);
+ QCOMPARE(seq3->called(1), FALSE);
+ QCOMPARE(seq4.called(1), TRUE);
+ QCOMPARE(seq1.called(2), TRUE);
+ QCOMPARE(seq2.called(2), TRUE);
+ QCOMPARE(seq3->called(2), FALSE);
+ QCOMPARE(seq4.called(2), TRUE);
+ QCOMPARE(seq1.sequence_slot1, ++sequence);
+ QCOMPARE(seq2.sequence_slot1, ++sequence);
+ QCOMPARE(seq4.sequence_slot1, ++sequence);
+ QCOMPARE(seq1.sequence_slot2, ++sequence);
+ QCOMPARE(seq2.sequence_slot2, ++sequence);
+ QCOMPARE(seq4.sequence_slot2, ++sequence);
+
+ // ensure emission order even if objects are destroyed during emission
+ QObject::disconnect(sender2, 0, &seq1, 0);
+ QObject::disconnect(sender2, 0, &seq2, 0);
+ QObject::disconnect(sender2, 0, seq3, 0);
+ QObject::disconnect(sender2, 0, &seq4, 0);
+ seq1.reset();
+ seq2.reset();
+ seq3->reset();
+ seq4.reset();
+
+ connect(sender2, SIGNAL(signal1()), &seq1, SLOT(slot1()));
+ connect(sender2, SIGNAL(signal1()), &seq2, SLOT(slot1_deleteNext()));
+ connect(sender2, SIGNAL(signal1()), seq3, SLOT(slot1()));
+ connect(sender2, SIGNAL(signal1()), &seq4, SLOT(slot1()));
+ connect(sender2, SIGNAL(signal1()), &seq1, SLOT(slot2()));
+ connect(sender2, SIGNAL(signal1()), &seq2, SLOT(slot2_deleteSender()));
+ connect(sender2, SIGNAL(signal1()), seq3, SLOT(slot2()));
+ connect(sender2, SIGNAL(signal1()), &seq4, SLOT(slot2()));
+
+ QPointer<SenderObject> psender = sender2;
+ QPointer<SequenceObject> pseq3 = seq3;
+
+ SequenceObject::sequence = sequence = 0;
+ sender2->emitSignal1();
+ QCOMPARE(static_cast<QObject *>(psender), static_cast<QObject *>(0));
+ QCOMPARE(static_cast<QObject *>(pseq3), static_cast<QObject *>(0));
+ QCOMPARE(seq1.called(1), TRUE);
+ QCOMPARE(seq2.called(1), TRUE);
+ QCOMPARE(seq4.called(1), TRUE);
+ QCOMPARE(seq1.called(2), TRUE);
+ QCOMPARE(seq2.called(2), TRUE);
+ QCOMPARE(seq4.called(2), FALSE);
+ QCOMPARE(seq1.sequence_slot1, ++sequence);
+ QCOMPARE(seq2.sequence_slot1, ++sequence);
+ QCOMPARE(seq4.sequence_slot1, ++sequence);
+ QCOMPARE(seq1.sequence_slot2, ++sequence);
+ QCOMPARE(seq2.sequence_slot2, ++sequence);
+
+ QPointer<SenderObject> psender3 = new SenderObject;
+ connect(psender3, SIGNAL(signal1()), psender3, SIGNAL(signal2()));
+ connect(psender3, SIGNAL(signal2()), &seq1, SLOT(slot2_deleteSender()));
+ psender3->emitSignal1();
+ QVERIFY(!psender3);
+}
+
+static int instanceCount = 0;
+
+struct CustomType
+{
+ CustomType(int l1 = 0, int l2 = 0, int l3 = 0): i1(l1), i2(l2), i3(l3)
+ { ++instanceCount; }
+ CustomType(const CustomType &other): i1(other.i1), i2(other.i2), i3(other.i3)
+ { ++instanceCount; }
+ ~CustomType() { --instanceCount; }
+
+ int i1, i2, i3;
+ int value() { return i1 + i2 + i3; }
+};
+
+Q_DECLARE_METATYPE(CustomType*)
+
+class QCustomTypeChecker: public QObject
+{
+ Q_OBJECT
+
+public:
+ QCustomTypeChecker(QObject *parent = 0): QObject(parent) {}
+ void doEmit(CustomType ct)
+ { emit signal1(ct); }
+
+public slots:
+ void slot1(CustomType ct);
+
+signals:
+ void signal1(CustomType ct);
+
+public:
+ CustomType received;
+};
+
+void QCustomTypeChecker::slot1(CustomType ct)
+{ received = ct; }
+
+
+void tst_QObject::customTypes()
+{
+ CustomType t0;
+ CustomType t1(1, 2, 3);
+ CustomType t2(2, 3, 4);
+
+ {
+ QCustomTypeChecker checker;
+ QCOMPARE(instanceCount, 4);
+
+ connect(&checker, SIGNAL(signal1(CustomType)), &checker, SLOT(slot1(CustomType)),
+ Qt::DirectConnection);
+ QCOMPARE(checker.received.value(), 0);
+ checker.doEmit(t1);
+ QCOMPARE(checker.received.value(), t1.value());
+ checker.received = t0;
+
+ int idx = qRegisterMetaType<CustomType>("CustomType");
+ QCOMPARE(QMetaType::type("CustomType"), idx);
+
+ checker.disconnect();
+ connect(&checker, SIGNAL(signal1(CustomType)), &checker, SLOT(slot1(CustomType)),
+ Qt::QueuedConnection);
+ QCOMPARE(instanceCount, 4);
+ checker.doEmit(t2);
+ QCOMPARE(instanceCount, 5);
+ QCOMPARE(checker.received.value(), t0.value());
+
+ QCoreApplication::processEvents();
+ QCOMPARE(checker.received.value(), t2.value());
+ QCOMPARE(instanceCount, 4);
+
+ QVERIFY(QMetaType::isRegistered(idx));
+ QCOMPARE(qRegisterMetaType<CustomType>("CustomType"), idx);
+ QCOMPARE(QMetaType::type("CustomType"), idx);
+ QVERIFY(QMetaType::isRegistered(idx));
+ }
+ QCOMPARE(instanceCount, 3);
+}
+
+QDataStream &operator<<(QDataStream &stream, const CustomType &ct)
+{
+ stream << ct.i1 << ct.i2 << ct.i3;
+ return stream;
+}
+
+QDataStream &operator>>(QDataStream &stream, CustomType &ct)
+{
+ stream >> ct.i1;
+ stream >> ct.i2;
+ stream >> ct.i3;
+ return stream;
+}
+
+void tst_QObject::streamCustomTypes()
+{
+ QByteArray ba;
+
+ int idx = qRegisterMetaType<CustomType>("CustomType");
+ qRegisterMetaTypeStreamOperators<CustomType>("CustomType");
+
+ {
+ CustomType t1(1, 2, 3);
+ QCOMPARE(instanceCount, 1);
+ QDataStream stream(&ba, (QIODevice::OpenMode)QIODevice::WriteOnly);
+ QMetaType::save(stream, idx, &t1);
+ }
+
+ QCOMPARE(instanceCount, 0);
+
+ {
+ CustomType t2;
+ QCOMPARE(instanceCount, 1);
+ QDataStream stream(&ba, (QIODevice::OpenMode)QIODevice::ReadOnly);
+ QMetaType::load(stream, idx, &t2);
+ QCOMPARE(instanceCount, 1);
+ QCOMPARE(t2.i1, 1);
+ QCOMPARE(t2.i2, 2);
+ QCOMPARE(t2.i3, 3);
+ }
+ QCOMPARE(instanceCount, 0);
+}
+
+typedef QString CustomString;
+
+class PropertyObject : public QObject
+{
+ Q_OBJECT
+ Q_ENUMS(Alpha Priority)
+
+ Q_PROPERTY(Alpha alpha READ alpha WRITE setAlpha)
+ Q_PROPERTY(Priority priority READ priority WRITE setPriority)
+ Q_PROPERTY(int number READ number WRITE setNumber)
+ Q_PROPERTY(QString string READ string WRITE setString)
+ Q_PROPERTY(QVariant variant READ variant WRITE setVariant)
+ Q_PROPERTY(CustomType* custom READ custom WRITE setCustom)
+ Q_PROPERTY(float myFloat READ myFloat WRITE setMyFloat)
+ Q_PROPERTY(qreal myQReal READ myQReal WRITE setMyQReal)
+ Q_PROPERTY(CustomString customString READ customString WRITE setCustomString )
+
+public:
+ enum Alpha {
+ Alpha0,
+ Alpha1,
+ Alpha2
+ };
+
+ enum Priority { High, Low, VeryHigh, VeryLow };
+
+ PropertyObject()
+ : m_alpha(Alpha0), m_priority(High), m_number(0), m_custom(0), m_float(42)
+ {}
+
+ Alpha alpha() const { return m_alpha; }
+ void setAlpha(Alpha alpha) { m_alpha = alpha; }
+
+ Priority priority() const { return m_priority; }
+ void setPriority(Priority priority) { m_priority = priority; }
+
+ int number() const { return m_number; }
+ void setNumber(int number) { m_number = number; }
+
+ QString string() const { return m_string; }
+ void setString(const QString &string) { m_string = string; }
+
+ QVariant variant() const { return m_variant; }
+ void setVariant(const QVariant &variant) { m_variant = variant; }
+
+ CustomType *custom() const { return m_custom; }
+ void setCustom(CustomType *custom) { m_custom = custom; }
+
+ void setMyFloat(float value) { m_float = value; }
+ inline float myFloat() const { return m_float; }
+
+ void setMyQReal(qreal value) { m_qreal = value; }
+ qreal myQReal() const { return m_qreal; }
+
+ CustomString customString() const { return m_customString; }
+ void setCustomString(const QString &string) { m_customString = string; }
+
+private:
+ Alpha m_alpha;
+ Priority m_priority;
+ int m_number;
+ QString m_string;
+ QVariant m_variant;
+ CustomType *m_custom;
+ float m_float;
+ qreal m_qreal;
+ CustomString m_customString;
+};
+
+Q_DECLARE_METATYPE(PropertyObject::Priority)
+
+void tst_QObject::threadSignalEmissionCrash()
+{
+#if defined(Q_OS_WINCE) || defined(Q_OS_SYMBIAN)
+ int loopCount = 100;
+#else
+ int loopCount = 1000;
+#endif
+ for (int i = 0; i < loopCount; ++i) {
+ QTcpSocket socket;
+ socket.connectToHost("localhost", 80);
+ }
+}
+
+class TestThread : public QThread
+{
+ Q_OBJECT
+public:
+ inline void run()
+ {
+ *object = new QObject;
+ *child = new QObject(*object);
+ mutex.lock();
+ cond.wakeOne();
+ cond.wait(&mutex);
+ mutex.unlock();
+ }
+
+ QObject **object, **child;
+ QMutex mutex;
+ QWaitCondition cond;
+};
+
+void tst_QObject::thread()
+{
+ QThread *currentThread = QThread::currentThread();
+ // the current thread is the same as the QApplication
+ // thread... see tst_QApplication::thread()
+
+ {
+ QObject object;
+ // thread affinity for objects with no parent should be the
+ // current thread
+ QVERIFY(object.thread() != 0);
+ QCOMPARE(object.thread(), currentThread);
+ // children inherit their parent's thread
+ QObject child(&object);
+ QCOMPARE(child.thread(), object.thread());
+ }
+
+ QObject *object = 0;
+ QObject *child = 0;
+
+ {
+ TestThread thr;
+ QVERIFY(thr.thread() != 0);
+ QCOMPARE(thr.thread(), currentThread);
+
+ thr.object = &object;
+ thr.child = &child;
+
+ thr.mutex.lock();
+ thr.start();
+ thr.cond.wait(&thr.mutex);
+
+ // thread affinity for an object with no parent should be the
+ // thread in which the object was created
+ QCOMPARE(object->thread(), (QThread *)&thr);
+ // children inherit their parent's thread
+ QCOMPARE(child->thread(), object->thread());
+
+ thr.cond.wakeOne();
+ thr.mutex.unlock();
+ thr.wait();
+
+ // even though the thread is no longer running, the affinity
+ // should not change
+ QCOMPARE(object->thread(), (QThread *)&thr);
+ QCOMPARE(child->thread(), object->thread());
+ }
+
+ // the thread has been destroyed, thread affinity should
+ // automatically reset to no thread
+ QCOMPARE(object->thread(), (QThread *)0);
+ QCOMPARE(child->thread(), object->thread());
+
+ delete object;
+}
+
+class MoveToThreadObject : public QObject
+{
+ Q_OBJECT
+public:
+ QThread *timerEventThread;
+ QThread *customEventThread;
+ QThread *slotThread;
+
+ MoveToThreadObject(QObject *parent = 0)
+ : QObject(parent), timerEventThread(0), customEventThread(0), slotThread(0)
+ { }
+
+ void customEvent(QEvent *)
+ {
+ Q_ASSERT(customEventThread == 0);
+ customEventThread = QThread::currentThread();
+ emit theSignal();
+ }
+
+ void timerEvent(QTimerEvent *)
+ {
+ Q_ASSERT(timerEventThread == 0);
+ timerEventThread = QThread::currentThread();
+ emit theSignal();
+ }
+
+public slots:
+ void theSlot()
+ {
+ Q_ASSERT(slotThread == 0);
+ slotThread = QThread::currentThread();
+ emit theSignal();
+ }
+
+signals:
+ void theSignal();
+};
+
+class MoveToThreadThread : public QThread
+{
+public:
+ ~MoveToThreadThread()
+ {
+ if (isRunning()) {
+ terminate();
+ wait();
+ }
+ }
+ void start()
+ {
+ QEventLoop eventLoop;
+ connect(this, SIGNAL(started()), &eventLoop, SLOT(quit()), Qt::QueuedConnection);
+ QThread::start();
+ // wait for thread to start
+ (void) eventLoop.exec();
+ }
+ void run()
+ { (void) exec(); }
+};
+
+void tst_QObject::thread0()
+{
+ QObject *object = new QObject;
+ object->moveToThread(0);
+ QObject *child = new QObject(object);
+ QCOMPARE(child->parent(), object);
+ QCOMPARE(child->thread(), (QThread *)0);
+
+#if 0
+ // We don't support moving children into a parent that has no thread
+ // affinity (yet?).
+ QObject *child2 = new QObject;
+ child2->moveToThread(0);
+ child2->setParent(object);
+ QCOMPARE(child2->parent(), object);
+ QCOMPARE(child2->thread(), (QThread *)0);
+#endif
+
+ delete object;
+}
+
+void tst_QObject::moveToThread()
+{
+ QThread *currentThread = QThread::currentThread();
+
+ {
+ QObject *object = new QObject;
+ QObject *child = new QObject(object);
+ QCOMPARE(object->thread(), currentThread);
+ QCOMPARE(child->thread(), currentThread);
+ object->moveToThread(0);
+ QCOMPARE(object->thread(), (QThread *)0);
+ QCOMPARE(child->thread(), (QThread *)0);
+ object->moveToThread(currentThread);
+ QCOMPARE(object->thread(), currentThread);
+ QCOMPARE(child->thread(), currentThread);
+ object->moveToThread(0);
+ QCOMPARE(object->thread(), (QThread *)0);
+ QCOMPARE(child->thread(), (QThread *)0);
+ // can delete an object with no thread anywhere
+ delete object;
+ }
+
+ {
+ MoveToThreadThread thread;
+ thread.start();
+
+ QObject *object = new QObject;
+ QObject *child = new QObject(object);
+ QPointer<QObject> opointer = object;
+ QPointer<QObject> cpointer = object;
+
+ QCOMPARE(object->thread(), currentThread);
+ QCOMPARE(child->thread(), currentThread);
+ object->moveToThread(&thread);
+ QCOMPARE(object->thread(), (QThread *)&thread);
+ QCOMPARE(child->thread(), (QThread *)&thread);
+
+ connect(object, SIGNAL(destroyed()), &thread, SLOT(quit()), Qt::DirectConnection);
+ QMetaObject::invokeMethod(object, "deleteLater", Qt::QueuedConnection);
+ thread.wait();
+
+ QVERIFY(opointer == 0);
+ QVERIFY(cpointer == 0);
+ }
+
+ {
+ // make sure posted events are moved with the object
+ MoveToThreadThread thread;
+ thread.start();
+
+ MoveToThreadObject *object = new MoveToThreadObject;
+ MoveToThreadObject *child = new MoveToThreadObject(object);
+
+ connect(object, SIGNAL(theSignal()), &thread, SLOT(quit()), Qt::DirectConnection);
+ QCoreApplication::postEvent(child, new QEvent(QEvent::User));
+ QCoreApplication::postEvent(object, new QEvent(QEvent::User));
+
+ QCOMPARE(object->thread(), currentThread);
+ QCOMPARE(child->thread(), currentThread);
+ object->moveToThread(&thread);
+ QCOMPARE(object->thread(), (QThread *)&thread);
+ QCOMPARE(child->thread(), (QThread *)&thread);
+
+ thread.wait();
+
+ QCOMPARE(object->customEventThread, (QThread *)&thread);
+ QCOMPARE(child->customEventThread, (QThread *)&thread);
+
+ thread.start();
+ connect(object, SIGNAL(destroyed()), &thread, SLOT(quit()), Qt::DirectConnection);
+ QMetaObject::invokeMethod(object, "deleteLater", Qt::QueuedConnection);
+ thread.wait();
+ }
+
+ {
+ // make sure timers are moved with the object
+ MoveToThreadThread thread;
+ thread.start();
+
+ MoveToThreadObject *object = new MoveToThreadObject;
+ MoveToThreadObject *child = new MoveToThreadObject(object);
+
+ connect(object, SIGNAL(theSignal()), &thread, SLOT(quit()), Qt::DirectConnection);
+
+#if defined(Q_OS_SYMBIAN)
+ // Child timer will be registered after parent timer in the new
+ // thread, and 10ms is less than symbian timer resolution, so
+ // child->timerEventThread compare after thread.wait() will
+ // usually fail unless timers are farther apart.
+ child->startTimer(100);
+ object->startTimer(150);
+#else
+ child->startTimer(90);
+ object->startTimer(100);
+#endif
+
+ QCOMPARE(object->thread(), currentThread);
+ QCOMPARE(child->thread(), currentThread);
+ object->moveToThread(&thread);
+ QCOMPARE(object->thread(), (QThread *)&thread);
+ QCOMPARE(child->thread(), (QThread *)&thread);
+
+ thread.wait();
+
+ QCOMPARE(object->timerEventThread, (QThread *)&thread);
+ QCOMPARE(child->timerEventThread, (QThread *)&thread);
+
+ thread.start();
+ connect(object, SIGNAL(destroyed()), &thread, SLOT(quit()), Qt::DirectConnection);
+ QMetaObject::invokeMethod(object, "deleteLater", Qt::QueuedConnection);
+ thread.wait();
+ }
+
+ {
+ // make sure socket notifiers are moved with the object
+ MoveToThreadThread thread;
+ thread.start();
+
+ QTcpServer server;
+ QVERIFY(server.listen(QHostAddress::LocalHost, 0));
+ QTcpSocket *socket = new QTcpSocket;
+ MoveToThreadObject *child = new MoveToThreadObject(socket);
+ connect(socket, SIGNAL(disconnected()), child, SLOT(theSlot()), Qt::DirectConnection);
+ connect(child, SIGNAL(theSignal()), &thread, SLOT(quit()), Qt::DirectConnection);
+
+ socket->connectToHost(server.serverAddress(), server.serverPort());
+
+ QVERIFY(server.waitForNewConnection(1000));
+ QTcpSocket *serverSocket = server.nextPendingConnection();
+ QVERIFY(serverSocket);
+
+ socket->waitForConnected();
+
+ QCOMPARE(socket->thread(), currentThread);
+ socket->moveToThread(&thread);
+ QCOMPARE(socket->thread(), (QThread *)&thread);
+
+ serverSocket->close();
+
+ QVERIFY(thread.wait(10000));
+
+ QCOMPARE(child->slotThread, (QThread *)&thread);
+
+ thread.start();
+ connect(socket, SIGNAL(destroyed()), &thread, SLOT(quit()), Qt::DirectConnection);
+ QMetaObject::invokeMethod(socket, "deleteLater", Qt::QueuedConnection);
+ thread.wait();
+ }
+}
+
+
+void tst_QObject::property()
+{
+ PropertyObject object;
+ const QMetaObject *mo = object.metaObject();
+ QMetaProperty property;
+ QVERIFY(mo);
+
+ QVERIFY(mo->indexOfProperty("alpha") != -1);
+ property = mo->property(mo->indexOfProperty("alpha"));
+ QVERIFY(property.isEnumType());
+ QCOMPARE(property.typeName(), "Alpha");
+ QCOMPARE(property.type(), QVariant::Int);
+
+ QVariant var = object.property("alpha");
+ QVERIFY(!var.isNull());
+ QCOMPARE(var.toInt(), int(PropertyObject::Alpha0));
+ object.setAlpha(PropertyObject::Alpha1);
+ QCOMPARE(object.property("alpha").toInt(), int(PropertyObject::Alpha1));
+ QVERIFY(object.setProperty("alpha", PropertyObject::Alpha2));
+ QCOMPARE(object.property("alpha").toInt(), int(PropertyObject::Alpha2));
+ QVERIFY(object.setProperty("alpha", "Alpha1"));
+ QCOMPARE(object.property("alpha").toInt(), int(PropertyObject::Alpha1));
+ QVERIFY(!object.setProperty("alpha", QVariant()));
+
+ QVERIFY(mo->indexOfProperty("number") != -1);
+ QCOMPARE(object.property("number").toInt(), 0);
+ object.setNumber(24);
+ QCOMPARE(object.property("number"), QVariant(24));
+ QVERIFY(object.setProperty("number", 12));
+ QCOMPARE(object.property("number"), QVariant(12));
+ QVERIFY(object.setProperty("number", "42"));
+ QCOMPARE(object.property("number"), QVariant(42));
+
+ QVERIFY(mo->indexOfProperty("string") != -1);
+ QCOMPARE(object.property("string").toString(), QString());
+ object.setString("String1");
+ QCOMPARE(object.property("string"), QVariant("String1"));
+ QVERIFY(object.setProperty("string", "String2"));
+ QCOMPARE(object.property("string"), QVariant("String2"));
+ QVERIFY(!object.setProperty("string", QVariant()));
+
+ const int idx = mo->indexOfProperty("variant");
+ QVERIFY(idx != -1);
+ QVERIFY(mo->property(idx).type() == QVariant::LastType);
+ QCOMPARE(object.property("variant"), QVariant());
+ QVariant variant1(42);
+ QVariant variant2("string");
+ object.setVariant(variant1);
+ QCOMPARE(object.property("variant"), variant1);
+ QVERIFY(object.setProperty("variant", variant2));
+ QCOMPARE(object.variant(), QVariant(variant2));
+ QCOMPARE(object.property("variant"), variant2);
+ QVERIFY(object.setProperty("variant", QVariant()));
+ QCOMPARE(object.property("variant"), QVariant());
+
+ QVERIFY(mo->indexOfProperty("custom") != -1);
+ property = mo->property(mo->indexOfProperty("custom"));
+ QVERIFY(property.isValid());
+ QVERIFY(property.isWritable());
+ QVERIFY(!property.isEnumType());
+ QCOMPARE(property.typeName(), "CustomType*");
+ QCOMPARE(property.type(), QVariant::UserType);
+
+ CustomType *customPointer = 0;
+ QVariant customVariant = object.property("custom");
+ customPointer = qVariantValue<CustomType *>(customVariant);
+ QCOMPARE(customPointer, object.custom());
+
+ CustomType custom;
+ customPointer = &custom;
+ qVariantSetValue(customVariant, customPointer);
+
+ property = mo->property(mo->indexOfProperty("custom"));
+ QVERIFY(property.isWritable());
+ QCOMPARE(property.typeName(), "CustomType*");
+ QCOMPARE(property.type(), QVariant::UserType);
+
+ QVERIFY(object.setProperty("custom", customVariant));
+ QCOMPARE(object.custom(), customPointer);
+
+ customVariant = object.property("custom");
+ customPointer = qVariantValue<CustomType *>(customVariant);
+ QCOMPARE(object.custom(), customPointer);
+
+ // this enum property has a meta type, but it's not yet registered, so we know this fails
+ QVERIFY(mo->indexOfProperty("priority") != -1);
+ property = mo->property(mo->indexOfProperty("priority"));
+ QVERIFY(property.isEnumType());
+ QCOMPARE(property.typeName(), "Priority");
+ QCOMPARE(property.type(), QVariant::Int);
+
+ var = object.property("priority");
+ QVERIFY(!var.isNull());
+ QCOMPARE(var.toInt(), int(PropertyObject::High));
+ object.setPriority(PropertyObject::Low);
+ QCOMPARE(object.property("priority").toInt(), int(PropertyObject::Low));
+ QVERIFY(object.setProperty("priority", PropertyObject::VeryHigh));
+ QCOMPARE(object.property("priority").toInt(), int(PropertyObject::VeryHigh));
+ QVERIFY(object.setProperty("priority", "High"));
+ QCOMPARE(object.property("priority").toInt(), int(PropertyObject::High));
+ QVERIFY(!object.setProperty("priority", QVariant()));
+
+ // now it's registered, so it works as expected
+ int priorityMetaTypeId = qRegisterMetaType<PropertyObject::Priority>("PropertyObject::Priority");
+
+ QVERIFY(mo->indexOfProperty("priority") != -1);
+ property = mo->property(mo->indexOfProperty("priority"));
+ QVERIFY(property.isEnumType());
+ QCOMPARE(property.typeName(), "Priority");
+ QCOMPARE(property.type(), QVariant::UserType);
+ QCOMPARE(property.userType(), priorityMetaTypeId);
+
+ var = object.property("priority");
+ QVERIFY(!var.isNull());
+ QVERIFY(qVariantCanConvert<PropertyObject::Priority>(var));
+ QCOMPARE(qVariantValue<PropertyObject::Priority>(var), PropertyObject::High);
+ object.setPriority(PropertyObject::Low);
+ QCOMPARE(qVariantValue<PropertyObject::Priority>(object.property("priority")), PropertyObject::Low);
+ QVERIFY(object.setProperty("priority", PropertyObject::VeryHigh));
+ QCOMPARE(qVariantValue<PropertyObject::Priority>(object.property("priority")), PropertyObject::VeryHigh);
+ QVERIFY(object.setProperty("priority", "High"));
+ QCOMPARE(qVariantValue<PropertyObject::Priority>(object.property("priority")), PropertyObject::High);
+ QVERIFY(!object.setProperty("priority", QVariant()));
+
+ var = object.property("priority");
+ QCOMPARE(qVariantValue<PropertyObject::Priority>(var), PropertyObject::High);
+ object.setPriority(PropertyObject::Low);
+ QCOMPARE(qVariantValue<PropertyObject::Priority>(object.property("priority")), PropertyObject::Low);
+ object.setProperty("priority", var);
+ QCOMPARE(qVariantValue<PropertyObject::Priority>(object.property("priority")), PropertyObject::High);
+
+ qRegisterMetaType<CustomString>("CustomString");
+ QVERIFY(mo->indexOfProperty("customString") != -1);
+ QCOMPARE(object.property("customString").toString(), QString());
+ object.setCustomString("String1");
+ QCOMPARE(object.property("customString"), QVariant("String1"));
+ QVERIFY(object.setProperty("customString", "String2"));
+ QCOMPARE(object.property("customString"), QVariant("String2"));
+ QVERIFY(!object.setProperty("customString", QVariant()));
+}
+
+void tst_QObject::metamethod()
+{
+ SenderObject obj;
+ const QMetaObject *mobj = obj.metaObject();
+ QMetaMethod m;
+
+ m = mobj->method(mobj->indexOfMethod("invoke1()"));
+ QVERIFY(QByteArray(m.signature()) == "invoke1()");
+ QVERIFY(m.methodType() == QMetaMethod::Method);
+ QVERIFY(m.access() == QMetaMethod::Public);
+ QVERIFY(!(m.attributes() & QMetaMethod::Scriptable));
+ QVERIFY(!(m.attributes() & QMetaMethod::Compatibility));
+
+ m = mobj->method(mobj->indexOfMethod("sinvoke1()"));
+ QVERIFY(QByteArray(m.signature()) == "sinvoke1()");
+ QVERIFY(m.methodType() == QMetaMethod::Method);
+ QVERIFY(m.access() == QMetaMethod::Public);
+ QVERIFY((m.attributes() & QMetaMethod::Scriptable));
+ QVERIFY(!(m.attributes() & QMetaMethod::Compatibility));
+
+ m = mobj->method(mobj->indexOfMethod("invoke2()"));
+ QVERIFY(QByteArray(m.signature()) == "invoke2()");
+ QVERIFY(m.methodType() == QMetaMethod::Method);
+ QVERIFY(m.access() == QMetaMethod::Protected);
+ QVERIFY(!(m.attributes() & QMetaMethod::Scriptable));
+ QVERIFY((m.attributes() & QMetaMethod::Compatibility));
+
+ m = mobj->method(mobj->indexOfMethod("sinvoke2()"));
+ QVERIFY(QByteArray(m.signature()) == "sinvoke2()");
+ QVERIFY(m.methodType() == QMetaMethod::Method);
+ QVERIFY(m.access() == QMetaMethod::Protected);
+ QVERIFY((m.attributes() & QMetaMethod::Scriptable));
+ QVERIFY((m.attributes() & QMetaMethod::Compatibility));
+
+ m = mobj->method(mobj->indexOfMethod("invoke3()"));
+ QVERIFY(QByteArray(m.signature()) == "invoke3()");
+ QVERIFY(m.methodType() == QMetaMethod::Method);
+ QVERIFY(m.access() == QMetaMethod::Private);
+ QVERIFY(!(m.attributes() & QMetaMethod::Scriptable));
+ QVERIFY(!(m.attributes() & QMetaMethod::Compatibility));
+
+ m = mobj->method(mobj->indexOfMethod("sinvoke3()"));
+ QVERIFY(QByteArray(m.signature()) == "sinvoke3()");
+ QVERIFY(m.methodType() == QMetaMethod::Method);
+ QVERIFY(m.access() == QMetaMethod::Private);
+ QVERIFY((m.attributes() & QMetaMethod::Scriptable));
+ QVERIFY(!(m.attributes() & QMetaMethod::Compatibility));
+
+ m = mobj->method(mobj->indexOfMethod("signal5()"));
+ QVERIFY(QByteArray(m.signature()) == "signal5()");
+ QVERIFY(m.methodType() == QMetaMethod::Signal);
+ QVERIFY(m.access() == QMetaMethod::Protected);
+ QVERIFY(!(m.attributes() & QMetaMethod::Scriptable));
+ QVERIFY((m.attributes() & QMetaMethod::Compatibility));
+
+ m = mobj->method(mobj->indexOfMethod("aPublicSlot()"));
+ QVERIFY(QByteArray(m.signature()) == "aPublicSlot()");
+ QVERIFY(m.methodType() == QMetaMethod::Slot);
+ QVERIFY(m.access() == QMetaMethod::Public);
+ QVERIFY(!(m.attributes() & QMetaMethod::Scriptable));
+ QVERIFY(!(m.attributes() & QMetaMethod::Compatibility));
+
+ m = mobj->method(mobj->indexOfMethod("invoke1()"));
+ QCOMPARE(m.parameterNames().count(), 0);
+ QCOMPARE(m.parameterTypes().count(), 0);
+
+ m = mobj->method(mobj->indexOfMethod("invoke2(int)"));
+ QCOMPARE(m.parameterNames().count(), 1);
+ QCOMPARE(m.parameterTypes().count(), 1);
+ QCOMPARE(m.parameterTypes().at(0), QByteArray("int"));
+ QVERIFY(m.parameterNames().at(0).isEmpty());
+
+ m = mobj->method(mobj->indexOfMethod("invoke3(int,int)"));
+ QCOMPARE(m.parameterNames().count(), 2);
+ QCOMPARE(m.parameterTypes().count(), 2);
+ QCOMPARE(m.parameterTypes().at(0), QByteArray("int"));
+ QCOMPARE(m.parameterNames().at(0), QByteArray("hinz"));
+ QCOMPARE(m.parameterTypes().at(1), QByteArray("int"));
+ QCOMPARE(m.parameterNames().at(1), QByteArray("kunz"));
+
+}
+
+namespace QObjectTest
+{
+ class TestObject: public QObject
+ {
+ Q_OBJECT
+ public:
+ TestObject(): QObject(), i(0) {}
+ void doEmit() { emit aSignal(); }
+ int i;
+ public slots:
+ void aSlot() { ++i; }
+ signals:
+ void aSignal();
+ };
+}
+
+void tst_QObject::namespaces()
+{
+ QObjectTest::TestObject obj;
+
+ QVERIFY(connect(&obj, SIGNAL(aSignal()), &obj, SLOT(aSlot())));
+ obj.doEmit();
+ QCOMPARE(obj.i, 1);
+}
+
+class SuperObject : public QObject
+{
+ Q_OBJECT
+public:
+ QObject *theSender;
+ int theSignalId;
+
+ SuperObject()
+ {
+ theSender = 0;
+ theSignalId = 0;
+ }
+
+ friend class tst_QObject;
+
+ using QObject::sender;
+
+public slots:
+ void rememberSender()
+ {
+ theSender = sender();
+ theSignalId = senderSignalIndex();
+ }
+
+ void deleteAndRememberSender()
+ {
+ delete theSender;
+ rememberSender();
+ }
+signals:
+ void anotherSignal();
+ void theSignal();
+};
+
+void tst_QObject::sender()
+{
+ {
+ SuperObject sender;
+ SuperObject receiver;
+ connect(&sender, SIGNAL(anotherSignal()),
+ &receiver, SLOT(rememberSender()));
+ connect(&sender, SIGNAL(theSignal()),
+ &receiver, SLOT(rememberSender()));
+ QCOMPARE(receiver.sender(), (QObject *)0);
+ QCOMPARE(receiver.senderSignalIndex(), -1);
+ emit sender.theSignal();
+ QCOMPARE(receiver.theSender, (QObject *)&sender);
+ QCOMPARE(receiver.sender(), (QObject *)0);
+ QCOMPARE(receiver.theSignalId,
+ sender.metaObject()->indexOfSignal("theSignal()"));
+ QCOMPARE(receiver.senderSignalIndex(), -1);
+
+ emit sender.anotherSignal();
+ QCOMPARE(receiver.theSignalId,
+ sender.metaObject()->indexOfSignal("anotherSignal()"));
+ QCOMPARE(receiver.senderSignalIndex(), -1);
+ }
+
+ {
+ SuperObject *sender = new SuperObject;
+ SuperObject *receiver = new SuperObject;
+ connect(sender, SIGNAL(theSignal()),
+ receiver, SLOT(rememberSender()),
+ Qt::BlockingQueuedConnection);
+
+ QThread thread;
+ receiver->moveToThread(&thread);
+ connect(sender, SIGNAL(theSignal()),
+ &thread, SLOT(quit()),
+ Qt::DirectConnection);
+
+ QCOMPARE(receiver->sender(), (QObject *)0);
+ QCOMPARE(receiver->senderSignalIndex(), -1);
+ receiver->theSender = 0;
+ receiver->theSignalId = -1;
+ thread.start();
+ emit sender->theSignal();
+ QCOMPARE(receiver->theSender, (QObject *) sender);
+ QCOMPARE(receiver->sender(), (QObject *)0);
+ QCOMPARE(receiver->theSignalId,
+ sender->metaObject()->indexOfSignal("theSignal()"));
+ QCOMPARE(receiver->senderSignalIndex(), -1);
+
+ QVERIFY(thread.wait(10000));
+ delete receiver;
+ delete sender;
+ }
+
+ {
+ SuperObject *sender = new SuperObject;
+ SuperObject receiver;
+ connect(sender, SIGNAL(theSignal()),
+ &receiver, SLOT(deleteAndRememberSender()));
+ QCOMPARE(receiver.sender(), (QObject *)0);
+ receiver.theSender = sender;
+ emit sender->theSignal();
+ QCOMPARE(receiver.theSender, (QObject *)0);
+ QCOMPARE(receiver.sender(), (QObject *)0);
+ }
+
+ {
+ SuperObject *sender = new SuperObject;
+ SuperObject *receiver = new SuperObject;
+ connect(sender, SIGNAL(theSignal()),
+ receiver, SLOT(deleteAndRememberSender()),
+ Qt::BlockingQueuedConnection);
+
+ QThread thread;
+ receiver->moveToThread(&thread);
+ connect(sender, SIGNAL(destroyed()),
+ &thread, SLOT(quit()),
+ Qt::DirectConnection);
+
+ QCOMPARE(receiver->sender(), (QObject *)0);
+ receiver->theSender = sender;
+ thread.start();
+ emit sender->theSignal();
+ QCOMPARE(receiver->theSender, (QObject *)0);
+ QCOMPARE(receiver->sender(), (QObject *)0);
+
+ QVERIFY(thread.wait(10000));
+ delete receiver;
+ }
+}
+
+namespace Foo
+{
+ struct Bar
+ {
+ virtual ~Bar() {}
+ virtual int rtti() const = 0;
+ };
+
+ struct Bleh
+ {
+ virtual ~Bleh() {}
+ virtual int rtti() const = 0;
+ };
+}
+
+QT_BEGIN_NAMESPACE
+Q_DECLARE_INTERFACE(Foo::Bar, "com.qtest.foobar")
+QT_END_NAMESPACE
+
+#define Bleh_iid "com.qtest.bleh"
+QT_BEGIN_NAMESPACE
+Q_DECLARE_INTERFACE(Foo::Bleh, Bleh_iid)
+QT_END_NAMESPACE
+
+class FooObject: public QObject, public Foo::Bar
+{
+ Q_OBJECT
+ Q_INTERFACES(Foo::Bar)
+public:
+ int rtti() const { return 42; }
+};
+
+class BlehObject : public QObject, public Foo::Bleh
+{
+ Q_OBJECT
+ Q_INTERFACES(Foo::Bleh)
+public:
+ int rtti() const { return 43; }
+};
+
+void tst_QObject::declareInterface()
+{
+ FooObject obj;
+
+ Foo::Bar *bar = qobject_cast<Foo::Bar *>(&obj);
+ QVERIFY(bar);
+ QCOMPARE(bar->rtti(), 42);
+ QCOMPARE(static_cast<Foo::Bar *>(&obj), bar);
+
+ BlehObject bleh;
+
+ bar = qobject_cast<Foo::Bar *>(&bleh);
+ QVERIFY(!bar);
+ Foo::Bleh *b = qobject_cast<Foo::Bleh *>(&bleh);
+ QCOMPARE(b->rtti(), 43);
+ QCOMPARE(static_cast<Foo::Bleh *>(&bleh), b);
+
+}
+
+class CustomData : public QObjectUserData
+{
+public:
+ int id;
+};
+
+void tst_QObject::testUserData()
+{
+ const int USER_DATA_COUNT = 100;
+ int user_data_ids[USER_DATA_COUNT];
+
+ // Register a few
+ for (int i=0; i<USER_DATA_COUNT; ++i) {
+ user_data_ids[i] = QObject::registerUserData();
+ }
+
+ // Randomize the table a bit
+ for (int i=0; i<100; ++i) {
+ int p1 = rand() % USER_DATA_COUNT;
+ int p2 = rand() % USER_DATA_COUNT;
+
+ int tmp = user_data_ids[p1];
+ user_data_ids[p1] = user_data_ids[p2];
+ user_data_ids[p2] = tmp;
+ }
+
+ // insert the user data into an object
+ QObject my_test_object;
+ for (int i=0; i<USER_DATA_COUNT; ++i) {
+ CustomData *data = new CustomData;
+ data->id = user_data_ids[i];
+ my_test_object.setUserData(data->id, data);
+ }
+
+ // verify that all ids and positions are matching
+ for (int i=0; i<USER_DATA_COUNT; ++i) {
+ int id = user_data_ids[i];
+ CustomData *data = static_cast<CustomData *>(my_test_object.userData(id));
+ QVERIFY(data != 0);
+ QVERIFY(data->id == id);
+ }
+}
+
+class DestroyedListener : public QObject
+{
+ Q_OBJECT
+public:
+ inline DestroyedListener() : pointerWasZero(false) {}
+
+ QPointer<QObject> pointer;
+ bool pointerWasZero;
+
+private slots:
+ inline void otherObjectDestroyed()
+ { pointerWasZero = pointer.isNull(); }
+};
+
+void tst_QObject::qpointerResetBeforeDestroyedSignal()
+{
+ QObject *obj = new QObject;
+ DestroyedListener listener;
+ listener.pointer = obj;
+ listener.pointerWasZero = false;
+ connect(obj, SIGNAL(destroyed()), &listener, SLOT(otherObjectDestroyed()));
+ delete obj;
+ QVERIFY(listener.pointerWasZero);
+ QVERIFY(listener.pointer.isNull());
+}
+
+class DefaultArguments : public QObject
+{
+ Q_OBJECT
+
+public slots:
+
+ void theSlot(const QString &s) { result = s; }
+
+signals:
+ void theOriginalSignal();
+ void theSecondSignal(const QString &s = QString("secondDefault"));
+
+public:
+
+ void emitTheOriginalSignal() { emit theOriginalSignal(); }
+ void emitTheSecondSignal() { emit theSecondSignal(); }
+ QString result;
+};
+
+void tst_QObject::connectSignalsToSignalsWithDefaultArguments()
+{
+ DefaultArguments o;
+ connect(&o, SIGNAL(theOriginalSignal()), &o, SIGNAL(theSecondSignal()));
+ connect(&o, SIGNAL(theSecondSignal(QString)), &o, SLOT(theSlot(QString)));
+ QVERIFY( o.result.isEmpty() );
+ o.emitTheSecondSignal();
+ QCOMPARE(o.result, QString("secondDefault"));
+ o.result = "Not called";
+ o.emitTheOriginalSignal();
+ QCOMPARE(o.result, QString("secondDefault"));
+
+}
+
+void tst_QObject::receivers()
+{
+ class Object : public QObject
+ {
+ public:
+ int receivers(const char* signal) const
+ { return QObject::receivers(signal); }
+ };
+
+ Object object;
+ QCOMPARE(object.receivers(SIGNAL(destroyed())), 0);
+ object.connect(&object, SIGNAL(destroyed()), SLOT(deleteLater()));
+ QCOMPARE(object.receivers(SIGNAL(destroyed())), 1);
+ object.connect(&object, SIGNAL(destroyed()), SLOT(deleteLater()));
+ QCOMPARE(object.receivers(SIGNAL(destroyed())), 2);
+ object.disconnect(SIGNAL(destroyed()), &object, SLOT(deleteLater()));
+ QCOMPARE(object.receivers(SIGNAL(destroyed())), 0);
+}
+
+enum Enum { };
+
+struct Struct { };
+class Class { };
+template <typename T> class Template { };
+
+class NormalizeObject : public QObject
+{
+ Q_OBJECT
+
+public:
+
+signals:
+ void uintPointerSignal(uint *);
+ void ulongPointerSignal(ulong *);
+ void constUintPointerSignal(const uint *);
+ void constUlongPointerSignal(const ulong *);
+
+ void structSignal(Struct s);
+ void classSignal(Class c);
+ void enumSignal(Enum e);
+
+ void structPointerSignal(Struct *s);
+ void classPointerSignal(Class *c);
+ void enumPointerSignal(Enum *e);
+
+ void constStructPointerSignal(const Struct *s);
+ void constClassPointerSignal(const Class *c);
+ void constEnumPointerSignal(const Enum *e);
+
+ void constStructPointerConstPointerSignal(const Struct * const *s);
+ void constClassPointerConstPointerSignal(const Class * const *c);
+ void constEnumPointerConstPointerSignal(const Enum * const *e);
+
+ void unsignedintSignal(unsigned int);
+ void unsignedSignal(unsigned);
+ void unsignedlongSignal(unsigned long);
+ void unsignedlonglongSignal(quint64);
+ void unsignedlongintSignal(unsigned long int);
+ void unsignedshortSignal(unsigned short);
+ void unsignedcharSignal(unsigned char);
+
+ void typeRefSignal(Template<Class &> &ref);
+ void constTypeRefSignal(const Template<Class const &> &ref);
+ void typeConstRefSignal(Template<Class const &> const &ref);
+
+ void typePointerConstRefSignal(Class * const &);
+
+ void constTemplateSignal1( Template<int > );
+ void constTemplateSignal2( Template< const int >);
+
+public slots:
+ void uintPointerSlot(uint *) { }
+ void ulongPointerSlot(ulong *) { }
+ void constUintPointerSlot(const uint *) { }
+ void constUlongPointerSlot(const ulong *) { }
+
+ void structSlot(Struct s) { Q_UNUSED(s); }
+ void classSlot(Class c) { Q_UNUSED(c); }
+ void enumSlot(Enum e) { Q_UNUSED(e); }
+
+ void structPointerSlot(Struct *s) { Q_UNUSED(s); }
+ void classPointerSlot(Class *c) { Q_UNUSED(c); }
+ void enumPointerSlot(Enum *e) { Q_UNUSED(e); }
+
+ void constStructPointerSlot(const Struct *s) { Q_UNUSED(s); }
+ void constClassPointerSlot(const Class *c) { Q_UNUSED(c); }
+ void constEnumPointerSlot(const Enum *e) { Q_UNUSED(e); }
+
+ void constStructPointerConstPointerSlot(const Struct * const *s) { Q_UNUSED(s); }
+ void constClassPointerConstPointerSlot(const Class * const *c) { Q_UNUSED(c); }
+ void constEnumPointerConstPointerSlot(const Enum * const *e) { Q_UNUSED(e); }
+
+ void uintSlot(uint) {};
+ void unsignedintSlot(unsigned int) {};
+ void unsignedSlot(unsigned) {};
+ void unsignedlongSlot(unsigned long) {};
+ void unsignedlonglongSlot(quint64) {};
+ void unsignedlongintSlot(unsigned long int) {};
+ void unsignedshortSlot(unsigned short) {};
+ void unsignedcharSlot(unsigned char) {};
+
+ void typeRefSlot(Template<Class &> &) {}
+ void constTypeRefSlot(const Template<const Class &> &) {}
+ void typeConstRefSlot(Template<Class const &> const &) {}
+
+ void typePointerConstRefSlot(Class * const &) {}
+
+ void constTemplateSlot1(Template<int > const) {}
+ void constTemplateSlot2(const Template<int > ) {}
+ void constTemplateSlot3(const Template< const int >) {}
+};
+
+#include "oldnormalizeobject.h"
+
+void tst_QObject::normalize()
+{
+ NormalizeObject object;
+
+ // unsigned int -> uint, unsigned long -> ulong
+ QVERIFY(object.connect(&object,
+ SIGNAL(uintPointerSignal(uint *)),
+ SLOT(uintPointerSlot(uint *))));
+ QVERIFY(object.connect(&object,
+ SIGNAL(uintPointerSignal(unsigned int *)),
+ SLOT(uintPointerSlot(uint *))));
+ QVERIFY(object.connect(&object,
+ SIGNAL(uintPointerSignal(uint *)),
+ SLOT(uintPointerSlot(unsigned int *))));
+
+ QVERIFY(object.connect(&object,
+ SIGNAL(constUintPointerSignal(const uint *)),
+ SLOT(constUintPointerSlot(const uint *))));
+ QVERIFY(object.connect(&object,
+ SIGNAL(constUintPointerSignal(const unsigned int *)),
+ SLOT(constUintPointerSlot(const uint *))));
+ QVERIFY(object.connect(&object,
+ SIGNAL(constUintPointerSignal(const uint *)),
+ SLOT(constUintPointerSlot(const unsigned int *))));
+
+ QVERIFY(object.connect(&object,
+ SIGNAL(ulongPointerSignal(ulong *)),
+ SLOT(ulongPointerSlot(ulong *))));
+ QVERIFY(object.connect(&object,
+ SIGNAL(ulongPointerSignal(unsigned long *)),
+ SLOT(ulongPointerSlot(ulong *))));
+ QVERIFY(object.connect(&object,
+ SIGNAL(ulongPointerSignal(ulong *)),
+ SLOT(ulongPointerSlot(unsigned long *))));
+
+ QVERIFY(object.connect(&object,
+ SIGNAL(constUlongPointerSignal(const ulong *)),
+ SLOT(constUlongPointerSlot(const ulong *))));
+ QVERIFY(object.connect(&object,
+ SIGNAL(constUlongPointerSignal(const unsigned long *)),
+ SLOT(constUlongPointerSlot(const ulong *))));
+ QVERIFY(object.connect(&object,
+ SIGNAL(constUlongPointerSignal(const ulong *)),
+ SLOT(constUlongPointerSlot(const unsigned long *))));
+
+ // struct, class, and enum are optional
+ QVERIFY(object.connect(&object,
+ SIGNAL(structSignal(struct Struct)),
+ SLOT(structSlot(struct Struct))));
+ QVERIFY(object.connect(&object,
+ SIGNAL(structSignal(Struct)),
+ SLOT(structSlot(struct Struct))));
+ QVERIFY(object.connect(&object,
+ SIGNAL(structSignal(struct Struct)),
+ SLOT(structSlot(Struct))));
+ QVERIFY(object.connect(&object,
+ SIGNAL(classSignal(class Class)),
+ SLOT(classSlot(class Class))));
+ QVERIFY(object.connect(&object,
+ SIGNAL(classSignal(Class)),
+ SLOT(classSlot(class Class))));
+ QVERIFY(object.connect(&object,
+ SIGNAL(classSignal(class Class)),
+ SLOT(classSlot(Class))));
+ QVERIFY(object.connect(&object,
+ SIGNAL(enumSignal(enum Enum)),
+ SLOT(enumSlot(enum Enum))));
+ QVERIFY(object.connect(&object,
+ SIGNAL(enumSignal(Enum)),
+ SLOT(enumSlot(enum Enum))));
+ QVERIFY(object.connect(&object,
+ SIGNAL(enumSignal(enum Enum)),
+ SLOT(enumSlot(Enum))));
+
+ QVERIFY(object.connect(&object,
+ SIGNAL(structPointerSignal(struct Struct *)),
+ SLOT(structPointerSlot(struct Struct *))));
+ QVERIFY(object.connect(&object,
+ SIGNAL(structPointerSignal(Struct *)),
+ SLOT(structPointerSlot(struct Struct *))));
+ QVERIFY(object.connect(&object,
+ SIGNAL(structPointerSignal(struct Struct *)),
+ SLOT(structPointerSlot(Struct *))));
+ QVERIFY(object.connect(&object,
+ SIGNAL(classPointerSignal(class Class *)),
+ SLOT(classPointerSlot(class Class *))));
+ QVERIFY(object.connect(&object,
+ SIGNAL(classPointerSignal(Class *)),
+ SLOT(classPointerSlot(class Class *))));
+ QVERIFY(object.connect(&object,
+ SIGNAL(classPointerSignal(class Class *)),
+ SLOT(classPointerSlot(Class *))));
+ QVERIFY(object.connect(&object,
+ SIGNAL(enumPointerSignal(enum Enum *)),
+ SLOT(enumPointerSlot(enum Enum *))));
+ QVERIFY(object.connect(&object,
+ SIGNAL(enumPointerSignal(Enum *)),
+ SLOT(enumPointerSlot(enum Enum *))));
+ QVERIFY(object.connect(&object,
+ SIGNAL(enumPointerSignal(enum Enum *)),
+ SLOT(enumPointerSlot(Enum *))));
+
+ QVERIFY(object.connect(&object,
+ SIGNAL(constStructPointerSignal(const struct Struct *)),
+ SLOT(constStructPointerSlot(const struct Struct *))));
+ QVERIFY(object.connect(&object,
+ SIGNAL(constStructPointerSignal(const Struct *)),
+ SLOT(constStructPointerSlot(const struct Struct *))));
+ QVERIFY(object.connect(&object,
+ SIGNAL(constStructPointerSignal(const struct Struct *)),
+ SLOT(constStructPointerSlot(const Struct *))));
+ QVERIFY(object.connect(&object,
+ SIGNAL(constClassPointerSignal(const class Class *)),
+ SLOT(constClassPointerSlot(const class Class *))));
+ QVERIFY(object.connect(&object,
+ SIGNAL(constClassPointerSignal(const Class *)),
+ SLOT(constClassPointerSlot(const class Class *))));
+ QVERIFY(object.connect(&object,
+ SIGNAL(constClassPointerSignal(const class Class *)),
+ SLOT(constClassPointerSlot(const Class *))));
+ QVERIFY(object.connect(&object,
+ SIGNAL(constEnumPointerSignal(const enum Enum *)),
+ SLOT(constEnumPointerSlot(const enum Enum *))));
+ QVERIFY(object.connect(&object,
+ SIGNAL(constEnumPointerSignal(const Enum *)),
+ SLOT(constEnumPointerSlot(const enum Enum *))));
+ QVERIFY(object.connect(&object,
+ SIGNAL(constEnumPointerSignal(const enum Enum *)),
+ SLOT(constEnumPointerSlot(const Enum *))));
+
+ QVERIFY(object.connect(&object,
+ SIGNAL(constStructPointerSignal(struct Struct const *)),
+ SLOT(constStructPointerSlot(struct Struct const *))));
+ QVERIFY(object.connect(&object,
+ SIGNAL(constStructPointerSignal(Struct const *)),
+ SLOT(constStructPointerSlot(struct Struct const *))));
+ QVERIFY(object.connect(&object,
+ SIGNAL(constStructPointerSignal(struct Struct const *)),
+ SLOT(constStructPointerSlot(Struct const *))));
+ QVERIFY(object.connect(&object,
+ SIGNAL(constClassPointerSignal(class Class const *)),
+ SLOT(constClassPointerSlot(class Class const *))));
+ QVERIFY(object.connect(&object,
+ SIGNAL(constClassPointerSignal(Class const *)),
+ SLOT(constClassPointerSlot(class Class const *))));
+ QVERIFY(object.connect(&object,
+ SIGNAL(constClassPointerSignal(class Class const *)),
+ SLOT(constClassPointerSlot(Class const *))));
+ QVERIFY(object.connect(&object,
+ SIGNAL(constEnumPointerSignal(enum Enum const *)),
+ SLOT(constEnumPointerSlot(enum Enum const *))));
+ QVERIFY(object.connect(&object,
+ SIGNAL(constEnumPointerSignal(Enum const *)),
+ SLOT(constEnumPointerSlot(enum Enum const *))));
+ QVERIFY(object.connect(&object,
+ SIGNAL(constEnumPointerSignal(enum Enum const *)),
+ SLOT(constEnumPointerSlot(Enum const *))));
+
+ QVERIFY(object.connect(&object,
+ SIGNAL(constStructPointerConstPointerSignal(const struct Struct * const *)),
+ SLOT(constStructPointerConstPointerSlot(const struct Struct * const *))));
+ QVERIFY(object.connect(&object,
+ SIGNAL(constStructPointerConstPointerSignal(const Struct * const *)),
+ SLOT(constStructPointerConstPointerSlot(const struct Struct * const *))));
+ QVERIFY(object.connect(&object,
+ SIGNAL(constStructPointerConstPointerSignal(const struct Struct * const *)),
+ SLOT(constStructPointerConstPointerSlot(const Struct * const *))));
+ QVERIFY(object.connect(&object,
+ SIGNAL(constClassPointerConstPointerSignal(const class Class * const *)),
+ SLOT(constClassPointerConstPointerSlot(const class Class * const *))));
+ QVERIFY(object.connect(&object,
+ SIGNAL(constClassPointerConstPointerSignal(const Class * const *)),
+ SLOT(constClassPointerConstPointerSlot(const class Class * const *))));
+ QVERIFY(object.connect(&object,
+ SIGNAL(constClassPointerConstPointerSignal(const class Class * const *)),
+ SLOT(constClassPointerConstPointerSlot(const Class * const *))));
+ QVERIFY(object.connect(&object,
+ SIGNAL(constEnumPointerConstPointerSignal(const enum Enum * const *)),
+ SLOT(constEnumPointerConstPointerSlot(const enum Enum * const *))));
+ QVERIFY(object.connect(&object,
+ SIGNAL(constEnumPointerConstPointerSignal(const Enum * const *)),
+ SLOT(constEnumPointerConstPointerSlot(const enum Enum * const *))));
+ QVERIFY(object.connect(&object,
+ SIGNAL(constEnumPointerConstPointerSignal(const enum Enum * const *)),
+ SLOT(constEnumPointerConstPointerSlot(const Enum * const *))));
+
+ QVERIFY(object.connect(&object,
+ SIGNAL(constStructPointerConstPointerSignal(struct Struct const * const *)),
+ SLOT(constStructPointerConstPointerSlot(struct Struct const * const *))));
+ QVERIFY(object.connect(&object,
+ SIGNAL(constStructPointerConstPointerSignal(Struct const * const *)),
+ SLOT(constStructPointerConstPointerSlot(struct Struct const * const *))));
+ QVERIFY(object.connect(&object,
+ SIGNAL(constStructPointerConstPointerSignal(struct Struct const * const *)),
+ SLOT(constStructPointerConstPointerSlot(Struct const * const *))));
+ QVERIFY(object.connect(&object,
+ SIGNAL(constClassPointerConstPointerSignal(class Class const * const *)),
+ SLOT(constClassPointerConstPointerSlot(class Class const * const *))));
+ QVERIFY(object.connect(&object,
+ SIGNAL(constClassPointerConstPointerSignal(Class const * const *)),
+ SLOT(constClassPointerConstPointerSlot(class Class const * const *))));
+ QVERIFY(object.connect(&object,
+ SIGNAL(constClassPointerConstPointerSignal(class Class const * const *)),
+ SLOT(constClassPointerConstPointerSlot(Class const * const *))));
+ QVERIFY(object.connect(&object,
+ SIGNAL(constEnumPointerConstPointerSignal(enum Enum const * const *)),
+ SLOT(constEnumPointerConstPointerSlot(enum Enum const * const *))));
+ QVERIFY(object.connect(&object,
+ SIGNAL(constEnumPointerConstPointerSignal(Enum const * const *)),
+ SLOT(constEnumPointerConstPointerSlot(enum Enum const * const *))));
+ QVERIFY(object.connect(&object,
+ SIGNAL(constEnumPointerConstPointerSignal(enum Enum const * const *)),
+ SLOT(constEnumPointerConstPointerSlot(Enum const * const *))));
+
+ QVERIFY(object.connect(&object,
+ SIGNAL(unsignedintSignal(unsigned int)),
+ SLOT(unsignedintSlot(unsigned int))));
+ QVERIFY(object.connect(&object,
+ SIGNAL(unsignedSignal(unsigned)),
+ SLOT(unsignedSlot(unsigned))));
+ QVERIFY(object.connect(&object,
+ SIGNAL(unsignedSignal(unsigned)),
+ SLOT(uintSlot(uint))));
+ QVERIFY(object.connect(&object,
+ SIGNAL(unsignedlongSignal(unsigned long)),
+ SLOT(unsignedlongSlot(unsigned long))));
+ QVERIFY(object.connect(&object,
+ SIGNAL(unsignedlonglongSignal(quint64)),
+ SLOT(unsignedlonglongSlot(quint64))));
+ QVERIFY(object.connect(&object,
+ SIGNAL(unsignedlongintSignal(unsigned long int)),
+ SLOT(unsignedlongintSlot(unsigned long int))));
+ QVERIFY(object.connect(&object,
+ SIGNAL(unsignedshortSignal(unsigned short)),
+ SLOT(unsignedshortSlot(unsigned short))));
+ QVERIFY(object.connect(&object,
+ SIGNAL(unsignedcharSignal(unsigned char)),
+ SLOT(unsignedcharSlot(unsigned char))));
+
+ // connect when original template signature and mixed usage of 'T<C const &> const &',
+ // 'const T<const C &> &', and 'T<const C &>'
+
+ QVERIFY(object.connect(&object,
+ SIGNAL(typeRefSignal(Template<Class &> &)),
+ SLOT(typeRefSlot(Template<Class &> &))));
+
+ QVERIFY(object.connect(&object,
+ SIGNAL(constTypeRefSignal(const Template<const Class &> &)),
+ SLOT(constTypeRefSlot(const Template<const Class &> &))));
+ QVERIFY(object.connect(&object,
+ SIGNAL(constTypeRefSignal(const Template<const Class &> &)),
+ SLOT(constTypeRefSlot(const Template<Class const &> &))));
+ QVERIFY(object.connect(&object,
+ SIGNAL(constTypeRefSignal(const Template<const Class &> &)),
+ SLOT(constTypeRefSlot(Template<Class const &> const &))));
+ QVERIFY(object.connect(&object,
+ SIGNAL(constTypeRefSignal(Template<const Class &> const &)),
+ SLOT(constTypeRefSlot(Template<Class const &> const &))));
+ QVERIFY(object.connect(&object,
+ SIGNAL(constTypeRefSignal(Template<Class const &> const &)),
+ SLOT(constTypeRefSlot(Template<Class const &> const &))));
+
+ QVERIFY(object.connect(&object,
+ SIGNAL(constTypeRefSignal(const Template<const Class &> &)),
+ SLOT(typeConstRefSlot(const Template<const Class &> &))));
+ QVERIFY(object.connect(&object,
+ SIGNAL(constTypeRefSignal(const Template<const Class &> &)),
+ SLOT(typeConstRefSlot(const Template<Class const &> &))));
+ QVERIFY(object.connect(&object,
+ SIGNAL(constTypeRefSignal(const Template<const Class &> &)),
+ SLOT(typeConstRefSlot(Template<Class const &> const &))));
+ QVERIFY(object.connect(&object,
+ SIGNAL(constTypeRefSignal(Template<const Class &> const &)),
+ SLOT(typeConstRefSlot(Template<Class const &> const &))));
+ QVERIFY(object.connect(&object,
+ SIGNAL(constTypeRefSignal(Template<Class const &> const &)),
+ SLOT(typeConstRefSlot(Template<Class const &> const &))));
+
+ QVERIFY(object.connect(&object,
+ SIGNAL(typeConstRefSignal(const Template<const Class &> &)),
+ SLOT(constTypeRefSlot(const Template<const Class &> &))));
+ QVERIFY(object.connect(&object,
+ SIGNAL(typeConstRefSignal(const Template<const Class &> &)),
+ SLOT(constTypeRefSlot(const Template<Class const &> &))));
+ QVERIFY(object.connect(&object,
+ SIGNAL(typeConstRefSignal(const Template<const Class &> &)),
+ SLOT(constTypeRefSlot(Template<Class const &> const &))));
+ QVERIFY(object.connect(&object,
+ SIGNAL(typeConstRefSignal(Template<const Class &> const &)),
+ SLOT(constTypeRefSlot(Template<Class const &> const &))));
+ QVERIFY(object.connect(&object,
+ SIGNAL(typeConstRefSignal(Template<Class const &> const &)),
+ SLOT(constTypeRefSlot(Template<Class const &> const &))));
+
+ QVERIFY(object.connect(&object,
+ SIGNAL(typeConstRefSignal(const Template<const Class &> &)),
+ SLOT(typeConstRefSlot(const Template<const Class &> &))));
+ QVERIFY(object.connect(&object,
+ SIGNAL(typeConstRefSignal(const Template<const Class &> &)),
+ SLOT(typeConstRefSlot(const Template<Class const &> &))));
+ QVERIFY(object.connect(&object,
+ SIGNAL(typeConstRefSignal(const Template<const Class &> &)),
+ SLOT(typeConstRefSlot(Template<Class const &> const &))));
+ QVERIFY(object.connect(&object,
+ SIGNAL(typeConstRefSignal(Template<const Class &> const &)),
+ SLOT(typeConstRefSlot(Template<Class const &> const &))));
+ QVERIFY(object.connect(&object,
+ SIGNAL(typeConstRefSignal(Template<Class const &> const &)),
+ SLOT(typeConstRefSlot(Template<Class const &> const &))));
+
+ // same test again, this time with an object compiled with old moc output... we know that
+ // it is not possible to connect everything, whic is the purpose for this test
+ OldNormalizeObject oldobject;
+
+ QVERIFY(oldobject.connect(&oldobject,
+ SIGNAL(constTypeRefSignal(const Template<const Class &> &)),
+ SLOT(constTypeRefSlot(const Template<const Class &> &))));
+ QVERIFY(oldobject.connect(&oldobject,
+ SIGNAL(constTypeRefSignal(const Template<const Class &> &)),
+ SLOT(constTypeRefSlot(const Template<Class const &> &))));
+ // this fails in older versions, but passes now due to proper normalizing
+ QVERIFY(oldobject.connect(&oldobject,
+ SIGNAL(constTypeRefSignal(const Template<const Class &> &)),
+ SLOT(constTypeRefSlot(Template<Class const &> const &))));
+ // this fails in older versions, but passes now due to proper normalizing
+ QVERIFY(oldobject.connect(&oldobject,
+ SIGNAL(constTypeRefSignal(Template<const Class &> const &)),
+ SLOT(constTypeRefSlot(Template<Class const &> const &))));
+ // this fails in older versions, but passes now due to proper normalizing
+ QVERIFY(oldobject.connect(&oldobject,
+ SIGNAL(constTypeRefSignal(Template<Class const &> const &)),
+ SLOT(constTypeRefSlot(Template<Class const &> const &))));
+
+ // these fail in older Qt versions, but pass now due to proper normalizing
+ QVERIFY(oldobject.connect(&oldobject,
+ SIGNAL(constTypeRefSignal(const Template<const Class &> &)),
+ SLOT(typeConstRefSlot(const Template<const Class &> &))));
+ QVERIFY(oldobject.connect(&oldobject,
+ SIGNAL(constTypeRefSignal(const Template<const Class &> &)),
+ SLOT(typeConstRefSlot(const Template<Class const &> &))));
+ QVERIFY(oldobject.connect(&oldobject,
+ SIGNAL(constTypeRefSignal(const Template<const Class &> &)),
+ SLOT(typeConstRefSlot(Template<Class const &> const &))));
+ QVERIFY(oldobject.connect(&oldobject,
+ SIGNAL(constTypeRefSignal(Template<const Class &> const &)),
+ SLOT(typeConstRefSlot(Template<Class const &> const &))));
+ QVERIFY(oldobject.connect(&oldobject,
+ SIGNAL(constTypeRefSignal(Template<Class const &> const &)),
+ SLOT(typeConstRefSlot(Template<Class const &> const &))));
+
+ // these also fail in older Qt versions, but pass now due to proper normalizing
+ QVERIFY(oldobject.connect(&oldobject,
+ SIGNAL(typeConstRefSignal(const Template<const Class &> &)),
+ SLOT(constTypeRefSlot(const Template<const Class &> &))));
+ QVERIFY(oldobject.connect(&oldobject,
+ SIGNAL(typeConstRefSignal(const Template<const Class &> &)),
+ SLOT(constTypeRefSlot(const Template<Class const &> &))));
+ QVERIFY(oldobject.connect(&oldobject,
+ SIGNAL(typeConstRefSignal(const Template<const Class &> &)),
+ SLOT(constTypeRefSlot(Template<Class const &> const &))));
+ QVERIFY(oldobject.connect(&oldobject,
+ SIGNAL(typeConstRefSignal(Template<const Class &> const &)),
+ SLOT(constTypeRefSlot(Template<Class const &> const &))));
+ QVERIFY(oldobject.connect(&oldobject,
+ SIGNAL(typeConstRefSignal(Template<Class const &> const &)),
+ SLOT(constTypeRefSlot(Template<Class const &> const &))));
+
+ // this fails in older versions, but passes now due to proper normalizing
+ QVERIFY(oldobject.connect(&oldobject,
+ SIGNAL(typeConstRefSignal(const Template<const Class &> &)),
+ SLOT(typeConstRefSlot(const Template<const Class &> &))));
+ // this fails in older versions, but passes now due to proper normalizing
+ QVERIFY(oldobject.connect(&oldobject,
+ SIGNAL(typeConstRefSignal(const Template<const Class &> &)),
+ SLOT(typeConstRefSlot(const Template<Class const &> &))));
+ // this fails in older versions, but passes now due to proper normalizing
+ QVERIFY(oldobject.connect(&oldobject,
+ SIGNAL(typeConstRefSignal(const Template<const Class &> &)),
+ SLOT(typeConstRefSlot(Template<Class const &> const &))));
+ QVERIFY(oldobject.connect(&oldobject,
+ SIGNAL(typeConstRefSignal(Template<const Class &> const &)),
+ SLOT(typeConstRefSlot(Template<Class const &> const &))));
+ QVERIFY(oldobject.connect(&oldobject,
+ SIGNAL(typeConstRefSignal(Template<Class const &> const &)),
+ SLOT(typeConstRefSlot(Template<Class const &> const &))));
+
+ QVERIFY(object.connect(&object,
+ SIGNAL(typePointerConstRefSignal(Class*const&)),
+ SLOT(typePointerConstRefSlot(Class*const&))));
+ QVERIFY(object.connect(&object,
+ SIGNAL(typePointerConstRefSignal(Class*const&)),
+ SLOT(typePointerConstRefSlot(Class*))));
+ QVERIFY(object.connect(&object,
+ SIGNAL(typePointerConstRefSignal(Class*)),
+ SLOT(typePointerConstRefSlot(Class*const&))));
+ QVERIFY(object.connect(&object,
+ SIGNAL(typePointerConstRefSignal(Class*)),
+ SLOT(typePointerConstRefSlot(Class*))));
+
+ QVERIFY( connect(&object, SIGNAL(constTemplateSignal1(Template <int>)),
+ &object , SLOT(constTemplateSlot1 (Template<int > ) ) ));
+ QVERIFY( connect(&object, SIGNAL(constTemplateSignal1(Template <int>)),
+ &object , SLOT(constTemplateSlot2 (Template<int > ) ) ));
+ QVERIFY( connect(&object, SIGNAL(constTemplateSignal2(Template <const int>)),
+ &object , SLOT(constTemplateSlot3(Template<int const > ) ) ));
+
+ //type does not match
+ QTest::ignoreMessage(QtWarningMsg, "QObject::connect: Incompatible sender/receiver arguments\n"
+ " NormalizeObject::constTemplateSignal1(Template<int>) --> NormalizeObject::constTemplateSlot3(Template<const int>)");
+ QVERIFY(!connect(&object, SIGNAL(constTemplateSignal1(Template <int>)),
+ &object , SLOT(constTemplateSlot3(Template<int const> ) ) ));
+}
+
+class SiblingDeleter : public QObject
+{
+public:
+ inline SiblingDeleter(QObject *sibling, QObject *parent)
+ : QObject(parent), sibling(sibling) {}
+ inline virtual ~SiblingDeleter() { delete sibling; }
+
+private:
+ QPointer<QObject> sibling;
+};
+
+
+void tst_QObject::childDeletesItsSibling()
+{
+ QObject *commonParent = new QObject(0);
+ QPointer<QObject> child = new QObject(0);
+ QPointer<QObject> siblingDeleter = new SiblingDeleter(child, commonParent);
+ child->setParent(commonParent);
+ delete commonParent; // don't crash
+ QVERIFY(!child);
+ QVERIFY(!siblingDeleter);
+}
+
+void tst_QObject::floatProperty()
+{
+ PropertyObject obj;
+ const int idx = obj.metaObject()->indexOfProperty("myFloat");
+ QVERIFY(idx > 0);
+ QMetaProperty prop = obj.metaObject()->property(idx);
+ QVERIFY(prop.isValid());
+ QVERIFY(prop.type() == uint(QMetaType::type("float")));
+ QVERIFY(!prop.write(&obj, QVariant("Hello")));
+ QVERIFY(prop.write(&obj, qVariantFromValue(128.0f)));
+ QVariant v = prop.read(&obj);
+ QVERIFY(int(v.userType()) == QMetaType::Float);
+ QVERIFY(qVariantValue<float>(v) == 128.0f);
+}
+
+void tst_QObject::qrealProperty()
+{
+ PropertyObject obj;
+ const int idx = obj.metaObject()->indexOfProperty("myQReal");
+ QVERIFY(idx > 0);
+ QMetaProperty prop = obj.metaObject()->property(idx);
+ QVERIFY(prop.isValid());
+ QVERIFY(prop.type() == uint(QMetaType::type("qreal")));
+ QVERIFY(!prop.write(&obj, QVariant("Hello")));
+
+ QVERIFY(prop.write(&obj, qVariantFromValue(128.0f)));
+ QVariant v = prop.read(&obj);
+ QCOMPARE(v.userType(), qMetaTypeId<qreal>());
+ QVERIFY(qVariantValue<qreal>(v) == 128.0);
+
+ QVERIFY(prop.write(&obj, qVariantFromValue(double(127))));
+ v = prop.read(&obj);
+ QCOMPARE(v.userType(), qMetaTypeId<qreal>());
+ QVERIFY(qVariantValue<qreal>(v) == 127.0);
+}
+
+class DynamicPropertyObject : public PropertyObject
+{
+public:
+ inline DynamicPropertyObject() {}
+
+ inline virtual bool event(QEvent *e) {
+ if (e->type() == QEvent::DynamicPropertyChange) {
+ changedDynamicProperties.append(static_cast<QDynamicPropertyChangeEvent *>(e)->propertyName());
+ }
+ return QObject::event(e);
+ }
+
+ QList<QByteArray> changedDynamicProperties;
+};
+
+void tst_QObject::dynamicProperties()
+{
+ DynamicPropertyObject obj;
+
+ QVERIFY(obj.dynamicPropertyNames().isEmpty());
+
+ QVERIFY(obj.setProperty("number", 42));
+ QVERIFY(obj.changedDynamicProperties.isEmpty());
+ QCOMPARE(obj.property("number").toInt(), 42);
+
+ QVERIFY(!obj.setProperty("number", "invalid string"));
+ QVERIFY(obj.changedDynamicProperties.isEmpty());
+
+ QVERIFY(!obj.setProperty("myuserproperty", "Hello"));
+ QCOMPARE(obj.changedDynamicProperties.count(), 1);
+ QCOMPARE(obj.changedDynamicProperties.first(), QByteArray("myuserproperty"));
+ obj.changedDynamicProperties.clear();
+
+ QCOMPARE(obj.property("myuserproperty").toString(), QString("Hello"));
+
+ QCOMPARE(obj.dynamicPropertyNames().count(), 1);
+ QCOMPARE(obj.dynamicPropertyNames().first(), QByteArray("myuserproperty"));
+
+ QVERIFY(!obj.setProperty("myuserproperty", QVariant()));
+
+ QCOMPARE(obj.changedDynamicProperties.count(), 1);
+ QCOMPARE(obj.changedDynamicProperties.first(), QByteArray("myuserproperty"));
+ obj.changedDynamicProperties.clear();
+
+ QVERIFY(obj.property("myuserproperty").isNull());
+
+ QVERIFY(obj.dynamicPropertyNames().isEmpty());
+}
+
+void tst_QObject::recursiveSignalEmission()
+{
+#if defined(Q_OS_SYMBIAN) && defined(Q_CC_NOKIAX86)
+ QSKIP("Emulator builds in Symbian do not support launching processes linking to Qt", SkipAll);
+#elif defined(QT_NO_PROCESS)
+ QSKIP("Test requires QProcess", SkipAll);
+#else
+ QProcess proc;
+ proc.start("./signalbug");
+ QVERIFY(proc.waitForFinished());
+ QVERIFY(proc.exitStatus() == QProcess::NormalExit);
+ QCOMPARE(proc.exitCode(), 0);
+#endif
+}
+
+void tst_QObject::blockingQueuedConnection()
+{
+ {
+ SenderObject sender;
+
+ MoveToThreadThread thread;
+ ReceiverObject receiver;
+ receiver.moveToThread(&thread);
+ thread.start();
+
+ receiver.connect(&sender, SIGNAL(signal1()), SLOT(slot1()), Qt::BlockingQueuedConnection);
+ sender.emitSignal1();
+ QVERIFY(receiver.called(1));
+
+ receiver.reset();
+ QVERIFY(QMetaObject::invokeMethod(&receiver, "slot1", Qt::BlockingQueuedConnection));
+ QVERIFY(receiver.called(1));
+
+ thread.quit();
+ QVERIFY(thread.wait());
+ }
+}
+
+class EventSpy : public QObject
+{
+ Q_OBJECT
+
+public:
+ typedef QList<QPair<QObject *, QEvent::Type> > EventList;
+
+ EventSpy(QObject *parent = 0)
+ : QObject(parent)
+ { }
+
+ EventList eventList()
+ {
+ return events;
+ }
+
+ void clear()
+ {
+ events.clear();
+ }
+
+ bool eventFilter(QObject *object, QEvent *event)
+ {
+ events.append(qMakePair(object, event->type()));
+ return false;
+ }
+
+private:
+ EventList events;
+};
+
+void tst_QObject::compatibilityChildInsertedEvents()
+{
+ EventSpy::EventList expected;
+
+ {
+ // no children created, so we expect no events
+ QObject object;
+ EventSpy spy;
+ object.installEventFilter(&spy);
+
+ QCoreApplication::postEvent(&object, new QEvent(QEvent::Type(QEvent::User + 1)));
+
+ QCoreApplication::processEvents();
+
+ expected =
+ EventSpy::EventList()
+ << qMakePair(&object, QEvent::Type(QEvent::User + 1));
+ QCOMPARE(spy.eventList(), expected);
+ }
+
+ {
+ // 2 children, so we expect 2 ChildAdded and 2 ChildInserted events
+ QObject object;
+ EventSpy spy;
+ object.installEventFilter(&spy);
+
+ QCoreApplication::postEvent(&object, new QEvent(QEvent::Type(QEvent::User + 1)));
+
+ QObject child1(&object);
+ QObject child2;
+ child2.setParent(&object);
+
+ QCoreApplication::postEvent(&object, new QEvent(QEvent::Type(QEvent::User + 2)));
+
+ expected =
+ EventSpy::EventList()
+ << qMakePair(&object, QEvent::ChildAdded)
+ << qMakePair(&object, QEvent::ChildAdded);
+ QCOMPARE(spy.eventList(), expected);
+ spy.clear();
+
+ QCoreApplication::processEvents();
+
+ expected =
+ EventSpy::EventList()
+#ifdef QT_HAS_QT3SUPPORT
+ << qMakePair(&object, QEvent::ChildInsertedRequest)
+ << qMakePair(&object, QEvent::ChildInserted)
+ << qMakePair(&object, QEvent::ChildInserted)
+#endif
+ << qMakePair(&object, QEvent::Type(QEvent::User + 1))
+ << qMakePair(&object, QEvent::Type(QEvent::User + 2));
+ QCOMPARE(spy.eventList(), expected);
+ }
+
+ {
+ // 2 children, but one is reparented away, so we expect:
+ // 2 ChildAdded, 1 ChildRemoved, and 1 ChildInserted
+ QObject object;
+ EventSpy spy;
+ object.installEventFilter(&spy);
+
+ QCoreApplication::postEvent(&object, new QEvent(QEvent::Type(QEvent::User + 1)));
+
+ QObject child1(&object);
+ QObject child2;
+ child2.setParent(&object);
+ child2.setParent(0);
+
+ QCoreApplication::postEvent(&object, new QEvent(QEvent::Type(QEvent::User + 2)));
+
+ expected =
+ EventSpy::EventList()
+ << qMakePair(&object, QEvent::ChildAdded)
+ << qMakePair(&object, QEvent::ChildAdded)
+ << qMakePair(&object, QEvent::ChildRemoved);
+ QCOMPARE(spy.eventList(), expected);
+ spy.clear();
+
+ QCoreApplication::processEvents();
+
+ expected =
+ EventSpy::EventList()
+#ifdef QT_HAS_QT3SUPPORT
+ << qMakePair(&object, QEvent::ChildInsertedRequest)
+ << qMakePair(&object, QEvent::ChildInserted)
+#endif
+ << qMakePair(&object, QEvent::Type(QEvent::User + 1))
+ << qMakePair(&object, QEvent::Type(QEvent::User + 2));
+ QCOMPARE(spy.eventList(), expected);
+ }
+}
+
+void tst_QObject::installEventFilter()
+{
+ QEvent event(QEvent::User);
+ EventSpy::EventList expected;
+
+ QObject object;
+ EventSpy spy;
+ object.installEventFilter(&spy);
+
+ // nothing special, should just work
+ QCoreApplication::sendEvent(&object, &event);
+ expected =
+ EventSpy::EventList()
+ << qMakePair(&object, QEvent::User);
+ QCOMPARE(spy.eventList(), expected);
+ spy.clear();
+
+ // moving the filter causes QCoreApplication to skip the filter
+ spy.moveToThread(0);
+ QTest::ignoreMessage(QtWarningMsg, "QCoreApplication: Object event filter cannot be in a different thread.");
+ QCoreApplication::sendEvent(&object, &event);
+ QVERIFY(spy.eventList().isEmpty());
+
+ // move it back, and the filter works again
+ spy.moveToThread(object.thread());
+ QCoreApplication::sendEvent(&object, &event);
+ expected =
+ EventSpy::EventList()
+ << qMakePair(&object, QEvent::User);
+ QCOMPARE(spy.eventList(), expected);
+ spy.clear();
+
+ // cannot install an event filter that lives in a different thread
+ object.removeEventFilter(&spy);
+ spy.moveToThread(0);
+ QTest::ignoreMessage(QtWarningMsg, "QObject::installEventFilter(): Cannot filter events for objects in a different thread.");
+ object.installEventFilter(&spy);
+ QCoreApplication::sendEvent(&object, &event);
+ QVERIFY(spy.eventList().isEmpty());
+}
+
+class EmitThread : public QThread
+{ Q_OBJECT
+public:
+ void run(void) {
+ emit work();
+ }
+signals:
+ void work();
+};
+
+class DeleteObject : public QObject
+{
+ Q_OBJECT
+
+public slots:
+ void deleteSelf()
+ {
+ delete this;
+ }
+
+ void relaySignalAndProcessEvents()
+ {
+ emit relayedSignal();
+ QCoreApplication::processEvents();
+ }
+
+signals:
+ void relayedSignal();
+};
+
+void tst_QObject::deleteSelfInSlot()
+{
+ {
+ SenderObject sender;
+ DeleteObject *receiver = new DeleteObject();
+ receiver->connect(&sender,
+ SIGNAL(signal1()),
+ SLOT(deleteSelf()),
+ Qt::BlockingQueuedConnection);
+
+ QThread thread;
+ receiver->moveToThread(&thread);
+ thread.connect(receiver, SIGNAL(destroyed()), SLOT(quit()), Qt::DirectConnection);
+ thread.start();
+
+ QPointer<DeleteObject> p = receiver;
+ sender.emitSignal1();
+ QVERIFY(p.isNull());
+
+ QVERIFY(thread.wait(10000));
+ }
+
+ {
+ SenderObject sender;
+ DeleteObject *receiver = new DeleteObject();
+ receiver->connect(&sender,
+ SIGNAL(signal1()),
+ SLOT(relaySignalAndProcessEvents()),
+ Qt::BlockingQueuedConnection);
+ receiver->connect(receiver,
+ SIGNAL(relayedSignal()),
+ SLOT(deleteSelf()),
+ Qt::QueuedConnection);
+
+ QThread thread;
+ receiver->moveToThread(&thread);
+ thread.connect(receiver, SIGNAL(destroyed()), SLOT(quit()), Qt::DirectConnection);
+ thread.start();
+
+ QPointer<DeleteObject> p = receiver;
+ sender.emitSignal1();
+ QVERIFY(p.isNull());
+
+ QVERIFY(thread.wait(10000));
+ }
+
+ {
+ EmitThread sender;
+ DeleteObject *receiver = new DeleteObject();
+ connect(&sender, SIGNAL(work()), receiver, SLOT(deleteSelf()), Qt::DirectConnection);
+ QPointer<DeleteObject> p = receiver;
+ sender.start();
+ QVERIFY(sender.wait(10000));
+ QVERIFY(p.isNull());
+ }
+}
+
+class DisconnectObject : public QObject
+{
+ Q_OBJECT
+
+public slots:
+ void disconnectSelf()
+ {
+ disconnect(sender(), 0, this, 0);
+ }
+
+ void relaySignalAndProcessEvents()
+ {
+ emit relayedSignal();
+ QCoreApplication::processEvents();
+ }
+
+signals:
+ void relayedSignal();
+};
+
+void tst_QObject::disconnectSelfInSlotAndDeleteAfterEmit()
+{
+ {
+ SenderObject sender;
+ DisconnectObject *receiver = new DisconnectObject();
+ receiver->connect(&sender, SIGNAL(signal1()), SLOT(disconnectSelf()));
+ sender.emitSignal1AfterRecursion();
+ delete receiver;
+ }
+
+ {
+ SenderObject sender;
+ DisconnectObject *receiver = new DisconnectObject();
+ receiver->connect(&sender,
+ SIGNAL(signal1()),
+ SLOT(disconnectSelf()),
+ Qt::BlockingQueuedConnection);
+
+ QThread thread;
+ receiver->moveToThread(&thread);
+ thread.connect(receiver, SIGNAL(destroyed()), SLOT(quit()), Qt::DirectConnection);
+ thread.start();
+
+ QPointer<DisconnectObject> p = receiver;
+ sender.emitSignal1();
+ QVERIFY(!p.isNull());
+
+ receiver->deleteLater();
+
+ QVERIFY(thread.wait(10000));
+ QVERIFY(p.isNull());
+ }
+
+ {
+ SenderObject sender;
+ DisconnectObject *receiver = new DisconnectObject();
+ receiver->connect(&sender,
+ SIGNAL(signal1()),
+ SLOT(relaySignalAndProcessEvents()),
+ Qt::BlockingQueuedConnection);
+ receiver->connect(receiver,
+ SIGNAL(relayedSignal()),
+ SLOT(disconnectSelf()),
+ Qt::QueuedConnection);
+
+ QThread thread;
+ receiver->moveToThread(&thread);
+ thread.connect(receiver, SIGNAL(destroyed()), SLOT(quit()), Qt::DirectConnection);
+ thread.start();
+
+ QPointer<DisconnectObject> p = receiver;
+ sender.emitSignal1();
+ QVERIFY(!p.isNull());
+
+ receiver->deleteLater();
+
+ QVERIFY(thread.wait(10000));
+ QVERIFY(p.isNull());
+ }
+}
+
+void tst_QObject::dumpObjectInfo()
+{
+ QObject a, b;
+ QObject::connect(&a, SIGNAL(destroyed(QObject *)), &b, SLOT(deleteLater()));
+ a.disconnect(&b);
+ a.dumpObjectInfo(); // should not crash
+}
+
+class ConnectToSender : public QObject
+{ Q_OBJECT
+ public slots:
+ void uselessSlot() { count++; }
+
+ void harmfullSlot() {
+ //this used to crash
+ connect(sender(), SIGNAL(signal4()), this, SLOT(uselessSlot()));
+ //play a little bit with the memory in order to really get a segfault.
+ connect(sender(), SIGNAL(signal1()), this, SLOT(uselessSlot()));
+ QList<double>() << 45 << 78 << 65 << 121 << 45 << 78 << 12;
+ }
+ public:
+ int count;
+};
+
+void tst_QObject::connectToSender()
+{
+ SenderObject s;
+ ConnectToSender r;
+ r.count = 0;
+ QObject::connect(&s, SIGNAL(signal1()), &r, SLOT(harmfullSlot()));
+ QObject::connect(&s, SIGNAL(signal1()), &r, SLOT(uselessSlot()));
+
+ s.emitSignal1();
+
+ QCOMPARE(r.count, 1);
+ s.emitSignal4();
+ QCOMPARE(r.count, 2);
+}
+
+void tst_QObject::qobjectConstCast()
+{
+ FooObject obj;
+
+ QObject *ptr = &obj;
+ const QObject *cptr = &obj;
+
+ QVERIFY(qobject_cast<FooObject *>(ptr));
+ QVERIFY(qobject_cast<const FooObject *>(cptr));
+}
+
+void tst_QObject::uniqConnection()
+{
+ SenderObject *s = new SenderObject;
+ ReceiverObject *r1 = new ReceiverObject;
+ ReceiverObject *r2 = new ReceiverObject;
+ r1->reset();
+ r2->reset();
+ ReceiverObject::sequence = 0;
+
+ QVERIFY( connect( s, SIGNAL( signal1() ), r1, SLOT( slot1() ) , Qt::UniqueConnection) );
+ QVERIFY( connect( s, SIGNAL( signal1() ), r2, SLOT( slot1() ) , Qt::UniqueConnection) );
+ QVERIFY( connect( s, SIGNAL( signal1() ), r1, SLOT( slot3() ) , Qt::UniqueConnection) );
+ QVERIFY( connect( s, SIGNAL( signal3() ), r1, SLOT( slot3() ) , Qt::UniqueConnection) );
+
+ s->emitSignal1();
+ s->emitSignal2();
+ s->emitSignal3();
+ s->emitSignal4();
+
+ QCOMPARE( r1->count_slot1, 1 );
+ QCOMPARE( r1->count_slot2, 0 );
+ QCOMPARE( r1->count_slot3, 2 );
+ QCOMPARE( r1->count_slot4, 0 );
+ QCOMPARE( r2->count_slot1, 1 );
+ QCOMPARE( r2->count_slot2, 0 );
+ QCOMPARE( r2->count_slot3, 0 );
+ QCOMPARE( r2->count_slot4, 0 );
+ QCOMPARE( r1->sequence_slot1, 1 );
+ QCOMPARE( r2->sequence_slot1, 2 );
+ QCOMPARE( r1->sequence_slot3, 4 );
+
+ r1->reset();
+ r2->reset();
+ ReceiverObject::sequence = 0;
+
+ QVERIFY( connect( s, SIGNAL( signal4() ), r1, SLOT( slot4() ) , Qt::UniqueConnection) );
+ QVERIFY( connect( s, SIGNAL( signal4() ), r2, SLOT( slot4() ) , Qt::UniqueConnection) );
+ QVERIFY(!connect( s, SIGNAL( signal4() ), r2, SLOT( slot4() ) , Qt::UniqueConnection) );
+ QVERIFY( connect( s, SIGNAL( signal1() ), r2, SLOT( slot4() ) , Qt::UniqueConnection) );
+ QVERIFY(!connect( s, SIGNAL( signal4() ), r1, SLOT( slot4() ) , Qt::UniqueConnection) );
+
+ s->emitSignal4();
+ QCOMPARE( r1->count_slot4, 1 );
+ QCOMPARE( r2->count_slot4, 1 );
+ QCOMPARE( r1->sequence_slot4, 1 );
+ QCOMPARE( r2->sequence_slot4, 2 );
+
+ r1->reset();
+ r2->reset();
+ ReceiverObject::sequence = 0;
+
+ connect( s, SIGNAL( signal4() ), r1, SLOT( slot4() ) );
+
+ s->emitSignal4();
+ QCOMPARE( r1->count_slot4, 2 );
+ QCOMPARE( r2->count_slot4, 1 );
+ QCOMPARE( r1->sequence_slot4, 3 );
+ QCOMPARE( r2->sequence_slot4, 2 );
+
+ delete s;
+ delete r1;
+ delete r2;
+}
+
+void tst_QObject::interfaceIid()
+{
+ QCOMPARE(QByteArray(qobject_interface_iid<Foo::Bleh *>()),
+ QByteArray(Bleh_iid));
+ QCOMPARE(QByteArray(qobject_interface_iid<Foo::Bar *>()),
+ QByteArray("com.qtest.foobar"));
+ QCOMPARE(QByteArray(qobject_interface_iid<FooObject *>()),
+ QByteArray());
+}
+
+void tst_QObject::deleteQObjectWhenDeletingEvent()
+{
+ //this is related to task 259514
+ //before the fix this used to dead lock when the QObject from the event was destroyed
+
+ struct MyEvent : public QEvent
+ {
+ MyEvent() : QEvent(QEvent::User) { }
+ QObject obj;
+ };
+
+ QObject o;
+ QApplication::postEvent(&o, new MyEvent);
+ QCoreApplication::removePostedEvents(&o); // here you would get a deadlock
+}
+
+class OverloadObject : public QObject
+{
+ friend class tst_QObject;
+ Q_OBJECT
+ signals:
+ void sig(int i, char c, qreal m = 12);
+ void sig(int i, int j = 12);
+ void sig(QObject *o, QObject *p, QObject *q = 0, QObject *r = 0) const;
+ void other(int a = 0);
+ void sig(QObject *o, OverloadObject *p = 0, QObject *q = 0, QObject *r = 0);
+ void sig(double r = 0.5);
+ public slots:
+ void slo(int i, int j = 43)
+ {
+ s_num += 1;
+ i1_num = i;
+ i2_num = j;
+ }
+ void slo(QObject *o, QObject *p = qApp, QObject *q = qApp, QObject *r = qApp)
+ {
+ s_num += 10;
+ o1_obj = o;
+ o2_obj = p;
+ o3_obj = q;
+ o4_obj = r;
+ }
+ void slo()
+ {
+ s_num += 100;
+ }
+
+ public:
+ int s_num;
+ int i1_num;
+ int i2_num;
+ QObject *o1_obj;
+ QObject *o2_obj;
+ QObject *o3_obj;
+ QObject *o4_obj;
+};
+
+void tst_QObject::overloads()
+{
+ OverloadObject obj1;
+ OverloadObject obj2;
+ QObject obj3;
+ obj1.s_num = 0;
+ obj2.s_num = 0;
+
+ connect (&obj1, SIGNAL(sig(int)) , &obj1, SLOT(slo(int)));
+ connect (&obj1, SIGNAL(sig(QObject *, QObject *, QObject *)) , &obj1, SLOT(slo(QObject * , QObject *, QObject *)));
+
+ connect (&obj1, SIGNAL(sig(QObject *, QObject *, QObject *, QObject *)) , &obj2, SLOT(slo(QObject * , QObject *, QObject *)));
+ connect (&obj1, SIGNAL(sig(QObject *)) , &obj2, SLOT(slo()));
+ connect (&obj1, SIGNAL(sig(int, int)) , &obj2, SLOT(slo(int, int)));
+
+ emit obj1.sig(0.5); //connected to nothing
+ emit obj1.sig(1, 'a'); //connected to nothing
+ QCOMPARE(obj1.s_num, 0);
+ QCOMPARE(obj2.s_num, 0);
+
+ emit obj1.sig(1); //this signal is connected
+ QCOMPARE(obj1.s_num, 1);
+ QCOMPARE(obj1.i1_num, 1);
+ QCOMPARE(obj1.i2_num, 43); //default argument of the slot
+
+ QCOMPARE(obj2.s_num, 1);
+ QCOMPARE(obj2.i1_num, 1);
+ QCOMPARE(obj2.i2_num, 12); //default argument of the signal
+
+
+ emit obj1.sig(&obj2); //this signal is conencted to obj2
+ QCOMPARE(obj1.s_num, 1);
+ QCOMPARE(obj2.s_num, 101);
+ emit obj1.sig(&obj2, &obj3); //this signal is connected
+ QCOMPARE(obj1.s_num, 11);
+ QCOMPARE(obj1.o1_obj, (QObject *)&obj2);
+ QCOMPARE(obj1.o2_obj, &obj3);
+ QCOMPARE(obj1.o3_obj, (QObject *)0); //default arg of the signal
+ QCOMPARE(obj1.o4_obj, (QObject *)qApp); //default arg of the slot
+
+ QCOMPARE(obj2.s_num, 111);
+ QCOMPARE(obj2.o1_obj, (QObject *)&obj2);
+ QCOMPARE(obj2.o2_obj, &obj3);
+ QCOMPARE(obj2.o3_obj, (QObject *)0); //default arg of the signal
+ QCOMPARE(obj2.o4_obj, (QObject *)qApp); //default arg of the slot
+}
+
+class ManySignals : public QObject
+{ Q_OBJECT
+ friend class tst_QObject;
+signals:
+ void sig00(); void sig01(); void sig02(); void sig03(); void sig04();
+ void sig05(); void sig06(); void sig07(); void sig08(); void sig09();
+ void sig10(); void sig11(); void sig12(); void sig13(); void sig14();
+ void sig15(); void sig16(); void sig17(); void sig18(); void sig19();
+ void sig20(); void sig21(); void sig22(); void sig23(); void sig24();
+ void sig25(); void sig26(); void sig27(); void sig28(); void sig29();
+ void sig30(); void sig31(); void sig32(); void sig33(); void sig34();
+ void sig35(); void sig36(); void sig37(); void sig38(); void sig39();
+ void sig40(); void sig41(); void sig42(); void sig43(); void sig44();
+ void sig45(); void sig46(); void sig47(); void sig48(); void sig49();
+ void sig50(); void sig51(); void sig52(); void sig53(); void sig54();
+ void sig55(); void sig56(); void sig57(); void sig58(); void sig59();
+ void sig60(); void sig61(); void sig62(); void sig63(); void sig64();
+ void sig65(); void sig66(); void sig67(); void sig68(); void sig69();
+
+public slots:
+ void received() { rec++; }
+public:
+ int rec;
+};
+
+
+void tst_QObject::isSignalConnected()
+{
+ ManySignals o;
+ o.rec = 0;
+#ifdef QT_BUILD_INTERNAL
+ QObjectPrivate *priv = QObjectPrivate::get(&o);
+ QVERIFY(!priv->isSignalConnected(priv->signalIndex("destroyed()")));
+ QVERIFY(!priv->isSignalConnected(priv->signalIndex("sig00()")));
+ QVERIFY(!priv->isSignalConnected(priv->signalIndex("sig05()")));
+ QVERIFY(!priv->isSignalConnected(priv->signalIndex("sig15()")));
+ QVERIFY(!priv->isSignalConnected(priv->signalIndex("sig29()")));
+ QVERIFY(!priv->isSignalConnected(priv->signalIndex("sig60()")));
+ QVERIFY(!priv->isSignalConnected(priv->signalIndex("sig61()")));
+#endif
+
+ QObject::connect(&o, SIGNAL(sig00()), &o, SIGNAL(sig69()));
+ QObject::connect(&o, SIGNAL(sig34()), &o, SIGNAL(sig03()));
+ QObject::connect(&o, SIGNAL(sig69()), &o, SIGNAL(sig34()));
+ QObject::connect(&o, SIGNAL(sig03()), &o, SIGNAL(sig18()));
+
+#ifdef QT_BUILD_INTERNAL
+ QVERIFY(!priv->isSignalConnected(priv->signalIndex("destroyed()")));
+ QVERIFY(!priv->isSignalConnected(priv->signalIndex("sig05()")));
+ QVERIFY(!priv->isSignalConnected(priv->signalIndex("sig15()")));
+ QVERIFY(!priv->isSignalConnected(priv->signalIndex("sig29()")));
+
+ QVERIFY(priv->isSignalConnected(priv->signalIndex("sig00()")));
+ QVERIFY(priv->isSignalConnected(priv->signalIndex("sig03()")));
+ QVERIFY(priv->isSignalConnected(priv->signalIndex("sig34()")));
+ QVERIFY(priv->isSignalConnected(priv->signalIndex("sig69()")));
+ QVERIFY(!priv->isSignalConnected(priv->signalIndex("sig18()")));
+#endif
+
+ QObject::connect(&o, SIGNAL(sig18()), &o, SIGNAL(sig29()));
+ QObject::connect(&o, SIGNAL(sig29()), &o, SIGNAL(sig62()));
+ QObject::connect(&o, SIGNAL(sig62()), &o, SIGNAL(sig28()));
+ QObject::connect(&o, SIGNAL(sig28()), &o, SIGNAL(sig27()));
+
+#ifdef QT_BUILD_INTERNAL
+ QVERIFY(priv->isSignalConnected(priv->signalIndex("sig18()")));
+ QVERIFY(priv->isSignalConnected(priv->signalIndex("sig62()")));
+ QVERIFY(priv->isSignalConnected(priv->signalIndex("sig28()")));
+ QVERIFY(priv->isSignalConnected(priv->signalIndex("sig69()")));
+ QVERIFY(!priv->isSignalConnected(priv->signalIndex("sig27()")));
+#endif
+
+ QCOMPARE(o.rec, 0);
+ emit o.sig01();
+ emit o.sig34();
+ QCOMPARE(o.rec, 0);
+
+ QObject::connect(&o, SIGNAL(sig27()), &o, SLOT(received()));
+
+#ifdef QT_BUILD_INTERNAL
+ QVERIFY(priv->isSignalConnected(priv->signalIndex("sig00()")));
+ QVERIFY(priv->isSignalConnected(priv->signalIndex("sig03()")));
+ QVERIFY(priv->isSignalConnected(priv->signalIndex("sig34()")));
+ QVERIFY(priv->isSignalConnected(priv->signalIndex("sig18()")));
+ QVERIFY(priv->isSignalConnected(priv->signalIndex("sig62()")));
+ QVERIFY(priv->isSignalConnected(priv->signalIndex("sig28()")));
+ QVERIFY(priv->isSignalConnected(priv->signalIndex("sig69()")));
+ QVERIFY(priv->isSignalConnected(priv->signalIndex("sig27()")));
+
+ QVERIFY(!priv->isSignalConnected(priv->signalIndex("sig04()")));
+ QVERIFY(!priv->isSignalConnected(priv->signalIndex("sig21()")));
+ QVERIFY(!priv->isSignalConnected(priv->signalIndex("sig25()")));
+ QVERIFY(!priv->isSignalConnected(priv->signalIndex("sig55()")));
+ QVERIFY(!priv->isSignalConnected(priv->signalIndex("sig61()")));
+#endif
+
+ emit o.sig00();
+ QCOMPARE(o.rec, 1);
+ emit o.sig69();
+ QCOMPARE(o.rec, 2);
+ emit o.sig36();
+ QCOMPARE(o.rec, 2);
+}
+
+void tst_QObject::qMetaObjectConnect()
+{
+ SenderObject *s = new SenderObject;
+ ReceiverObject *r1 = new ReceiverObject;
+ ReceiverObject *r2 = new ReceiverObject;
+ r1->reset();
+ r2->reset();
+ ReceiverObject::sequence = 0;
+
+ int signal1Index = s->metaObject()->indexOfSignal("signal1()");
+ int signal3Index = s->metaObject()->indexOfSignal("signal3()");
+ int slot1Index = r1->metaObject()->indexOfSlot("slot1()");
+ int slot2Index = r1->metaObject()->indexOfSlot("slot2()");
+ int slot3Index = r1->metaObject()->indexOfSlot("slot3()");
+
+ QVERIFY(slot1Index > 0);
+ QVERIFY(slot2Index > 0);
+ QVERIFY(slot3Index > 0);
+
+ QVERIFY( QMetaObject::connect( s, signal1Index, r1, slot1Index) );
+ QVERIFY( QMetaObject::connect( s, signal3Index, r2, slot3Index) );
+ QVERIFY( QMetaObject::connect( s, -1, r2, slot2Index) );
+
+ QCOMPARE( r1->count_slot1, 0 );
+ QCOMPARE( r1->count_slot2, 0 );
+ QCOMPARE( r1->count_slot3, 0 );
+ QCOMPARE( r2->count_slot1, 0 );
+ QCOMPARE( r2->count_slot2, 0 );
+ QCOMPARE( r2->count_slot3, 0 );
+
+ s->emitSignal1();
+
+ QCOMPARE( r1->count_slot1, 1 );
+ QCOMPARE( r1->count_slot2, 0 );
+ QCOMPARE( r1->count_slot3, 0 );
+ QCOMPARE( r2->count_slot1, 0 );
+ QCOMPARE( r2->count_slot2, 1 );
+ QCOMPARE( r2->count_slot3, 0 );
+
+ s->emitSignal2();
+ s->emitSignal3();
+ s->emitSignal4();
+
+ QCOMPARE( r1->count_slot1, 1 );
+ QCOMPARE( r1->count_slot2, 0 );
+ QCOMPARE( r1->count_slot3, 0 );
+ QCOMPARE( r2->count_slot1, 0 );
+ QCOMPARE( r2->count_slot2, 4 );
+ QCOMPARE( r2->count_slot3, 1 );
+
+ QVERIFY( QMetaObject::disconnect( s, signal1Index, r1, slot1Index) );
+ QVERIFY( QMetaObject::disconnect( s, signal3Index, r2, slot3Index) );
+ QVERIFY( QMetaObject::disconnect( s, -1, r2, slot2Index) );
+
+ s->emitSignal1();
+ s->emitSignal2();
+ s->emitSignal3();
+ s->emitSignal4();
+
+ QCOMPARE( r1->count_slot1, 1 );
+ QCOMPARE( r1->count_slot2, 0 );
+ QCOMPARE( r1->count_slot3, 0 );
+ QCOMPARE( r2->count_slot1, 0 );
+ QCOMPARE( r2->count_slot2, 4 );
+ QCOMPARE( r2->count_slot3, 1 );
+
+ //some "dynamic" signal
+ QVERIFY( QMetaObject::connect( s, s->metaObject()->methodOffset() + 20, r1, slot3Index) );
+ QVERIFY( QMetaObject::connect( s, s->metaObject()->methodOffset() + 35, r2, slot1Index) );
+ QVERIFY( QMetaObject::connect( s, -1, r1, slot2Index) );
+
+ r1->reset();
+ r2->reset();
+
+ void *args[] = { 0 , 0 };
+ QMetaObject::activate(s, s->metaObject()->methodOffset() + 20, args);
+ QMetaObject::activate(s, s->metaObject()->methodOffset() + 48, args);
+ QCOMPARE( r1->count_slot1, 0 );
+ QCOMPARE( r1->count_slot2, 2 );
+ QCOMPARE( r1->count_slot3, 1 );
+ QCOMPARE( r2->count_slot1, 0 );
+ QCOMPARE( r2->count_slot2, 0 );
+ QCOMPARE( r2->count_slot3, 0 );
+
+ QMetaObject::activate(s, s->metaObject()->methodOffset() + 35, args);
+ s->emitSignal1();
+ s->emitSignal2();
+
+ QCOMPARE( r1->count_slot1, 0 );
+ QCOMPARE( r1->count_slot2, 5 );
+ QCOMPARE( r1->count_slot3, 1 );
+ QCOMPARE( r2->count_slot1, 1 );
+ QCOMPARE( r2->count_slot2, 0 );
+ QCOMPARE( r2->count_slot3, 0 );
+
+ delete s;
+ r1->reset();
+ r2->reset();
+
+#define SIGNAL_INDEX(S) obj1.metaObject()->indexOfSignal(QMetaObject::normalizedSignature(#S))
+ OverloadObject obj1;
+ QObject obj2, obj3;
+
+ QMetaObject::connect(&obj1, SIGNAL_INDEX(sig(int)) , r1, slot1Index);
+ QMetaObject::connect(&obj1, SIGNAL_INDEX(sig(QObject *, QObject *, QObject *)) , r2, slot1Index);
+
+ QMetaObject::connect(&obj1, SIGNAL_INDEX(sig(QObject *, QObject *, QObject *, QObject *)) , r1, slot2Index);
+ QMetaObject::connect(&obj1, SIGNAL_INDEX(sig(QObject *)) , r2, slot2Index);
+ QMetaObject::connect(&obj1, SIGNAL_INDEX(sig(int, int)) , r1, slot3Index);
+
+ emit obj1.sig(0.5); //connected to nothing
+ emit obj1.sig(1, 'a'); //connected to nothing
+ QCOMPARE( r1->count_slot1, 0 );
+ QCOMPARE( r1->count_slot2, 0 );
+ QCOMPARE( r1->count_slot3, 0 );
+ QCOMPARE( r2->count_slot1, 0 );
+ QCOMPARE( r2->count_slot2, 0 );
+ QCOMPARE( r2->count_slot3, 0 );
+
+ emit obj1.sig(1); //this signal is connected
+ emit obj1.sig(&obj2);
+
+ QCOMPARE( r1->count_slot1, 1 );
+ QCOMPARE( r1->count_slot2, 0 );
+ QCOMPARE( r1->count_slot3, 1 );
+ QCOMPARE( r2->count_slot1, 0 );
+ QCOMPARE( r2->count_slot2, 1 );
+ QCOMPARE( r2->count_slot3, 0 );
+
+ emit obj1.sig(&obj2, &obj3); //this signal is connected
+
+ QCOMPARE( r1->count_slot1, 1 );
+ QCOMPARE( r1->count_slot2, 1 );
+ QCOMPARE( r1->count_slot3, 1 );
+ QCOMPARE( r2->count_slot1, 1 );
+ QCOMPARE( r2->count_slot2, 1 );
+ QCOMPARE( r2->count_slot3, 0 );
+
+ delete r1;
+ delete r2;
+
+}
+
+void tst_QObject::qMetaObjectDisconnectOne()
+{
+ SenderObject *s = new SenderObject;
+ ReceiverObject *r1 = new ReceiverObject;
+
+ int signal1Index = s->metaObject()->indexOfSignal("signal1()");
+ int signal3Index = s->metaObject()->indexOfSignal("signal3()");
+ int slot1Index = r1->metaObject()->indexOfSlot("slot1()");
+ int slot2Index = r1->metaObject()->indexOfSlot("slot2()");
+
+ QVERIFY(signal1Index > 0);
+ QVERIFY(signal3Index > 0);
+ QVERIFY(slot1Index > 0);
+ QVERIFY(slot2Index > 0);
+
+ QVERIFY( QMetaObject::connect(s, signal1Index, r1, slot1Index) );
+ QVERIFY( QMetaObject::connect(s, signal3Index, r1, slot2Index) );
+ QVERIFY( QMetaObject::connect(s, signal3Index, r1, slot2Index) );
+ QVERIFY( QMetaObject::connect(s, signal3Index, r1, slot2Index) );
+
+ r1->reset();
+ QCOMPARE( r1->count_slot1, 0 );
+ QCOMPARE( r1->count_slot2, 0 );
+
+ s->emitSignal1();
+ QCOMPARE( r1->count_slot1, 1 );
+ QCOMPARE( r1->count_slot2, 0 );
+
+ s->emitSignal3();
+ QCOMPARE( r1->count_slot1, 1 );
+ QCOMPARE( r1->count_slot2, 3 );
+
+ r1->reset();
+ QVERIFY( QMetaObject::disconnectOne(s, signal1Index, r1, slot1Index) );
+ QVERIFY( QMetaObject::disconnectOne(s, signal3Index, r1, slot2Index) );
+
+ s->emitSignal1();
+ QCOMPARE( r1->count_slot1, 0 );
+ QCOMPARE( r1->count_slot2, 0 );
+
+ s->emitSignal3();
+ QCOMPARE( r1->count_slot1, 0 );
+ QCOMPARE( r1->count_slot2, 2 );
+
+ r1->reset();
+ QVERIFY( false == QMetaObject::disconnectOne(s, signal1Index, r1, slot1Index) );
+ QVERIFY( QMetaObject::disconnectOne(s, signal3Index, r1, slot2Index) );
+
+ s->emitSignal1();
+ QCOMPARE( r1->count_slot1, 0 );
+ QCOMPARE( r1->count_slot2, 0 );
+
+ s->emitSignal3();
+ QCOMPARE( r1->count_slot1, 0 );
+ QCOMPARE( r1->count_slot2, 1 );
+
+ r1->reset();
+ QVERIFY( false == QMetaObject::disconnectOne(s, signal1Index, r1, slot1Index) );
+ QVERIFY( QMetaObject::disconnectOne(s, signal3Index, r1, slot2Index) );
+
+ s->emitSignal1();
+ QCOMPARE( r1->count_slot1, 0 );
+ QCOMPARE( r1->count_slot2, 0 );
+
+ s->emitSignal3();
+ QCOMPARE( r1->count_slot1, 0 );
+ QCOMPARE( r1->count_slot2, 0 );
+
+ delete s;
+ delete r1;
+}
+
+class ConfusingObject : public SenderObject
+{ Q_OBJECT
+public slots:
+ void signal1() { s++; }
+signals:
+ void aPublicSlot();
+public:
+ int s;
+ ConfusingObject() : s(0) {}
+ friend class tst_QObject;
+};
+
+void tst_QObject::sameName()
+{
+ ConfusingObject c1, c2;
+ QVERIFY(connect(&c1, SIGNAL(signal1()), &c1, SLOT(signal1())));
+ c1.emitSignal1();
+ QCOMPARE(c1.s, 1);
+
+ QVERIFY(connect(&c2, SIGNAL(signal1()), &c1, SIGNAL(signal1())));
+ c2.emitSignal1();
+ QCOMPARE(c1.s, 2);
+
+ QVERIFY(connect(&c2, SIGNAL(aPublicSlot()), &c1, SLOT(signal1())));
+ c2.aPublicSlot();
+ QCOMPARE(c2.aPublicSlotCalled, 0);
+ QCOMPARE(c1.aPublicSlotCalled, 0);
+ QCOMPARE(c1.s, 3);
+
+ QVERIFY(connect(&c2, SIGNAL(aPublicSlot()), &c1, SLOT(aPublicSlot())));
+ c2.aPublicSlot();
+ QCOMPARE(c2.aPublicSlotCalled, 0);
+ QCOMPARE(c1.aPublicSlotCalled, 1);
+ QCOMPARE(c1.s, 4);
+}
+
+void tst_QObject::connectByMetaMethods()
+{
+ SenderObject s;
+ ReceiverObject r;
+ const QMetaObject *smeta = s.metaObject();
+ const QMetaObject *rmeta = r.metaObject();
+ int sigIndx = smeta->indexOfSignal(QMetaObject::normalizedSignature("signal1()"));
+ int slotIndx = rmeta->indexOfSlot(QMetaObject::normalizedSignature("slot1()"));
+ QVERIFY( sigIndx != -1 );
+ QVERIFY( slotIndx != -1 );
+ QMetaMethod signal = smeta->method(sigIndx);
+ QMetaMethod slot = rmeta->method(slotIndx);
+
+ QVERIFY(connect(&s,signal, &r,slot));
+
+ QVERIFY(!r.called(1));
+ s.emitSignal1();
+ QVERIFY(r.called(1));
+}
+
+void tst_QObject::connectByMetaMethodSlotInsteadOfSignal()
+{
+ SenderObject s;
+ ReceiverObject r;
+ const QMetaObject *smeta = s.metaObject();
+ const QMetaObject *rmeta = r.metaObject();
+ int badIndx = smeta->indexOfSlot(QMetaObject::normalizedSignature("aPublicSlot()"));
+ int slotIndx = rmeta->indexOfSlot(QMetaObject::normalizedSignature("slot1()"));
+ QVERIFY( badIndx != -1 );
+ QVERIFY( slotIndx != -1 );
+ QMetaMethod badMethod = smeta->method(badIndx);
+ QMetaMethod slot = rmeta->method(slotIndx);
+
+ QTest::ignoreMessage(QtWarningMsg,"QObject::connect: Cannot connect SenderObject::aPublicSlot() to ReceiverObject::slot1()");
+ QVERIFY(!connect(&s,badMethod, &r,slot));
+}
+
+class Constructable: public QObject
+{
+ Q_OBJECT
+
+public:
+ Q_INVOKABLE Constructable(){}
+
+};
+
+void tst_QObject::connectConstructorByMetaMethod()
+{
+ Constructable sc;
+ Constructable rc;
+ SenderObject s;
+ ReceiverObject r;
+
+ const QMetaObject cmeta = Constructable::staticMetaObject;
+ const QMetaObject *smeta = s.metaObject();
+ const QMetaObject *rmeta = r.metaObject();
+ int constructorIndx = cmeta.indexOfConstructor(QMetaObject::normalizedSignature("Constructable()"));
+ int sigIndx = smeta->indexOfSignal(QMetaObject::normalizedSignature("signal1()"));
+ int slotIndx = rmeta->indexOfSlot(QMetaObject::normalizedSignature("slot1()"));
+ QVERIFY( constructorIndx != -1 );
+ QVERIFY( sigIndx != -1 );
+ QVERIFY( slotIndx != -1 );
+
+ QMetaMethod constructor = cmeta.constructor(constructorIndx);
+ QMetaMethod signal = smeta->method(sigIndx);
+ QMetaMethod slot = rmeta->method(slotIndx);
+
+ QTest::ignoreMessage(QtWarningMsg,"QObject::connect: Cannot connect Constructable::Constructable() to ReceiverObject::slot1()");
+ QVERIFY(!connect(&sc,constructor, &r,slot));
+ QTest::ignoreMessage(QtWarningMsg,"QObject::connect: Cannot connect SenderObject::signal1() to Constructable::Constructable()");
+ QVERIFY(!connect(&s,signal, &rc,constructor));
+ QTest::ignoreMessage(QtWarningMsg,"QObject::connect: Cannot connect Constructable::Constructable() to Constructable::Constructable()");
+ QVERIFY(!connect(&sc,constructor, &rc,constructor));
+}
+
+void tst_QObject::disconnectByMetaMethod()
+{
+ SenderObject *s = new SenderObject;
+ ReceiverObject *r1 = new ReceiverObject;
+ ReceiverObject *r2 = new ReceiverObject;
+
+ QMetaMethod signal1 = s->metaObject()->method(
+ s->metaObject()->indexOfMethod("signal1()"));
+ QMetaMethod signal2 = s->metaObject()->method(
+ s->metaObject()->indexOfMethod("signal2()"));
+ QMetaMethod signal3 = s->metaObject()->method(
+ s->metaObject()->indexOfMethod("signal3()"));
+ QMetaMethod signal4 = s->metaObject()->method(
+ s->metaObject()->indexOfMethod("signal4()"));
+
+ QMetaMethod slot1 = r1->metaObject()->method(
+ r1->metaObject()->indexOfMethod("slot1()"));
+ QMetaMethod slot2 = r1->metaObject()->method(
+ r1->metaObject()->indexOfMethod("slot2()"));
+ QMetaMethod slot3 = r1->metaObject()->method(
+ r1->metaObject()->indexOfMethod("slot3()"));
+ QMetaMethod slot4 = r1->metaObject()->method(
+ r1->metaObject()->indexOfMethod("slot4()"));
+
+ connect(s, signal1, r1, slot1);
+
+ s->emitSignal1();
+
+ QVERIFY(r1->called(1));
+ r1->reset();
+
+ // usual disconnect with all parameters given
+ bool ret = QObject::disconnect(s, signal1, r1, slot1);
+
+ s->emitSignal1();
+
+ QVERIFY(!r1->called(1));
+ r1->reset();
+
+ QVERIFY(ret);
+ ret = QObject::disconnect(s, signal1, r1, slot1);
+ QVERIFY(!ret);
+
+ r1->reset();
+
+ connect( s, signal1, r1, slot1 );
+ connect( s, signal1, r1, slot2 );
+ connect( s, signal1, r1, slot3 );
+ connect( s, signal2, r1, slot4 );
+
+ // disconnect s's signal1() from all slots of r1
+ QObject::disconnect(s, signal1, r1, QMetaMethod());
+
+ s->emitSignal1();
+ s->emitSignal2();
+
+ QVERIFY(!r1->called(1));
+ QVERIFY(!r1->called(2));
+ QVERIFY(!r1->called(3));
+ QVERIFY(r1->called(4));
+ r1->reset();
+ // make sure all is disconnected again
+ QObject::disconnect(s, 0, r1, 0);
+
+ connect(s, signal1, r1, slot1);
+ connect(s, signal1, r2, slot1);
+ connect(s, signal2, r1, slot2);
+ connect(s, signal2, r2, slot2);
+ connect(s, signal3, r1, slot3);
+ connect(s, signal3, r2, slot3);
+
+ // disconnect signal1() from all receivers
+ QObject::disconnect(s, signal1, 0, QMetaMethod());
+ s->emitSignal1();
+ s->emitSignal2();
+ s->emitSignal3();
+
+ QVERIFY(!r1->called(1));
+ QVERIFY(!r2->called(1));
+ QVERIFY(r1->called(2));
+ QVERIFY(r2->called(2));
+ QVERIFY(r1->called(2));
+ QVERIFY(r2->called(2));
+
+ r1->reset();
+ r2->reset();
+
+ // disconnect all signals of s from all receivers
+ QObject::disconnect( s, 0, 0, 0 );
+
+ connect( s, signal1, r1, slot1 );
+ connect( s, signal1, r2, slot1 );
+
+ // disconnect all signals from slot1 of r1
+ QObject::disconnect(s, QMetaMethod(), r1, slot1);
+
+ s->emitSignal1();
+
+ QVERIFY(!r1->called(1));
+ QVERIFY(r2->called(1));
+
+ delete r2;
+ delete r1;
+ delete s;
+}
+
+void tst_QObject::disconnectNotSignalMetaMethod()
+{
+ SenderObject s;
+ ReceiverObject r;
+
+ connect(&s, SIGNAL(signal1()), &r, SLOT(slot1()));
+
+ QMetaMethod slot = s.metaObject()->method(
+ s.metaObject()->indexOfMethod("aPublicSlot()"));
+
+ QTest::ignoreMessage(QtWarningMsg,"Object::disconnect: Attempt to unbind non-signal SenderObject::aPublicSlot()");
+ QVERIFY(!QObject::disconnect(&s, slot, &r, QMetaMethod()));
+}
+
+class ThreadAffinityThread : public QThread
+{
+public:
+ SenderObject *sender;
+
+ ThreadAffinityThread(SenderObject *sender)
+ : sender(sender)
+ { }
+ void run()
+ {
+ sender->emitSignal1();
+ }
+};
+
+void tst_QObject::autoConnectionBehavior()
+{
+ SenderObject *sender = new SenderObject;
+ ReceiverObject *receiver = new ReceiverObject;
+ connect(sender, SIGNAL(signal1()), receiver, SLOT(slot1()));
+
+ // at emit, currentThread == sender->thread(), currentThread == receiver->thread(), sender->thread() == receiver->thread()
+ QVERIFY(!receiver->called(1));
+ sender->emitSignal1();
+ QVERIFY(receiver->called(1));
+ receiver->reset();
+
+ // at emit, currentThread != sender->thread(), currentThread != receiver->thread(), sender->thread() == receiver->thread()
+ ThreadAffinityThread emitThread1(sender);
+ QVERIFY(!receiver->called(1));
+ emitThread1.start();
+ QVERIFY(emitThread1.wait(30000));
+ QVERIFY(!receiver->called(1));
+ QCoreApplication::sendPostedEvents(receiver, QEvent::MetaCall);
+ QVERIFY(receiver->called(1));
+ receiver->reset();
+
+ // at emit, currentThread == sender->thread(), currentThread != receiver->thread(), sender->thread() != receiver->thread()
+ sender->moveToThread(&emitThread1);
+ QVERIFY(!receiver->called(1));
+ emitThread1.start();
+ QVERIFY(emitThread1.wait(30000));
+ QVERIFY(!receiver->called(1));
+ QCoreApplication::sendPostedEvents(receiver, QEvent::MetaCall);
+ QVERIFY(receiver->called(1));
+ receiver->reset();
+
+ // at emit, currentThread != sender->thread(), currentThread == receiver->thread(), sender->thread() != receiver->thread()
+ QVERIFY(!receiver->called(1));
+ sender->emitSignal1();
+ QVERIFY(receiver->called(1));
+ receiver->reset();
+
+ // at emit, currentThread != sender->thread(), currentThread != receiver->thread(), sender->thread() != receiver->thread()
+ ThreadAffinityThread emitThread2(sender);
+ QThread receiverThread;
+ QTimer *timer = new QTimer;
+ timer->setSingleShot(true);
+ timer->setInterval(100);
+ connect(&receiverThread, SIGNAL(started()), timer, SLOT(start()));
+ connect(timer, SIGNAL(timeout()), &receiverThread, SLOT(quit()), Qt::DirectConnection);
+ connect(&receiverThread, SIGNAL(finished()), timer, SLOT(deleteLater()));
+ timer->moveToThread(&receiverThread);
+
+ receiver->moveToThread(&receiverThread);
+ QVERIFY(!receiver->called(1));
+ emitThread2.start();
+ QVERIFY(emitThread2.wait(30000));
+ QVERIFY(!receiver->called(1));
+ receiverThread.start();
+ QVERIFY(receiverThread.wait(30000));
+ QVERIFY(receiver->called(1));
+ receiver->reset();
+
+ delete sender;
+ delete receiver;
+}
+
+class BaseDestroyed : public QObject
+{ Q_OBJECT
+ QList<QString> fooList;
+ bool destroyed;
+public:
+ BaseDestroyed() : destroyed(false)
+ { fooList << "a" << "b"; }
+ ~BaseDestroyed()
+ {
+ QVERIFY(!destroyed);
+ destroyed = true;
+ }
+
+public slots:
+ void slotUseList()
+ {
+ QVERIFY(!destroyed);
+ fooList << "c" << "d";
+ }
+};
+
+void tst_QObject::baseDestroyed()
+{
+ BaseDestroyed d;
+ connect(&d, SIGNAL(destroyed()), &d, SLOT(slotUseList()));
+ //When d goes out of scope, slotUseList should not be called as the BaseDestroyed has
+ // already been destroyed while ~QObject emit destroyed
+}
+
+QTEST_MAIN(tst_QObject)
+#include "tst_qobject.moc"
diff --git a/tests/auto/qobject/tst_qobject.pro b/tests/auto/qobject/tst_qobject.pro
new file mode 100644
index 0000000000..5745e671c2
--- /dev/null
+++ b/tests/auto/qobject/tst_qobject.pro
@@ -0,0 +1,21 @@
+load(qttest_p4)
+SOURCES += tst_qobject.cpp
+
+# this is here for a reason, moc_oldnormalizedobject.cpp is not auto-generated, it was generated by
+# moc from Qt 4.6, and should *not* be generated by the current moc
+SOURCES += moc_oldnormalizeobject.cpp
+
+QT = core \
+ network \
+ gui
+contains(QT_CONFIG, qt3support):DEFINES += QT_HAS_QT3SUPPORT
+wince*: {
+ addFiles.files = signalbug.exe
+ addFiles.path = .
+ DEPLOYMENT += addFiles
+}
+symbian: {
+ addFiles.files = signalbug.exe
+ addFiles.path = \\sys\\bin
+ DEPLOYMENT += addFiles
+}