/**************************************************************************** ** ** 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$ ** GNU Lesser General Public License Usage ** 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. ** ** GNU General Public License Usage ** Alternatively, this file may be used under the terms of the GNU General ** Public License version 3.0 as published by the Free Software Foundation ** and appearing in the file LICENSE.GPL included in the packaging of this ** file. Please review the following information to ensure the GNU General ** Public License version 3.0 requirements will be met: ** http://www.gnu.org/copyleft/gpl.html. ** ** Other Usage ** Alternatively, this file may be used in accordance with the terms and ** conditions contained in a signed written agreement between you and Nokia. ** ** ** ** ** ** $QT_END_LICENSE$ ** ****************************************************************************/ #include #include #include #include #include #include #include #include #include #include #include #include #include #include "qobject.h" #ifdef QT_BUILD_INTERNAL #include #endif #include //TESTED_CLASS= //TESTED_FILES= class tst_QObject : public QObject { Q_OBJECT 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(); #ifndef QT_NO_PROCESS void recursiveSignalEmission(); #endif 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(); void pointerConnect(); void emitInDefinedOrderPointer(); void customTypesPointer(); void connectCxx0x(); void connectToStaticCxx0x(); void connectCxx0xTypeMatching(); void connectConvert(); void connectWithReference(); void connectManyArguments(); }; 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_slot10 = 0; called_slot9 = 0; 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; int called_slot9; int called_slot10; 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; case 9: return called_slot9; case 10: return called_slot10; 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() { ++called_slot9; } void on() { ++called_slot10; } 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); QCOMPARE(receiver.called(9), false); QCOMPARE(receiver.called(10), 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); QCOMPARE(receiver.called(9), false); QCOMPARE(receiver.called(10), 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); QCOMPARE(receiver.called(9), false); QCOMPARE(receiver.called(10), 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); QCOMPARE(receiver.called(9), false); QCOMPARE(receiver.called(10), 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); QCOMPARE(receiver.called(9), false); QCOMPARE(receiver.called(10), 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); QCOMPARE(receiver.called(9), false); QCOMPARE(receiver.called(10), false); receiver.reset(); } void tst_QObject::qobject_castTemplate() { QObject *o = 0; QVERIFY( !::qobject_cast(o) ); o = new SenderObject; QVERIFY( ::qobject_cast(o) ); QVERIFY( ::qobject_cast(o) ); QVERIFY( !::qobject_cast(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(&o, "o1"); QCOMPARE(op, &o1); op = qFindChild(&o, "o2"); QCOMPARE(op, &o2); op = qFindChild(&o, "o11"); QCOMPARE(op, &o11); op = qFindChild(&o, "o12"); QCOMPARE(op, &o12); op = qFindChild(&o, "o111"); QCOMPARE(op, &o111); op = qFindChild(&o, "t1"); QCOMPARE(op, static_cast(&t1)); op = qFindChild(&o, "t121"); QCOMPARE(op, static_cast(&t121)); op = qFindChild(&o, "t1"); QCOMPARE(op, static_cast(&t1)); op = qFindChild(&o, "t121"); QCOMPARE(op, static_cast(&t121)); op = qFindChild(&o, "o12"); QCOMPARE(op, static_cast(0)); op = qFindChild(&o, "o"); QCOMPARE(op, static_cast(0)); op = qFindChild(&o, "harry"); QCOMPARE(op, static_cast(0)); op = qFindChild(&o, "o1"); QCOMPARE(op, &o1); QList l; QList tl; l = qFindChildren(&o, "o1"); QCOMPARE(l.size(), 1); QCOMPARE(l.at(0), &o1); l = qFindChildren(&o, "o2"); QCOMPARE(l.size(), 1); QCOMPARE(l.at(0), &o2); l = qFindChildren(&o, "o11"); QCOMPARE(l.size(), 1); QCOMPARE(l.at(0), &o11); l = qFindChildren(&o, "o12"); QCOMPARE(l.size(), 1); QCOMPARE(l.at(0), &o12); l = qFindChildren(&o, "o111"); QCOMPARE(l.size(), 1); QCOMPARE(l.at(0), &o111); l = qFindChildren(&o, "t1"); QCOMPARE(l.size(), 1); QCOMPARE(l.at(0), static_cast(&t1)); l = qFindChildren(&o, "t121"); QCOMPARE(l.size(), 1); QCOMPARE(l.at(0), static_cast(&t121)); tl = qFindChildren(&o, "t1"); QCOMPARE(tl.size(), 1); QCOMPARE(tl.at(0), &t1); tl = qFindChildren(&o, "t121"); QCOMPARE(tl.size(), 1); QCOMPARE(tl.at(0), &t121); l = qFindChildren(&o, "o"); QCOMPARE(l.size(), 0); l = qFindChildren(&o, "harry"); QCOMPARE(l.size(), 0); tl = qFindChildren(&o, "o12"); QCOMPARE(tl.size(), 0); l = qFindChildren(&o, "o1"); QCOMPARE(l.size(), 1); QCOMPARE(l.at(0), &o1); l = qFindChildren(&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(&o, QRegExp("t.*")); QCOMPARE(l.size(), 2); QVERIFY(l.contains(&t1)); QVERIFY(l.contains(&t121)); tl = qFindChildren(&o, QRegExp(".*")); QCOMPARE(tl.size(), 3); QVERIFY(tl.contains(&t1)); QVERIFY(tl.contains(&t121)); tl = qFindChildren(&o, QRegExp("o.*")); QCOMPARE(tl.size(), 0); l = qFindChildren(&o, QRegExp("harry")); QCOMPARE(l.size(), 0); // empty and null string check op = qFindChild(&o); QCOMPARE(op, &o1); op = qFindChild(&o, ""); QCOMPARE(op, &unnamed); op = qFindChild(&o, "unnamed"); QCOMPARE(op, static_cast(0)); l = qFindChildren(&o); QCOMPARE(l.size(), 9); l = qFindChildren(&o, ""); QCOMPARE(l.size(), 2); l = qFindChildren(&o, "unnamed"); QCOMPARE(l.size(), 0); tl = o.findChildren("t1"); QCOMPARE(tl.size(), 1); QCOMPARE(tl.at(0), &t1); // Find direct child/children op = o.findChild("o1", Qt::FindDirectChildrenOnly); QCOMPARE(op, &o1); op = o.findChild("o2", Qt::FindDirectChildrenOnly); QCOMPARE(op, &o2); op = o.findChild("o11", Qt::FindDirectChildrenOnly); QCOMPARE(op, static_cast(0)); op = o.findChild("o12", Qt::FindDirectChildrenOnly); QCOMPARE(op, static_cast(0)); op = o.findChild("o111", Qt::FindDirectChildrenOnly); QCOMPARE(op, static_cast(0)); op = o.findChild("t1", Qt::FindDirectChildrenOnly); QCOMPARE(op, static_cast(&t1)); op = o.findChild("t121", Qt::FindDirectChildrenOnly); QCOMPARE(op, static_cast(0)); op = o.findChild("t1", Qt::FindDirectChildrenOnly); QCOMPARE(op, static_cast(&t1)); op = o.findChild("t121", Qt::FindDirectChildrenOnly); QCOMPARE(op, static_cast(0)); op = o.findChild("o12", Qt::FindDirectChildrenOnly); QCOMPARE(op, static_cast(0)); op = o.findChild("o", Qt::FindDirectChildrenOnly); QCOMPARE(op, static_cast(0)); op = o.findChild("harry", Qt::FindDirectChildrenOnly); QCOMPARE(op, static_cast(0)); op = o.findChild("o1", Qt::FindDirectChildrenOnly); QCOMPARE(op, &o1); l = o.findChildren("o1", Qt::FindDirectChildrenOnly); QCOMPARE(l.size(), 1); QCOMPARE(l.at(0), &o1); l = o.findChildren("o2", Qt::FindDirectChildrenOnly); QCOMPARE(l.size(), 1); QCOMPARE(l.at(0), &o2); l = o.findChildren("o11", Qt::FindDirectChildrenOnly); QCOMPARE(l.size(), 0); l = o.findChildren("o12", Qt::FindDirectChildrenOnly); QCOMPARE(l.size(), 0); l = o.findChildren("o111", Qt::FindDirectChildrenOnly); QCOMPARE(l.size(), 0); l = o.findChildren("t1", Qt::FindDirectChildrenOnly); QCOMPARE(l.size(), 1); QCOMPARE(l.at(0), static_cast(&t1)); l = o.findChildren("t121", Qt::FindDirectChildrenOnly); QCOMPARE(l.size(), 0); tl = o.findChildren("t1", Qt::FindDirectChildrenOnly); QCOMPARE(tl.size(), 1); QCOMPARE(tl.at(0), &t1); tl = o.findChildren("t121", Qt::FindDirectChildrenOnly); QCOMPARE(tl.size(), 0); l = o.findChildren("o", Qt::FindDirectChildrenOnly); QCOMPARE(l.size(), 0); l = o.findChildren("harry", Qt::FindDirectChildrenOnly); QCOMPARE(l.size(), 0); tl = o.findChildren("o12", Qt::FindDirectChildrenOnly); QCOMPARE(tl.size(), 0); l = o.findChildren("o1", Qt::FindDirectChildrenOnly); QCOMPARE(l.size(), 1); QCOMPARE(l.at(0), &o1); l = o.findChildren(QRegExp("o.*"), Qt::FindDirectChildrenOnly); QCOMPARE(l.size(), 2); QVERIFY(l.contains(&o1)); QVERIFY(l.contains(&o2)); l = o.findChildren(QRegExp("t.*"), Qt::FindDirectChildrenOnly); QCOMPARE(l.size(), 1); QVERIFY(l.contains(&t1)); tl = o.findChildren(QRegExp(".*"), Qt::FindDirectChildrenOnly); QCOMPARE(tl.size(), 2); QVERIFY(tl.contains(&t1)); tl = o.findChildren(QRegExp("o.*"), Qt::FindDirectChildrenOnly); QCOMPARE(tl.size(), 0); l = o.findChildren(QRegExp("harry"), Qt::FindDirectChildrenOnly); QCOMPARE(l.size(), 0); // empty and null string check op = o.findChild(QString(), Qt::FindDirectChildrenOnly); QCOMPARE(op, &o1); op = o.findChild("", Qt::FindDirectChildrenOnly); QCOMPARE(op, &unnamed); op = o.findChild("unnamed", Qt::FindDirectChildrenOnly); QCOMPARE(op, static_cast(0)); l = o.findChildren(QString(), Qt::FindDirectChildrenOnly); QCOMPARE(l.size(), 5); l = o.findChildren("", Qt::FindDirectChildrenOnly); QCOMPARE(l.size(), 2); l = o.findChildren("unnamed", Qt::FindDirectChildrenOnly); QCOMPARE(l.size(), 0); tl = o.findChildren("t1", Qt::FindDirectChildrenOnly); 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("a_signal"); QTest::addColumn("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 psender = sender2; QPointer pseq3 = seq3; SequenceObject::sequence = sequence = 0; sender2->emitSignal1(); QCOMPARE(static_cast(psender), static_cast(0)); QCOMPARE(static_cast(pseq3), static_cast(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 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 CheckInstanceCount { const int saved; CheckInstanceCount() : saved(instanceCount) {} ~CheckInstanceCount() { QCOMPARE(saved, instanceCount); } }; 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*) 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"); 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"), 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"); qRegisterMetaTypeStreamOperators("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) 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 *) { if (customEventThread) qFatal("%s: customEventThread should be null", Q_FUNC_INFO); customEventThread = QThread::currentThread(); emit theSignal(); } void timerEvent(QTimerEvent *) { if (timerEventThread) qFatal("%s: timerEventThread should be null", Q_FUNC_INFO); timerEventThread = QThread::currentThread(); emit theSignal(); } public slots: void theSlot() { if (slotThread) qFatal("%s: slotThread should be null", Q_FUNC_INFO); 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 opointer = object; QPointer 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); child->startTimer(90); object->startTimer(100); 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(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(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"); 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(var)); QCOMPARE(qVariantValue(var), PropertyObject::High); object.setPriority(PropertyObject::Low); QCOMPARE(qVariantValue(object.property("priority")), PropertyObject::Low); QVERIFY(object.setProperty("priority", PropertyObject::VeryHigh)); QCOMPARE(qVariantValue(object.property("priority")), PropertyObject::VeryHigh); QVERIFY(object.setProperty("priority", "High")); QCOMPARE(qVariantValue(object.property("priority")), PropertyObject::High); QVERIFY(!object.setProperty("priority", QVariant())); var = object.property("priority"); QCOMPARE(qVariantValue(var), PropertyObject::High); object.setPriority(PropertyObject::Low); QCOMPARE(qVariantValue(object.property("priority")), PropertyObject::Low); object.setProperty("priority", var); QCOMPARE(qVariantValue(object.property("priority")), PropertyObject::High); qRegisterMetaType("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(&obj); QVERIFY(bar); QCOMPARE(bar->rtti(), 42); QCOMPARE(static_cast(&obj), bar); BlehObject bleh; bar = qobject_cast(&bleh); QVERIFY(!bar); Foo::Bleh *b = qobject_cast(&bleh); QCOMPARE(b->rtti(), 43); QCOMPARE(static_cast(&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; iid = user_data_ids[i]; my_test_object.setUserData(data->id, data); } // verify that all ids and positions are matching for (int i=0; i(my_test_object.userData(id)); QVERIFY(data != 0); QVERIFY(data->id == id); } } class DestroyedListener : public QObject { Q_OBJECT public: inline DestroyedListener() : pointerWasZero(false) {} QPointer 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 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 &ref); void constTypeRefSignal(const Template &ref); void typeConstRefSignal(Template const &ref); void typePointerConstRefSignal(Class * const &); void constTemplateSignal1( Template ); 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 &) {} void constTypeRefSlot(const Template &) {} void typeConstRefSlot(Template const &) {} void typePointerConstRefSlot(Class * const &) {} void constTemplateSlot1(Template const) {} void constTemplateSlot2(const Template ) {} 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 const &', // 'const T &', and 'T' QVERIFY(object.connect(&object, SIGNAL(typeRefSignal(Template &)), SLOT(typeRefSlot(Template &)))); QVERIFY(object.connect(&object, SIGNAL(constTypeRefSignal(const Template &)), SLOT(constTypeRefSlot(const Template &)))); QVERIFY(object.connect(&object, SIGNAL(constTypeRefSignal(const Template &)), SLOT(constTypeRefSlot(const Template &)))); QVERIFY(object.connect(&object, SIGNAL(constTypeRefSignal(const Template &)), SLOT(constTypeRefSlot(Template const &)))); QVERIFY(object.connect(&object, SIGNAL(constTypeRefSignal(Template const &)), SLOT(constTypeRefSlot(Template const &)))); QVERIFY(object.connect(&object, SIGNAL(constTypeRefSignal(Template const &)), SLOT(constTypeRefSlot(Template const &)))); QVERIFY(object.connect(&object, SIGNAL(constTypeRefSignal(const Template &)), SLOT(typeConstRefSlot(const Template &)))); QVERIFY(object.connect(&object, SIGNAL(constTypeRefSignal(const Template &)), SLOT(typeConstRefSlot(const Template &)))); QVERIFY(object.connect(&object, SIGNAL(constTypeRefSignal(const Template &)), SLOT(typeConstRefSlot(Template const &)))); QVERIFY(object.connect(&object, SIGNAL(constTypeRefSignal(Template const &)), SLOT(typeConstRefSlot(Template const &)))); QVERIFY(object.connect(&object, SIGNAL(constTypeRefSignal(Template const &)), SLOT(typeConstRefSlot(Template const &)))); QVERIFY(object.connect(&object, SIGNAL(typeConstRefSignal(const Template &)), SLOT(constTypeRefSlot(const Template &)))); QVERIFY(object.connect(&object, SIGNAL(typeConstRefSignal(const Template &)), SLOT(constTypeRefSlot(const Template &)))); QVERIFY(object.connect(&object, SIGNAL(typeConstRefSignal(const Template &)), SLOT(constTypeRefSlot(Template const &)))); QVERIFY(object.connect(&object, SIGNAL(typeConstRefSignal(Template const &)), SLOT(constTypeRefSlot(Template const &)))); QVERIFY(object.connect(&object, SIGNAL(typeConstRefSignal(Template const &)), SLOT(constTypeRefSlot(Template const &)))); QVERIFY(object.connect(&object, SIGNAL(typeConstRefSignal(const Template &)), SLOT(typeConstRefSlot(const Template &)))); QVERIFY(object.connect(&object, SIGNAL(typeConstRefSignal(const Template &)), SLOT(typeConstRefSlot(const Template &)))); QVERIFY(object.connect(&object, SIGNAL(typeConstRefSignal(const Template &)), SLOT(typeConstRefSlot(Template const &)))); QVERIFY(object.connect(&object, SIGNAL(typeConstRefSignal(Template const &)), SLOT(typeConstRefSlot(Template const &)))); QVERIFY(object.connect(&object, SIGNAL(typeConstRefSignal(Template const &)), SLOT(typeConstRefSlot(Template 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 &)), SLOT(constTypeRefSlot(const Template &)))); QVERIFY(oldobject.connect(&oldobject, SIGNAL(constTypeRefSignal(const Template &)), SLOT(constTypeRefSlot(const Template &)))); // this fails in older versions, but passes now due to proper normalizing QVERIFY(oldobject.connect(&oldobject, SIGNAL(constTypeRefSignal(const Template &)), SLOT(constTypeRefSlot(Template const &)))); // this fails in older versions, but passes now due to proper normalizing QVERIFY(oldobject.connect(&oldobject, SIGNAL(constTypeRefSignal(Template const &)), SLOT(constTypeRefSlot(Template const &)))); // this fails in older versions, but passes now due to proper normalizing QVERIFY(oldobject.connect(&oldobject, SIGNAL(constTypeRefSignal(Template const &)), SLOT(constTypeRefSlot(Template const &)))); // these fail in older Qt versions, but pass now due to proper normalizing QVERIFY(oldobject.connect(&oldobject, SIGNAL(constTypeRefSignal(const Template &)), SLOT(typeConstRefSlot(const Template &)))); QVERIFY(oldobject.connect(&oldobject, SIGNAL(constTypeRefSignal(const Template &)), SLOT(typeConstRefSlot(const Template &)))); QVERIFY(oldobject.connect(&oldobject, SIGNAL(constTypeRefSignal(const Template &)), SLOT(typeConstRefSlot(Template const &)))); QVERIFY(oldobject.connect(&oldobject, SIGNAL(constTypeRefSignal(Template const &)), SLOT(typeConstRefSlot(Template const &)))); QVERIFY(oldobject.connect(&oldobject, SIGNAL(constTypeRefSignal(Template const &)), SLOT(typeConstRefSlot(Template const &)))); // these also fail in older Qt versions, but pass now due to proper normalizing QVERIFY(oldobject.connect(&oldobject, SIGNAL(typeConstRefSignal(const Template &)), SLOT(constTypeRefSlot(const Template &)))); QVERIFY(oldobject.connect(&oldobject, SIGNAL(typeConstRefSignal(const Template &)), SLOT(constTypeRefSlot(const Template &)))); QVERIFY(oldobject.connect(&oldobject, SIGNAL(typeConstRefSignal(const Template &)), SLOT(constTypeRefSlot(Template const &)))); QVERIFY(oldobject.connect(&oldobject, SIGNAL(typeConstRefSignal(Template const &)), SLOT(constTypeRefSlot(Template const &)))); QVERIFY(oldobject.connect(&oldobject, SIGNAL(typeConstRefSignal(Template const &)), SLOT(constTypeRefSlot(Template const &)))); // this fails in older versions, but passes now due to proper normalizing QVERIFY(oldobject.connect(&oldobject, SIGNAL(typeConstRefSignal(const Template &)), SLOT(typeConstRefSlot(const Template &)))); // this fails in older versions, but passes now due to proper normalizing QVERIFY(oldobject.connect(&oldobject, SIGNAL(typeConstRefSignal(const Template &)), SLOT(typeConstRefSlot(const Template &)))); // this fails in older versions, but passes now due to proper normalizing QVERIFY(oldobject.connect(&oldobject, SIGNAL(typeConstRefSignal(const Template &)), SLOT(typeConstRefSlot(Template const &)))); QVERIFY(oldobject.connect(&oldobject, SIGNAL(typeConstRefSignal(Template const &)), SLOT(typeConstRefSlot(Template const &)))); QVERIFY(oldobject.connect(&oldobject, SIGNAL(typeConstRefSignal(Template const &)), SLOT(typeConstRefSlot(Template 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 )), &object , SLOT(constTemplateSlot1 (Template ) ) )); QVERIFY( connect(&object, SIGNAL(constTemplateSignal1(Template )), &object , SLOT(constTemplateSlot2 (Template ) ) )); QVERIFY( connect(&object, SIGNAL(constTemplateSignal2(Template )), &object , SLOT(constTemplateSlot3(Template ) ) )); //type does not match QTest::ignoreMessage(QtWarningMsg, "QObject::connect: Incompatible sender/receiver arguments\n" " NormalizeObject::constTemplateSignal1(Template) --> NormalizeObject::constTemplateSlot3(Template)"); QVERIFY(!connect(&object, SIGNAL(constTemplateSignal1(Template )), &object , SLOT(constTemplateSlot3(Template ) ) )); } class SiblingDeleter : public QObject { public: inline SiblingDeleter(QObject *sibling, QObject *parent) : QObject(parent), sibling(sibling) {} inline virtual ~SiblingDeleter() { delete sibling; } private: QPointer sibling; }; void tst_QObject::childDeletesItsSibling() { QObject *commonParent = new QObject(0); QPointer child = new QObject(0); QPointer 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(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()); QVERIFY(qVariantValue(v) == 128.0); QVERIFY(prop.write(&obj, qVariantFromValue(double(127)))); v = prop.read(&obj); QCOMPARE(v.userType(), qMetaTypeId()); QVERIFY(qVariantValue(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(e)->propertyName()); } return QObject::event(e); } QList 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()); } #ifndef QT_NO_PROCESS void tst_QObject::recursiveSignalEmission() { 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)); connect(&sender, &SenderObject::signal2, &receiver, &ReceiverObject::slot2, Qt::BlockingQueuedConnection); sender.emitSignal2(); QVERIFY(receiver.called(2)); thread.quit(); QVERIFY(thread.wait()); } } class EventSpy : public QObject { Q_OBJECT public: typedef QList > 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() << 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() << 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(); }; namespace QObjectTest { // Do not clash with WinAPI 'DeleteObject' class DeleteObject : public QObject { Q_OBJECT public slots: void deleteSelf() { delete this; } void relaySignalAndProcessEvents() { emit relayedSignal(); QCoreApplication::processEvents(); } signals: void relayedSignal(); }; } // namespace QObjectTest void tst_QObject::deleteSelfInSlot() { { SenderObject sender; QObjectTest::DeleteObject *receiver = new QObjectTest::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 p = receiver; sender.emitSignal1(); QVERIFY(p.isNull()); QVERIFY(thread.wait(10000)); } { SenderObject sender; QObjectTest::DeleteObject *receiver = new QObjectTest::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 p = receiver; sender.emitSignal1(); QVERIFY(p.isNull()); QVERIFY(thread.wait(10000)); } { EmitThread sender; QObjectTest::DeleteObject *receiver = new QObjectTest::DeleteObject(); connect(&sender, SIGNAL(work()), receiver, SLOT(deleteSelf()), Qt::DirectConnection); QPointer 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 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 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() << 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(ptr)); QVERIFY(qobject_cast(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()), QByteArray(Bleh_iid)); QCOMPARE(QByteArray(qobject_interface_iid()), QByteArray("com.qtest.foobar")); QCOMPARE(QByteArray(qobject_interface_iid()), 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; QGuiApplication::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 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 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 } void tst_QObject::pointerConnect() { SenderObject *s = new SenderObject; ReceiverObject *r1 = new ReceiverObject; ReceiverObject *r2 = new ReceiverObject; r1->reset(); r2->reset(); ReceiverObject::sequence = 0; QVERIFY( connect( s, &SenderObject::signal1 , r1, &ReceiverObject::slot1 ) ); QVERIFY( connect( s, &SenderObject::signal1 , r2, &ReceiverObject::slot1 ) ); QVERIFY( connect( s, &SenderObject::signal1 , r1, &ReceiverObject::slot3 ) ); QVERIFY( connect( s, &SenderObject::signal3 , r1, &ReceiverObject::slot3 ) ); 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, &SenderObject::signal4, r1, &ReceiverObject::slot4 ) ); QVERIFY( connect( s, &SenderObject::signal4, r2, &ReceiverObject::slot4 ) ); QVERIFY( connect( s, &SenderObject::signal1, r2, &ReceiverObject::slot4 ) ); 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, &SenderObject::signal4 , r1, &ReceiverObject::slot4 ); s->emitSignal4(); QCOMPARE( r1->count_slot4, 2 ); QCOMPARE( r2->count_slot4, 1 ); QCOMPARE( r1->sequence_slot4, 3 ); QCOMPARE( r2->sequence_slot4, 2 ); QMetaObject::Connection con; QVERIFY(!con); QVERIFY(!QObject::disconnect(con)); //connect a slot to a signal (== error) QTest::ignoreMessage(QtWarningMsg, "QObject::connect: signal not found in ReceiverObject"); con = connect(r1, &ReceiverObject::slot4 , s, &SenderObject::signal4 ); QVERIFY(!con); QVERIFY(!QObject::disconnect(con)); delete s; delete r1; delete r2; } void tst_QObject::emitInDefinedOrderPointer() { SenderObject sender; ReceiverObject receiver1, receiver2, receiver3, receiver4; QMetaObject::Connection h0 = connect(&sender, &SenderObject::signal1, &receiver1, &SequenceObject::slot1); QMetaObject::Connection h1 = connect(&sender, &SenderObject::signal1, &receiver2, &SequenceObject::slot1); QVERIFY(h0); QVERIFY(h1); connect(&sender, &SenderObject::signal1, &receiver3, &SequenceObject::slot1); connect(&sender, &SenderObject::signal1, &receiver4, &SequenceObject::slot1); connect(&sender, &SenderObject::signal1, &receiver1, &SequenceObject::slot2); connect(&sender, &SenderObject::signal1, &receiver2, &SequenceObject::slot2); connect(&sender, &SenderObject::signal1, &receiver3, &SequenceObject::slot2); connect(&sender, &SenderObject::signal1, &receiver4, &SequenceObject::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(h1); h1 = connect(&sender, &SenderObject::signal1, &receiver2, &SequenceObject::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(h0); h0 = connect(&sender, &SenderObject::signal1, &receiver1, &SequenceObject::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); QVERIFY(QObject::disconnect(h0)); QVERIFY(!QObject::disconnect(h0)); } void tst_QObject::customTypesPointer() { CustomType t0; CustomType t1(1, 2, 3); CustomType t2(2, 3, 4); { QCustomTypeChecker checker; QCOMPARE(instanceCount, 4); connect(&checker, &QCustomTypeChecker::signal1, &checker, &QCustomTypeChecker::slot1, Qt::DirectConnection); QCOMPARE(checker.received.value(), 0); checker.doEmit(t1); QCOMPARE(checker.received.value(), t1.value()); checker.received = t0; checker.disconnect(); int idx = qRegisterMetaType("CustomType"); QCOMPARE(QMetaType::type("CustomType"), idx); connect(&checker, &QCustomTypeChecker::signal1, &checker, &QCustomTypeChecker::slot1, 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"), idx); QCOMPARE(QMetaType::type("CustomType"), idx); QVERIFY(QMetaType::isRegistered(idx)); } QCOMPARE(instanceCount, 3); } void tst_QObject::connectCxx0x() { SenderObject *s = new SenderObject; ReceiverObject *r1 = new ReceiverObject; QObject::connect(s, &SenderObject::signal1, r1, &ReceiverObject::slot1); QObject::connect(s, &SenderObject::signal3, r1, &ReceiverObject::slot2); QObject::connect(s, &SenderObject::signal3, r1, &ReceiverObject::slot2); QObject::connect(s, &SenderObject::signal3, r1, &ReceiverObject::slot2); 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 ); // connect signal to signal QObject::connect(s, &SenderObject::signal2, s, &SenderObject::signal1); r1->reset(); s->emitSignal2(); QCOMPARE( r1->count_slot1, 1 ); delete s; delete r1; } int receivedCount; void receiverFunction() { ++receivedCount; } void tst_QObject::connectToStaticCxx0x() { SenderObject *s = new SenderObject; void (*receiver)() = receiverFunction; QObject::connect(s, &SenderObject::signal1, receiver); receivedCount = 0; s->emitSignal1(); QCOMPARE(receivedCount, 1); QObject::connect(s, &SenderObject::signal1, receiver); receivedCount = 0; s->emitSignal1(); QCOMPARE(receivedCount, 2); delete s; } class LotsOfSignalsAndSlots: public QObject { Q_OBJECT typedef void (*fptr)(); public slots: void slot_v() {} void slot_vi(int) {} void slot_vii(int, int) {} void slot_viii(int, int, int) {} int slot_i() { return 0; } int slot_ii(int) { return 0; } int slot_iii(int, int) { return 0; } int slot_iiii(int, int, int) { return 0; } void slot_vRi(int &) {} void slot_vs(short) {} void slot_vRs(short&) {} /* #ifdef Q_COMPILER_RVALUE_REFS void slot_vOi(int &&) {} void slot_vOs(short &&) {} #endif*/ void slot_vPFvvE(fptr) {} static void static_slot_v() {} static void static_slot_vi(int) {} static void static_slot_vii(int, int) {} static void static_slot_viii(int, int, int) {} static int static_slot_i() { return 0; } static int static_slot_ii(int) { return 0; } static int static_slot_iii(int, int) { return 0; } static int static_slot_iiii(int, int, int) { return 0; } static void static_slot_vRi(int &) {} static void static_slot_vs(short) {} static void static_slot_vRs(short&) {} /* #if defined(Q_COMPILER_RVALUE_REFS) || defined(QT_ENABLE_CXX0X) static void static_slot_vOi(int &&) {} static void static_slot_vOs(short &&) {} #endif*/ static void static_slot_vPFvvE(fptr) {} signals: void signal_v(); void signal_vi(int); void signal_vii(int, int); void signal_viii(int, int, int); void signal_vRi(int &); void signal_vs(short); void signal_vRs(short &); /* #if defined(Q_COMPILER_RVALUE_REFS) || defined(QT_ENABLE_CXX0X) void signal_vOi(int &&); void signal_vOs(short &&); #endif*/ void signal_vPFvvE(fptr); void signal(short&, short, long long, short); void otherSignal(const char *); }; void tst_QObject::connectCxx0xTypeMatching() { // this is just about connecting the signals to the slots // if this fails, this will be a compiler failure typedef LotsOfSignalsAndSlots Foo; Foo obj; // member connects QObject::connect(&obj, &Foo::signal_v, &obj, &Foo::slot_v); QObject::connect(&obj, &Foo::signal_v, &obj, &Foo::slot_i); QObject::connect(&obj, &Foo::signal_vi, &obj, &Foo::slot_v); QObject::connect(&obj, &Foo::signal_vi, &obj, &Foo::slot_i); QObject::connect(&obj, &Foo::signal_vi, &obj, &Foo::slot_vi); QObject::connect(&obj, &Foo::signal_vi, &obj, &Foo::slot_ii); QObject::connect(&obj, &Foo::signal_vii, &obj, &Foo::slot_v); QObject::connect(&obj, &Foo::signal_vii, &obj, &Foo::slot_i); QObject::connect(&obj, &Foo::signal_vii, &obj, &Foo::slot_vi); QObject::connect(&obj, &Foo::signal_vii, &obj, &Foo::slot_ii); QObject::connect(&obj, &Foo::signal_vii, &obj, &Foo::slot_vii); QObject::connect(&obj, &Foo::signal_vii, &obj, &Foo::slot_iii); QObject::connect(&obj, &Foo::signal_viii, &obj, &Foo::slot_v); QObject::connect(&obj, &Foo::signal_viii, &obj, &Foo::slot_i); QObject::connect(&obj, &Foo::signal_viii, &obj, &Foo::slot_vi); QObject::connect(&obj, &Foo::signal_viii, &obj, &Foo::slot_ii); QObject::connect(&obj, &Foo::signal_viii, &obj, &Foo::slot_vii); QObject::connect(&obj, &Foo::signal_viii, &obj, &Foo::slot_iii); QObject::connect(&obj, &Foo::signal_viii, &obj, &Foo::slot_viii); QObject::connect(&obj, &Foo::signal_viii, &obj, &Foo::slot_iiii); QObject::connect(&obj, &Foo::signal_vi, &obj, &Foo::slot_vi); // repeated from above QObject::connect(&obj, &Foo::signal_vRi, &obj, &Foo::slot_vi); QObject::connect(&obj, &Foo::signal_vRi, &obj, &Foo::slot_vRi); /*#if defined(Q_COMPILER_RVALUE_REFS) || defined(QT_ENABLE_CXX0X) QObject::connect(&obj, &Foo::signal_vOi, &obj, &Foo::slot_vi); QObject::connect(&obj, &Foo::signal_vi, &obj, &Foo::slot_vOi); QObject::connect(&obj, &Foo::signal_vRi, &obj, &Foo::slot_vOi); QObject::connect(&obj, &Foo::signal_vOi, &obj, &Foo::slot_vOi); #endif*/ // these are not supposed to compile: //QObject::connect(&obj, &Foo::signal_vi, &obj, &Foo::slot_vRi); //QObject::connect(&obj, &Foo::signal_vOi, &obj, &Foo::slot_vRi); QObject::connect(&obj, &Foo::signal_vs, &obj, &Foo::slot_vi); QObject::connect(&obj, &Foo::signal_vRs, &obj, &Foo::slot_vi); /*#if defined(Q_COMPILER_RVALUE_REFS) || defined(QT_ENABLE_CXX0X) QObject::connect(&obj, &Foo::signal_vOs, &obj, &Foo::slot_vi); QObject::connect(&obj, &Foo::signal_vRs, &obj, &Foo::slot_vOi); QObject::connect(&obj, &Foo::signal_vOs, &obj, &Foo::slot_vOi); // these are not supposed to compile: //QObject::connect(&obj, &Foo::signal_vOs, &obj, &Foo::slot_vRi); //QObject::connect(&obj, &Foo::signal_vRs, &obj, &Foo::slot_vRi); #endif*/ QObject::connect(&obj, &Foo::signal_vPFvvE, &obj, &Foo::slot_v); QObject::connect(&obj, &Foo::signal_vPFvvE, &obj, &Foo::slot_i); QObject::connect(&obj, &Foo::signal_vPFvvE, &obj, &Foo::slot_vPFvvE); QObject::connect(&obj, &Foo::signal_v, &Foo::static_slot_v); QObject::connect(&obj, &Foo::signal_v, &Foo::static_slot_i); QObject::connect(&obj, &Foo::signal_vi, &Foo::static_slot_v); QObject::connect(&obj, &Foo::signal_vi, &Foo::static_slot_i); QObject::connect(&obj, &Foo::signal_vi, &Foo::static_slot_vi); QObject::connect(&obj, &Foo::signal_vi, &Foo::static_slot_ii); QObject::connect(&obj, &Foo::signal_vii, &Foo::static_slot_v); QObject::connect(&obj, &Foo::signal_vii, &Foo::static_slot_i); QObject::connect(&obj, &Foo::signal_vii, &Foo::static_slot_vi); QObject::connect(&obj, &Foo::signal_vii, &Foo::static_slot_ii); QObject::connect(&obj, &Foo::signal_vii, &Foo::static_slot_vii); QObject::connect(&obj, &Foo::signal_vii, &Foo::static_slot_iii); QObject::connect(&obj, &Foo::signal_viii, &Foo::static_slot_v); QObject::connect(&obj, &Foo::signal_viii, &Foo::static_slot_i); QObject::connect(&obj, &Foo::signal_viii, &Foo::static_slot_vi); QObject::connect(&obj, &Foo::signal_viii, &Foo::static_slot_ii); QObject::connect(&obj, &Foo::signal_viii, &Foo::static_slot_vii); QObject::connect(&obj, &Foo::signal_viii, &Foo::static_slot_iii); QObject::connect(&obj, &Foo::signal_viii, &Foo::static_slot_viii); QObject::connect(&obj, &Foo::signal_viii, &Foo::static_slot_iiii); /*#if defined(Q_COMPILER_RVALUE_REFS) && defined(QT_ENABLE_CXX0X) QObject::connect(&obj, &Foo::signal_vi, &Foo::static_slot_vOi); QObject::connect(&obj, &Foo::signal_vRi, &Foo::static_slot_vi); QObject::connect(&obj, &Foo::signal_vRi, &Foo::static_slot_vRi); QObject::connect(&obj, &Foo::signal_vRi, &Foo::static_slot_vOi); QObject::connect(&obj, &Foo::signal_vOi, &Foo::static_slot_vi); QObject::connect(&obj, &Foo::signal_vOi, &Foo::static_slot_vOi); //QObject::connect(&obj, &Foo::signal_vi, &Foo::static_slot_vRi); //QObject::connect(&obj, &Foo::signal_vOi, &Foo::static_slot_vRi); #endif*/ QObject::connect(&obj, &Foo::signal_vs, &Foo::static_slot_vi); QObject::connect(&obj, &Foo::signal_vRs, &Foo::static_slot_vi); /*#if defined(Q_COMPILER_RVALUE_REFS) && defined(QT_ENABLE_CXX0X) QObject::connect(&obj, &Foo::signal_vOs, &Foo::static_slot_vi); QObject::connect(&obj, &Foo::signal_vRs, &Foo::static_slot_vOi); QObject::connect(&obj, &Foo::signal_vOs, &Foo::static_slot_vOi); //QObject::connect(&obj, &Foo::signal_vOs, &Foo::static_slot_vRi); //QObject::connect(&obj, &Foo::signal_vRs, &Foo::static_slot_vRi); #endif*/ QObject::connect(&obj, &Foo::signal_vPFvvE, &Foo::static_slot_v); QObject::connect(&obj, &Foo::signal_vPFvvE, &Foo::static_slot_i); QObject::connect(&obj, &Foo::signal_vPFvvE, &Foo::static_slot_vPFvvE); QVERIFY(true); //compilation only test } class StringVariant : public QObject { Q_OBJECT signals: void stringSignal(const QString &str); public slots: void variantSlot(const QVariant &v) { var = v; } public: QVariant var; friend class tst_QObject; }; struct Functor { QVariant *var; void operator() (const QVariant &v) { *var = v; } }; void tst_QObject::connectConvert() { StringVariant obj; QVERIFY(connect(&obj, &StringVariant::stringSignal, &obj, &StringVariant::variantSlot)); QString s = QString::fromLatin1("Hello World"); emit obj.stringSignal(s); QCOMPARE(obj.var.toString(), s); QVERIFY(obj.var.toString().isSharedWith(s)); QVariant var; Functor f; f.var = &var; QVERIFY(connect(&obj, &StringVariant::stringSignal, f)); s = QString::fromLatin1("GoodBye"); emit obj.stringSignal(s); QCOMPARE(obj.var.toString(), s); QVERIFY(obj.var.toString().isSharedWith(s)); QCOMPARE(var, obj.var); } class ConnectWithReferenceObject : public QObject { Q_OBJECT friend class tst_QObject; signals: void boolRef(bool &, bool); void stringRef(QString &, const QString &); void boolPtr(bool *, bool); void stringPtr(QString *, const QString &); public slots: void boolRefSlot(bool &b1, bool b2) { b1 = b2; } void stringRefSlot(QString &s1, const QString &s2) { s1 = s2; } void boolPtrSlot(bool *b1, bool b2) { *b1 = b2; } void stringPtrSlot(QString *s1, const QString &s2) { *s1 = s2; } void stringSlot1(QString s) { last = s; } void stringSlot2(const QString &s) { last = s; } void stringSlot3(QString &s) { last = s; } public: QString last; }; void tst_QObject::connectWithReference() { ConnectWithReferenceObject o; bool b1 = true; QString s1 = QString::fromLatin1("str1"); const QString s2 = QString::fromLatin1("str2"); const QString s3 = QString::fromLatin1("str3"); o.boolRef(b1, false); o.stringRef(s1, s2); QCOMPARE(b1, true); QCOMPARE(s1, QString::fromLatin1("str1")); o.boolPtr(&b1, false); o.stringPtr(&s1, s2); QCOMPARE(b1, true); QCOMPARE(s1, QString::fromLatin1("str1")); QVERIFY(connect(&o, &ConnectWithReferenceObject::boolRef, &o, &ConnectWithReferenceObject::boolRefSlot)); QVERIFY(connect(&o, &ConnectWithReferenceObject::stringRef, &o, &ConnectWithReferenceObject::stringRefSlot)); QVERIFY(connect(&o, &ConnectWithReferenceObject::boolPtr, &o, &ConnectWithReferenceObject::boolPtrSlot)); QVERIFY(connect(&o, &ConnectWithReferenceObject::stringPtr, &o, &ConnectWithReferenceObject::stringPtrSlot)); o.boolRef(b1, false); o.stringRef(s1, s2); QCOMPARE(b1, false); QCOMPARE(s1, QString::fromLatin1("str2")); o.boolPtr(&b1, true); o.stringPtr(&s1, s3); QCOMPARE(b1, true); QCOMPARE(s1, QString::fromLatin1("str3")); { ConnectWithReferenceObject o2; QVERIFY(connect(&o2, &ConnectWithReferenceObject::stringRef, &o2, &ConnectWithReferenceObject::stringSlot1)); o2.stringRef(s1, s2); QCOMPARE(s1, s3); QCOMPARE(o2.last, s3); } { ConnectWithReferenceObject o2; QVERIFY(connect(&o2, &ConnectWithReferenceObject::stringRef, &o2, &ConnectWithReferenceObject::stringSlot2)); o2.stringRef(s1, s2); QCOMPARE(s1, s3); QCOMPARE(o2.last, s3); } { ConnectWithReferenceObject o2; QVERIFY(connect(&o2, &ConnectWithReferenceObject::stringRef, &o2, &ConnectWithReferenceObject::stringSlot3)); o2.stringRef(s1, s2); QCOMPARE(s1, s3); QCOMPARE(o2.last, s3); } } class ManyArgumentObject : public QObject { Q_OBJECT signals: void signal1(const QString &); void signal2(const QString &, const QString &); void signal3(const QString &, const QString &, const QString &); void signal4(const QString &, const QString &, const QString &, const QString&); void signal5(const QString &, const QString &, const QString &, const QString&, const QString&); void signal6(const QString &, const QString &, const QString &, const QString&, const QString&, const QString&); public slots: #define MANYARGUMENT_COMPARE(L) QCOMPARE(L, QString(#L)) void slot1(const QString &a) { MANYARGUMENT_COMPARE(a); count++; } void slot2(const QString &a, const QString &b) { MANYARGUMENT_COMPARE(a); MANYARGUMENT_COMPARE(b); count++; } void slot3(const QString &a, const QString &b, const QString &c) { MANYARGUMENT_COMPARE(a); MANYARGUMENT_COMPARE(b); MANYARGUMENT_COMPARE(c); count++; } void slot4(const QString &a, const QString &b, const QString &c, const QString&d) { MANYARGUMENT_COMPARE(a); MANYARGUMENT_COMPARE(b); MANYARGUMENT_COMPARE(c); MANYARGUMENT_COMPARE(d); count++; } void slot5(const QString &a, const QString &b, const QString &c, const QString&d, const QString&e) { MANYARGUMENT_COMPARE(a); MANYARGUMENT_COMPARE(b); MANYARGUMENT_COMPARE(c); MANYARGUMENT_COMPARE(d); MANYARGUMENT_COMPARE(e); count++; } void slot6(const QString &a, const QString &b, const QString &c, const QString&d, const QString&e, const QString&f) { MANYARGUMENT_COMPARE(a); MANYARGUMENT_COMPARE(b); MANYARGUMENT_COMPARE(c); MANYARGUMENT_COMPARE(d); MANYARGUMENT_COMPARE(e); MANYARGUMENT_COMPARE(f); count++; } public: int count; }; namespace ManyArgumentNamespace { int count; void slot1(const QString &a) { MANYARGUMENT_COMPARE(a); count++; } void slot2(const QString &a, const QString &b) { MANYARGUMENT_COMPARE(a); MANYARGUMENT_COMPARE(b); count++; } void slot3(const QString &a, const QString &b, const QString &c) { MANYARGUMENT_COMPARE(a); MANYARGUMENT_COMPARE(b); MANYARGUMENT_COMPARE(c); count++; } void slot4(const QString &a, const QString &b, const QString &c, const QString&d) { MANYARGUMENT_COMPARE(a); MANYARGUMENT_COMPARE(b); MANYARGUMENT_COMPARE(c); MANYARGUMENT_COMPARE(d); count++; } void slot5(const QString &a, const QString &b, const QString &c, const QString&d, const QString&e) { MANYARGUMENT_COMPARE(a); MANYARGUMENT_COMPARE(b); MANYARGUMENT_COMPARE(c); MANYARGUMENT_COMPARE(d); MANYARGUMENT_COMPARE(e); count++; } void slot6(const QString &a, const QString &b, const QString &c, const QString&d, const QString&e, const QString&f) { MANYARGUMENT_COMPARE(a); MANYARGUMENT_COMPARE(b); MANYARGUMENT_COMPARE(c); MANYARGUMENT_COMPARE(d); MANYARGUMENT_COMPARE(e); MANYARGUMENT_COMPARE(f); count++; } } void tst_QObject::connectManyArguments() { #ifdef Q_COMPILER_VARIADIC_TEMPLATES ManyArgumentObject ob; ob.count = 0; ManyArgumentNamespace::count = 0; connect(&ob, &ManyArgumentObject::signal1, &ob, &ManyArgumentObject::slot1); connect(&ob, &ManyArgumentObject::signal2, &ob, &ManyArgumentObject::slot2); connect(&ob, &ManyArgumentObject::signal3, &ob, &ManyArgumentObject::slot3); connect(&ob, &ManyArgumentObject::signal4, &ob, &ManyArgumentObject::slot4); connect(&ob, &ManyArgumentObject::signal5, &ob, &ManyArgumentObject::slot5); connect(&ob, &ManyArgumentObject::signal6, &ob, &ManyArgumentObject::slot6); connect(&ob, &ManyArgumentObject::signal1, ManyArgumentNamespace::slot1); connect(&ob, &ManyArgumentObject::signal2, ManyArgumentNamespace::slot2); connect(&ob, &ManyArgumentObject::signal3, ManyArgumentNamespace::slot3); connect(&ob, &ManyArgumentObject::signal4, ManyArgumentNamespace::slot4); connect(&ob, &ManyArgumentObject::signal5, ManyArgumentNamespace::slot5); connect(&ob, &ManyArgumentObject::signal6, ManyArgumentNamespace::slot6); connect(&ob, &ManyArgumentObject::signal6, &ob, &ManyArgumentObject::signal5); connect(&ob, &ManyArgumentObject::signal5, &ob, &ManyArgumentObject::signal4); connect(&ob, &ManyArgumentObject::signal4, &ob, &ManyArgumentObject::signal3); connect(&ob, &ManyArgumentObject::signal3, &ob, &ManyArgumentObject::signal2); connect(&ob, &ManyArgumentObject::signal2, &ob, &ManyArgumentObject::signal1); emit ob.signal6("a", "b", "c", "d", "e", "f"); QCOMPARE(ob.count, 6); QCOMPARE(ManyArgumentNamespace::count, 6); ManyArgumentObject ob2; ob2.count = 0; ManyArgumentNamespace::count = 0; connect(&ob2, &ManyArgumentObject::signal6, &ob2, &ManyArgumentObject::slot1); connect(&ob2, &ManyArgumentObject::signal6, &ob2, &ManyArgumentObject::slot2); connect(&ob2, &ManyArgumentObject::signal6, &ob2, &ManyArgumentObject::slot3); connect(&ob2, &ManyArgumentObject::signal6, &ob2, &ManyArgumentObject::slot4); connect(&ob2, &ManyArgumentObject::signal6, &ob2, &ManyArgumentObject::slot5); connect(&ob2, &ManyArgumentObject::signal6, &ob2, &ManyArgumentObject::slot6); connect(&ob2, &ManyArgumentObject::signal6, ManyArgumentNamespace::slot1); connect(&ob2, &ManyArgumentObject::signal6, ManyArgumentNamespace::slot2); connect(&ob2, &ManyArgumentObject::signal6, ManyArgumentNamespace::slot3); connect(&ob2, &ManyArgumentObject::signal6, ManyArgumentNamespace::slot4); connect(&ob2, &ManyArgumentObject::signal6, ManyArgumentNamespace::slot5); connect(&ob2, &ManyArgumentObject::signal6, ManyArgumentNamespace::slot6); emit ob2.signal6("a", "b", "c", "d", "e", "f"); QCOMPARE(ob2.count, 6); QCOMPARE(ManyArgumentNamespace::count, 6); #endif } QTEST_MAIN(tst_QObject) #include "tst_qobject.moc"