--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/tests/auto/qobject/tst_qobject.cpp Mon Jan 11 14:00:40 2010 +0000
@@ -0,0 +1,3020 @@
+/****************************************************************************
+**
+** Copyright (C) 2009 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"
+
+#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();
+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() : 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(){}
+
+public:
+ Q_INVOKABLE void invoke1(){}
+ Q_SCRIPTABLE void sinvoke1(){}
+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; }
+ void on_Sender_signalWithParams(int i, QString string) { ++called_slot3; }
+ void on_Sender_signalManyParams() { ++called_slot4; }
+ void on_Sender_signalManyParams(int i1, int i2, int i3, QString string, bool onoff) { ++called_slot5; }
+ void on_Sender_signalManyParams(int i1, int i2, int i3, QString string, bool onoff, bool dummy) { ++called_slot6; }
+ void on_Sender_signalManyParams2(int i1, int i2, int i3, QString string, bool onoff) { ++called_slot7; }
+ 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);
+
+#ifndef QT_NO_MEMBER_TEMPLATES
+ tl = o.findChildren<QTimer *>("t1");
+ QCOMPARE(tl.size(), 1);
+ QCOMPARE(tl.at(0), &t1);
+#endif
+}
+
+
+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);
+
+ 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);
+}
+
+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)
+
+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; }
+
+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;
+};
+
+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);
+}
+
+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;
+ SuperObject()
+ {
+ theSender = 0;
+ }
+
+ friend class tst_QObject;
+
+ using QObject::sender;
+
+public slots:
+ void rememberSender()
+ {
+ theSender = sender();
+ }
+
+ void deleteAndRememberSender()
+ {
+ delete theSender;
+ theSender = sender();
+ }
+signals:
+ void theSignal();
+
+};
+
+void tst_QObject::sender()
+{
+ {
+ SuperObject sender;
+ SuperObject receiver;
+ connect(&sender, SIGNAL(theSignal()),
+ &receiver, SLOT(rememberSender()));
+ QCOMPARE(receiver.sender(), (QObject *)0);
+ emit sender.theSignal();
+ QCOMPARE(receiver.theSender, (QObject *)&sender);
+ QCOMPARE(receiver.sender(), (QObject *)0);
+ }
+
+ {
+ 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);
+ receiver->theSender = 0;
+ thread.start();
+ emit sender->theSignal();
+ QCOMPARE(receiver->theSender, (QObject *) sender);
+ QCOMPARE(receiver->sender(), (QObject *)0);
+
+ 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 { };
+
+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);
+
+public slots:
+ void uintPointerSlot(uint *) { }
+ void ulongPointerSlot(ulong *) { }
+ void constUintPointerSlot(const uint *) { }
+ void constUlongPointerSlot(const ulong *) { }
+
+ void structSlot(Struct s) { }
+ void classSlot(Class c) { }
+ void enumSlot(Enum e) { }
+
+ void structPointerSlot(Struct *s) { }
+ void classPointerSlot(Class *c) { }
+ void enumPointerSlot(Enum *e) { }
+
+ void constStructPointerSlot(const Struct *s) { }
+ void constClassPointerSlot(const Class *c) { }
+ void constEnumPointerSlot(const Enum *e) { }
+
+ void constStructPointerConstPointerSlot(const Struct * const *s) { }
+ void constClassPointerConstPointerSlot(const Class * const *c) { }
+ void constEnumPointerConstPointerSlot(const Enum * const *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 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))));
+
+
+}
+
+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 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));
+ }
+}
+
+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, &obj2);
+ QCOMPARE(obj1.o2_obj, &obj3);
+ QCOMPARE(obj1.o3_obj, (QObject *)0); //default arg of the signal
+ QCOMPARE(obj1.o4_obj, qApp); //default arg of the slot
+
+ QCOMPARE(obj2.s_num, 111);
+ QCOMPARE(obj2.o1_obj, &obj2);
+ QCOMPARE(obj2.o2_obj, &obj3);
+ QCOMPARE(obj2.o3_obj, (QObject *)0); //default arg of the signal
+ QCOMPARE(obj2.o4_obj, qApp); //default arg of the slot
+}
+
+QTEST_MAIN(tst_QObject)
+#include "tst_qobject.moc"