OSDN Git Service

add QObject test
authorIvailo Monev <xakepa10@gmail.com>
Sun, 29 Aug 2021 20:48:27 +0000 (23:48 +0300)
committerIvailo Monev <xakepa10@gmail.com>
Sun, 29 Aug 2021 20:48:27 +0000 (23:48 +0300)
Signed-off-by: Ivailo Monev <xakepa10@gmail.com>
tests/auto/qobject/CMakeLists.txt [new file with mode: 0644]
tests/auto/qobject/signalbug.cpp [new file with mode: 0644]
tests/auto/qobject/signalbug.h [new file with mode: 0644]
tests/auto/qobject/tst_qobject.cpp [new file with mode: 0644]

diff --git a/tests/auto/qobject/CMakeLists.txt b/tests/auto/qobject/CMakeLists.txt
new file mode 100644 (file)
index 0000000..d36faae
--- /dev/null
@@ -0,0 +1,14 @@
+katie_test(tst_qobject
+    ${CMAKE_CURRENT_SOURCE_DIR}/tst_qobject.cpp
+)
+
+target_link_libraries(tst_qobject KtNetwork)
+
+set(CMAKE_RUNTIME_OUTPUT_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR})
+katie_setup_target(signalbug
+    ${CMAKE_CURRENT_SOURCE_DIR}/signalbug.cpp
+    ${CMAKE_CURRENT_SOURCE_DIR}/signalbug.h
+)
+add_executable(signalbug ${signalbug_SOURCES})
+
+target_link_libraries(signalbug KtCore)
diff --git a/tests/auto/qobject/signalbug.cpp b/tests/auto/qobject/signalbug.cpp
new file mode 100644 (file)
index 0000000..f7b1b4a
--- /dev/null
@@ -0,0 +1,134 @@
+/****************************************************************************
+**
+** Copyright (C) 2015 The Qt Company Ltd.
+** Copyright (C) 2016 Ivailo Monev
+**
+** This file is part of the test suite of the Katie 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.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "signalbug.h"
+
+#include <qcoreapplication.h>
+#include <qstring.h>
+
+#include <stdio.h>
+
+static int Step = 0;
+Sender RandomSender (0, 0);
+
+
+void TRACE (int step, const char *name)
+{
+    for (int t = 0; t < step - 1; t++)
+        fprintf (stderr, "\t");
+    fprintf (stderr, "Step %d: %s\n", step, name);
+    return;
+}
+
+
+Receiver::Receiver ()
+    : QObject ()
+{
+}
+
+void Receiver::received ()
+{
+    ::Step++;
+    const int stepCopy = ::Step;
+    TRACE (stepCopy, "Receiver::received()");
+    if (::Step != 2 && ::Step != 4)
+        qFatal("%s: Incorrect Step: %d (should be 2 or 4)", Q_FUNC_INFO, ::Step);
+
+    if (::Step == 2)
+        s->fire ();
+
+    fprintf (stderr, "Receiver<%s>::received() sender=%s\n",
+        (const char *) objectName ().toAscii (), sender ()->metaObject()->className());
+
+    TRACE (stepCopy, "ends Receiver::received()");
+}
+
+
+Disconnector::Disconnector ()
+    : QObject ()
+{
+}
+
+void Disconnector::received ()
+{
+    ::Step++;
+    const int stepCopy = ::Step;
+    TRACE (stepCopy, "Disconnector::received()");
+    if (::Step != 5 && ::Step != 6)
+        qFatal("%s: Incorrect Step: %d (should be 5 or 6)", Q_FUNC_INFO, ::Step);
+
+    fprintf (stderr, "Disconnector<%s>::received() sender=%s\n",
+            (const char *) objectName ().toAscii (), sender ()->metaObject()->className());
+    if (sender () == 0)
+        fprintf (stderr, "WE SHOULD NOT BE RECEIVING THIS SIGNAL\n");
+
+    if (::Step == 5)
+    {
+        disconnect (s, SIGNAL (fired ()), s->d, SLOT (received ()));
+
+        connect (&RandomSender, SIGNAL (fired ()), s->d, SLOT (received ()));
+    }
+
+    TRACE (stepCopy, "ends Disconnector::received()");
+}
+
+
+Sender::Sender (Receiver *r, Disconnector *d)
+    : QObject ()
+{
+    this->r = r; this->d = d;
+    if (r)
+        connect (this, SIGNAL (fired ()), r, SLOT (received ()));
+    if (d)
+        connect (this, SIGNAL (fired ()), d, SLOT (received ()));
+};
+
+void Sender::fire ()
+{
+    ::Step++;
+    const int stepCopy = ::Step;
+    TRACE (stepCopy, "Sender::fire()");
+    if (::Step != 1 && ::Step != 3)
+        qFatal("%s: Incorrect Step: %d (should be 1 or 3)", Q_FUNC_INFO, ::Step);
+
+    emit fired ();
+    TRACE (stepCopy, "ends Sender::fire()");
+}
+
+
+int main (int argc, char *argv [])
+{
+    QCoreApplication app (argc, argv);
+
+    Receiver r;
+    Disconnector d;
+    Sender s (&r, &d);
+
+    r.s = &s;
+    d.s = &s;
+
+
+    ::Step = 0;
+    s.fire ();
+    return 0;
+}
+
+#include "moc_signalbug.h"
diff --git a/tests/auto/qobject/signalbug.h b/tests/auto/qobject/signalbug.h
new file mode 100644 (file)
index 0000000..5aeceec
--- /dev/null
@@ -0,0 +1,83 @@
+/****************************************************************************
+**
+** Copyright (C) 2015 The Qt Company Ltd.
+** Copyright (C) 2016 Ivailo Monev
+**
+** This file is part of the test suite of the Katie 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.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef SIGNAL_BUG_H
+#define SIGNAL_BUG_H
+
+
+#include <QObject>
+
+
+class Sender;
+
+
+class Receiver : public QObject
+{
+    Q_OBJECT
+
+public:
+    Receiver ();
+    virtual ~Receiver () {}
+
+protected slots:
+    void received ();
+
+public:
+    Sender *s;
+};
+
+
+class Disconnector : public QObject
+{
+    Q_OBJECT
+
+public:
+    Disconnector ();
+    virtual ~Disconnector () {}
+
+protected slots:
+    void received ();
+
+public:
+    Sender *s;
+};
+
+
+class Sender : public QObject
+{
+Q_OBJECT
+
+public:
+    Sender (Receiver *r, Disconnector *d);
+    virtual ~Sender () {}
+
+    void fire ();
+
+signals:
+    void fired ();
+
+public:
+    Receiver *r;
+    Disconnector *d;
+};
+
+
+#endif  // SIGNAL_BUG_H
diff --git a/tests/auto/qobject/tst_qobject.cpp b/tests/auto/qobject/tst_qobject.cpp
new file mode 100644 (file)
index 0000000..f649744
--- /dev/null
@@ -0,0 +1,3723 @@
+/****************************************************************************
+**
+** Copyright (C) 2015 The Qt Company Ltd.
+** Copyright (C) 2016 Ivailo Monev
+**
+** This file is part of the test suite of the Katie 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.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include <QtTest/QtTest>
+
+#include <qcoreapplication.h>
+#include <qpointer.h>
+#include <qtimer.h>
+#include <qregexp.h>
+#include <qmetaobject.h>
+#include <qvariant.h>
+#include <QTcpServer>
+#include <QTcpSocket>
+#include <QThread>
+#include <QMutex>
+#include <QWaitCondition>
+#include <QProcess>
+#include "qobject.h"
+#include "qobject_p.h"
+
+#include <math.h>
+
+//TESTED_CLASS=
+//TESTED_FILES=
+
+class tst_QObject : public QObject
+{
+    Q_OBJECT
+
+public:
+    tst_QObject();
+    virtual ~tst_QObject();
+
+
+public slots:
+    void initTestCase();
+    void cleanupTestCase();
+    void init();
+    void cleanup();
+private slots:
+    void disconnect();
+    void connectByName();
+    void connectSignalsToSignalsWithDefaultArguments();
+    void receivers();
+    void normalize();
+    void qobject_castTemplate();
+    void findChildren();
+    void connectDisconnectNotify_data();
+    void connectDisconnectNotify();
+    void emitInDefinedOrder();
+    void customTypes();
+    void streamCustomTypes();
+    void metamethod();
+    void namespaces();
+    void threadSignalEmissionCrash();
+    void thread();
+    void moveToThread();
+    void sender();
+    void declareInterface();
+    void qpointerResetBeforeDestroyedSignal();
+    void childDeletesItsSibling();
+    void dynamicProperties();
+    void floatProperty();
+    void qrealProperty();
+    void property();
+    void recursiveSignalEmission();
+    void blockingQueuedConnection();
+    void compatibilityChildInsertedEvents();
+    void installEventFilter();
+    void deleteSelfInSlot();
+    void disconnectSelfInSlotAndDeleteAfterEmit();
+    void dumpObjectInfo();
+    void connectToSender();
+    void qobjectConstCast();
+    void uniqConnection();
+    void interfaceIid();
+    void deleteQObjectWhenDeletingEvent();
+    void overloads();
+    void isSignalConnected();
+    void qMetaObjectConnect();
+    void qMetaObjectDisconnectOne();
+    void sameName();
+    void connectByMetaMethods();
+    void connectByMetaMethodSlotInsteadOfSignal();
+    void connectConstructorByMetaMethod();
+    void disconnectByMetaMethod();
+    void disconnectNotSignalMetaMethod();
+    void autoConnectionBehavior();
+    void baseDestroyed();
+protected:
+};
+
+tst_QObject::tst_QObject()
+{
+
+}
+
+tst_QObject::~tst_QObject()
+{
+
+}
+
+void tst_QObject::initTestCase()
+{
+}
+
+void tst_QObject::cleanupTestCase()
+{
+}
+
+void tst_QObject::init()
+{
+}
+
+void tst_QObject::cleanup()
+{
+}
+
+class SenderObject : public QObject
+{
+    Q_OBJECT
+
+public:
+    SenderObject() : aPublicSlotCalled(0), recursionCount(0) {}
+
+    void emitSignal1AfterRecursion()
+    {
+        if (recursionCount++ < 100)
+            emitSignal1AfterRecursion();
+        else
+            emitSignal1();
+    }
+
+    void emitSignal1() { emit signal1(); }
+    void emitSignal2() { emit signal2(); }
+    void emitSignal3() { emit signal3(); }
+    void emitSignal4() { emit signal4(); }
+
+signals:
+    void signal1();
+    void signal2();
+    void signal3();
+    void signal4();
+    void signal5();
+
+public slots:
+    void aPublicSlot() { aPublicSlotCalled++; }
+
+public:
+    Q_INVOKABLE void invoke1(){}
+    Q_SCRIPTABLE void sinvoke1(){}
+    int aPublicSlotCalled;
+protected:
+    Q_INVOKABLE void invoke2(){}
+    Q_INVOKABLE void invoke2(int){}
+    Q_SCRIPTABLE 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<QObject*>(o) );
+
+    o = new SenderObject;
+    QVERIFY( ::qobject_cast<SenderObject*>(o) );
+    QVERIFY( ::qobject_cast<QObject*>(o) );
+    QVERIFY( !::qobject_cast<ReceiverObject*>(o) );
+    delete o;
+}
+
+void tst_QObject::findChildren()
+{
+    QObject o;
+    QObject o1(&o);
+    QObject o2(&o);
+    QObject o11(&o1);
+    QObject o12(&o1);
+    QObject o111(&o11);
+    QObject unnamed(&o);
+    QTimer t1(&o);
+    QTimer t121(&o12);
+    QTimer emptyname(&o);
+
+    o.setObjectName("o");
+    o1.setObjectName("o1");
+    o2.setObjectName("o2");
+    o11.setObjectName("o11");
+    o12.setObjectName("o12");
+    o111.setObjectName("o111");
+    t1.setObjectName("t1");
+    t121.setObjectName("t121");
+    emptyname.setObjectName("");
+
+    QObject *op = 0;
+
+    op = o.findChild<QObject*>("o1");
+    QCOMPARE(op, &o1);
+    op = o.findChild<QObject*>("o2");
+    QCOMPARE(op, &o2);
+    op = o.findChild<QObject*>("o11");
+    QCOMPARE(op, &o11);
+    op = o.findChild<QObject*>("o12");
+    QCOMPARE(op, &o12);
+    op = o.findChild<QObject*>("o111");
+    QCOMPARE(op, &o111);
+    op = o.findChild<QObject*>("t1");
+    QCOMPARE(op, static_cast<QObject *>(&t1));
+    op = o.findChild<QObject*>("t121");
+    QCOMPARE(op, static_cast<QObject *>(&t121));
+    op = o.findChild<QTimer*>("t1");
+    QCOMPARE(op, static_cast<QObject *>(&t1));
+    op = o.findChild<QTimer*>("t121");
+    QCOMPARE(op, static_cast<QObject *>(&t121));
+    op = o.findChild<QTimer*>("o12");
+    QCOMPARE(op, static_cast<QObject *>(0));
+    op = o.findChild<QObject*>("o");
+    QCOMPARE(op, static_cast<QObject *>(0));
+    op = o.findChild<QObject*>("harry");
+    QCOMPARE(op, static_cast<QObject *>(0));
+    op = o.findChild<QObject*>("o1");
+    QCOMPARE(op, &o1);
+
+    QList<QObject*> l;
+    QList<QTimer*> tl;
+
+    l = o.findChildren<QObject*>("o1");
+    QCOMPARE(l.size(), 1);
+    QCOMPARE(l.at(0), &o1);
+    l = o.findChildren<QObject*>("o2");
+    QCOMPARE(l.size(), 1);
+    QCOMPARE(l.at(0), &o2);
+    l = o.findChildren<QObject*>("o11");
+    QCOMPARE(l.size(), 1);
+    QCOMPARE(l.at(0), &o11);
+    l = o.findChildren<QObject*>("o12");
+    QCOMPARE(l.size(), 1);
+    QCOMPARE(l.at(0), &o12);
+    l = o.findChildren<QObject*>("o111");
+    QCOMPARE(l.size(), 1);
+    QCOMPARE(l.at(0), &o111);
+    l = o.findChildren<QObject*>("t1");
+    QCOMPARE(l.size(), 1);
+    QCOMPARE(l.at(0), static_cast<QObject *>(&t1));
+    l = o.findChildren<QObject*>("t121");
+    QCOMPARE(l.size(), 1);
+    QCOMPARE(l.at(0), static_cast<QObject *>(&t121));
+    tl = o.findChildren<QTimer*>("t1");
+    QCOMPARE(tl.size(), 1);
+    QCOMPARE(tl.at(0), &t1);
+    tl = o.findChildren<QTimer*>("t121");
+    QCOMPARE(tl.size(), 1);
+    QCOMPARE(tl.at(0), &t121);
+    l = o.findChildren<QObject*>("o");
+    QCOMPARE(l.size(), 0);
+    l = o.findChildren<QObject*>("harry");
+    QCOMPARE(l.size(), 0);
+    tl = o.findChildren<QTimer*>("o12");
+    QCOMPARE(tl.size(), 0);
+    l = o.findChildren<QObject*>("o1");
+    QCOMPARE(l.size(), 1);
+    QCOMPARE(l.at(0), &o1);
+
+    l = o.findChildren<QObject*>(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 = o.findChildren<QObject*>(QRegExp("t.*"));
+    QCOMPARE(l.size(), 2);
+    QVERIFY(l.contains(&t1));
+    QVERIFY(l.contains(&t121));
+    tl = o.findChildren<QTimer*>(QRegExp(".*"));
+    QCOMPARE(tl.size(), 3);
+    QVERIFY(tl.contains(&t1));
+    QVERIFY(tl.contains(&t121));
+    tl = o.findChildren<QTimer*>(QRegExp("o.*"));
+    QCOMPARE(tl.size(), 0);
+    l = o.findChildren<QObject*>(QRegExp("harry"));
+    QCOMPARE(l.size(), 0);
+
+    // empty and null string check
+    op = o.findChild<QObject*>();
+    QCOMPARE(op, &o1);
+    op = o.findChild<QObject*>("");
+    QCOMPARE(op, &unnamed);
+    op = o.findChild<QObject*>("unnamed");
+    QCOMPARE(op, static_cast<QObject *>(0));
+
+    l = o.findChildren<QObject*>();
+    QCOMPARE(l.size(), 9);
+    l = o.findChildren<QObject*>("");
+    QCOMPARE(l.size(), 2);
+    l = o.findChildren<QObject*>("unnamed");
+    QCOMPARE(l.size(), 0);
+
+    tl = o.findChildren<QTimer *>("t1");
+    QCOMPARE(tl.size(), 1);
+    QCOMPARE(tl.at(0), &t1);
+}
+
+
+class NotifyObject : public SenderObject, public ReceiverObject
+{
+public:
+    NotifyObject() : SenderObject(), ReceiverObject()
+    {}
+
+    QString org_signal;
+    QString nw_signal;
+
+protected:
+    void connectNotify( const char *signal )
+    {
+        org_signal = signal;
+        nw_signal = QMetaObject::normalizedSignature(signal);
+    };
+    void disconnectNotify( const char *signal )
+    {
+        org_signal = signal;
+        nw_signal = QMetaObject::normalizedSignature(signal);
+    };
+};
+
+void tst_QObject::connectDisconnectNotify_data()
+{
+    QTest::addColumn<QString>("a_signal");
+    QTest::addColumn<QString>("a_slot");
+
+    QTest::newRow("combo1") << SIGNAL( signal1() )        << SLOT( slot1() );
+    QTest::newRow("combo2") << SIGNAL( signal2(void) )    << SLOT( slot2(  ) );
+    QTest::newRow("combo3") << SIGNAL( signal3(  ) )      << SLOT( slot3(void) );
+    QTest::newRow("combo4") << SIGNAL(  signal4( void )  )<< SLOT(  slot4( void )  );
+}
+
+void tst_QObject::connectDisconnectNotify()
+{
+    NotifyObject *s = new NotifyObject;
+    NotifyObject *r = new NotifyObject;
+
+    QFETCH(QString, a_signal);
+    QFETCH(QString, a_slot);
+
+    // Test connectNotify
+    connect( (SenderObject*)s, a_signal.toLatin1(), (ReceiverObject*)r, a_slot.toLatin1() );
+    QCOMPARE( s->org_signal, s->nw_signal );
+    QCOMPARE( s->org_signal.toLatin1(), QMetaObject::normalizedSignature(a_signal.toLatin1().constData()) );
+
+    // Test disconnectNotify
+    QObject::disconnect( (SenderObject*)s, a_signal.toLatin1(), (ReceiverObject*)r, a_slot.toLatin1() );
+    QCOMPARE( s->org_signal, s->nw_signal );
+    QCOMPARE( s->org_signal.toLatin1(), QMetaObject::normalizedSignature(a_signal.toLatin1().constData()) );
+
+    // Reconnect
+    connect( (SenderObject*)s, a_signal.toLatin1(), (ReceiverObject*)r, a_slot.toLatin1() );
+    // Test disconnectNotify for a complete disconnect
+    ((SenderObject*)s)->disconnect((ReceiverObject*)r);
+
+    // Obtaining meta methods
+    int signalIndx = ((SenderObject*)s)->metaObject()->indexOfSignal(
+            QMetaObject::normalizedSignature(a_signal.toLatin1().constData()+1).constData());
+    int methodIndx = ((ReceiverObject*)r)->metaObject()->indexOfMethod(
+            QMetaObject::normalizedSignature(a_slot.toLatin1().constData()+1).constData());
+    QMetaMethod signal = ((SenderObject*)s)->metaObject()->method(signalIndx);
+    QMetaMethod method = ((ReceiverObject*)r)->metaObject()->method(methodIndx);
+
+    // Test connectNotify when connecting by QMetaMethod
+    connect( (SenderObject*)s, signal, (ReceiverObject*)r, method );
+    QCOMPARE( s->org_signal, s->nw_signal );
+    QCOMPARE( s->org_signal.toLatin1(), QMetaObject::normalizedSignature(a_signal.toLatin1().constData()) );
+
+    // Test disconnectNotify when disconnecting by QMetaMethod
+    QObject::disconnect( (SenderObject*)s, signal, (ReceiverObject*)r, method );
+    QCOMPARE( s->org_signal, s->nw_signal );
+    QCOMPARE( s->org_signal.toLatin1(), QMetaObject::normalizedSignature(a_signal.toLatin1().constData()) );
+
+    delete s;
+    delete r;
+}
+
+class SequenceObject : public ReceiverObject
+{
+    Q_OBJECT
+
+public:
+    QObject *next;
+    SequenceObject() : next(0) { }
+
+public slots:
+    void slot1_disconnectThis()
+    {
+        slot1();
+        disconnect(sender(), SIGNAL(signal1()), this, SLOT(slot1_disconnectThis()));
+    }
+
+    void slot2_reconnectThis()
+    {
+        slot2();
+
+        const QObject *s = sender();
+        disconnect(s, SIGNAL(signal1()), this, SLOT(slot2_reconnectThis()));
+        connect(s, SIGNAL(signal1()), this, SLOT(slot2_reconnectThis()));
+    }
+
+    void slot1_disconnectNext()
+    {
+        slot1();
+        disconnect(sender(), SIGNAL(signal1()), next, SLOT(slot1()));
+    }
+
+    void slot2_reconnectNext()
+    {
+        slot2();
+
+        // modify the connection list in 'this'
+        disconnect(sender(), SIGNAL(signal1()), next, SLOT(slot2()));
+        connect(sender(), SIGNAL(signal1()), next, SLOT(slot2()));
+
+        // modify the sender list in 'this'
+        connect(next, SIGNAL(destroyed()), this, SLOT(deleteLater()));
+        connect(QCoreApplication::instance(), SIGNAL(aboutToQuit()), this, SLOT(deleteLater()));
+        disconnect(next, SIGNAL(destroyed()), this, SLOT(deleteLater()));
+        disconnect(QCoreApplication::instance(), SIGNAL(aboutToQuit()), this, SLOT(deleteLater()));
+    }
+
+    void slot1_deleteNext()
+    {
+        slot1();
+        delete next;
+    }
+
+    void slot2_deleteSender()
+    {
+        slot2();
+        delete sender();
+    }
+};
+
+void tst_QObject::emitInDefinedOrder()
+{
+    SenderObject sender;
+    ReceiverObject receiver1, receiver2, receiver3, receiver4;
+
+    connect(&sender, SIGNAL(signal1()), &receiver1, SLOT(slot1()));
+    connect(&sender, SIGNAL(signal1()), &receiver2, SLOT(slot1()));
+    connect(&sender, SIGNAL(signal1()), &receiver3, SLOT(slot1()));
+    connect(&sender, SIGNAL(signal1()), &receiver4, SLOT(slot1()));
+    connect(&sender, SIGNAL(signal1()), &receiver1, SLOT(slot2()));
+    connect(&sender, SIGNAL(signal1()), &receiver2, SLOT(slot2()));
+    connect(&sender, SIGNAL(signal1()), &receiver3, SLOT(slot2()));
+    connect(&sender, SIGNAL(signal1()), &receiver4, SLOT(slot2()));
+
+    int sequence;
+    ReceiverObject::sequence = sequence = 0;
+    sender.emitSignal1();
+    QCOMPARE(receiver1.sequence_slot1, ++sequence);
+    QCOMPARE(receiver2.sequence_slot1, ++sequence);
+    QCOMPARE(receiver3.sequence_slot1, ++sequence);
+    QCOMPARE(receiver4.sequence_slot1, ++sequence);
+    QCOMPARE(receiver1.sequence_slot2, ++sequence);
+    QCOMPARE(receiver2.sequence_slot2, ++sequence);
+    QCOMPARE(receiver3.sequence_slot2, ++sequence);
+    QCOMPARE(receiver4.sequence_slot2, ++sequence);
+
+    QObject::disconnect(&sender, SIGNAL(signal1()), &receiver2, SLOT(slot1()));
+    connect(&sender, SIGNAL(signal1()), &receiver2, SLOT(slot1()));
+
+    ReceiverObject::sequence = sequence =  0;
+    sender.emitSignal1();
+    QCOMPARE(receiver1.sequence_slot1, ++sequence);
+    QCOMPARE(receiver3.sequence_slot1, ++sequence);
+    QCOMPARE(receiver4.sequence_slot1, ++sequence);
+    QCOMPARE(receiver1.sequence_slot2, ++sequence);
+    QCOMPARE(receiver2.sequence_slot2, ++sequence);
+    QCOMPARE(receiver3.sequence_slot2, ++sequence);
+    QCOMPARE(receiver4.sequence_slot2, ++sequence);
+    QCOMPARE(receiver2.sequence_slot1, ++sequence);
+
+    QObject::disconnect(&sender, SIGNAL(signal1()), &receiver1, SLOT(slot1()));
+    connect(&sender, SIGNAL(signal1()), &receiver1, SLOT(slot1()));
+
+    ReceiverObject::sequence = sequence =  0;
+    sender.emitSignal1();
+    QCOMPARE(receiver3.sequence_slot1, ++sequence);
+    QCOMPARE(receiver4.sequence_slot1, ++sequence);
+    QCOMPARE(receiver1.sequence_slot2, ++sequence);
+    QCOMPARE(receiver2.sequence_slot2, ++sequence);
+    QCOMPARE(receiver3.sequence_slot2, ++sequence);
+    QCOMPARE(receiver4.sequence_slot2, ++sequence);
+    QCOMPARE(receiver2.sequence_slot1, ++sequence);
+    QCOMPARE(receiver1.sequence_slot1, ++sequence);
+
+    // ensure emission order even if the connections change during emission
+    SenderObject *sender2 = new SenderObject;
+    SequenceObject seq1, seq2, *seq3 = new SequenceObject, seq4;
+    seq1.next = &seq2;
+    seq2.next = seq3;
+    seq3->next = &seq4;
+
+    // try 1
+    connect(sender2, SIGNAL(signal1()), &seq1, SLOT(slot1_disconnectThis()));
+    connect(sender2, SIGNAL(signal1()), &seq2, SLOT(slot1_disconnectNext()));
+    connect(sender2, SIGNAL(signal1()), seq3, SLOT(slot1()));
+    connect(sender2, SIGNAL(signal1()), &seq4, SLOT(slot1()));
+    connect(sender2, SIGNAL(signal1()), &seq1, SLOT(slot2_reconnectThis()));
+    connect(sender2, SIGNAL(signal1()), &seq2, SLOT(slot2_reconnectNext()));
+    connect(sender2, SIGNAL(signal1()), seq3, SLOT(slot2()));
+    connect(sender2, SIGNAL(signal1()), &seq4, SLOT(slot2()));
+
+    SequenceObject::sequence = sequence = 0;
+    sender2->emitSignal1();
+    QCOMPARE(seq1.called(1), true);
+    QCOMPARE(seq2.called(1), true);
+    QCOMPARE(seq3->called(1), false);
+    QCOMPARE(seq4.called(1), true);
+    QCOMPARE(seq1.called(2), true);
+    QCOMPARE(seq2.called(2), true);
+    QCOMPARE(seq3->called(2), false);
+    QCOMPARE(seq4.called(2), true);
+    QCOMPARE(seq1.sequence_slot1, ++sequence);
+    QCOMPARE(seq2.sequence_slot1, ++sequence);
+    QCOMPARE(seq4.sequence_slot1, ++sequence);
+    QCOMPARE(seq1.sequence_slot2, ++sequence);
+    QCOMPARE(seq2.sequence_slot2, ++sequence);
+    QCOMPARE(seq4.sequence_slot2, ++sequence);
+
+    QObject::disconnect(sender2, 0, &seq1, 0);
+    QObject::disconnect(sender2, 0, &seq2, 0);
+    QObject::disconnect(sender2, 0, seq3, 0);
+    QObject::disconnect(sender2, 0, &seq4, 0);
+    seq1.reset();
+    seq2.reset();
+    seq3->reset();
+    seq4.reset();
+
+    // try 2
+    connect(sender2, SIGNAL(signal1()), &seq1, SLOT(slot2_reconnectThis()));
+    connect(sender2, SIGNAL(signal1()), &seq2, SLOT(slot2_reconnectNext()));
+    connect(sender2, SIGNAL(signal1()), seq3, SLOT(slot2()));
+    connect(sender2, SIGNAL(signal1()), &seq4, SLOT(slot2()));
+    connect(sender2, SIGNAL(signal1()), &seq1, SLOT(slot1_disconnectThis()));
+    connect(sender2, SIGNAL(signal1()), &seq2, SLOT(slot1_disconnectNext()));
+    connect(sender2, SIGNAL(signal1()), seq3, SLOT(slot1()));
+    connect(sender2, SIGNAL(signal1()), &seq4, SLOT(slot1()));
+
+    SequenceObject::sequence = sequence = 0;
+    sender2->emitSignal1();
+    QCOMPARE(seq1.called(2), true);
+    QCOMPARE(seq2.called(2), true);
+    QCOMPARE(seq3->called(2), false);
+    QCOMPARE(seq4.called(2), true);
+    QCOMPARE(seq1.called(1), true);
+    QCOMPARE(seq2.called(1), true);
+    QCOMPARE(seq3->called(1), false);
+    QCOMPARE(seq4.called(1), true);
+    QCOMPARE(seq1.sequence_slot2, ++sequence);
+    QCOMPARE(seq2.sequence_slot2, ++sequence);
+    QCOMPARE(seq4.sequence_slot2, ++sequence);
+    QCOMPARE(seq1.sequence_slot1, ++sequence);
+    QCOMPARE(seq2.sequence_slot1, ++sequence);
+    QCOMPARE(seq4.sequence_slot1, ++sequence);
+
+    QObject::disconnect(sender2, 0, &seq1, 0);
+    QObject::disconnect(sender2, 0, &seq2, 0);
+    QObject::disconnect(sender2, 0, seq3, 0);
+    QObject::disconnect(sender2, 0, &seq4, 0);
+    seq1.reset();
+    seq2.reset();
+    seq3->reset();
+    seq4.reset();
+
+    // try 3
+    connect(sender2, SIGNAL(signal1()), &seq1, SLOT(slot1()));
+    connect(sender2, SIGNAL(signal1()), &seq2, SLOT(slot1_disconnectNext()));
+    connect(sender2, SIGNAL(signal1()), seq3, SLOT(slot1()));
+    connect(sender2, SIGNAL(signal1()), &seq4, SLOT(slot1()));
+    connect(sender2, SIGNAL(signal1()), &seq1, SLOT(slot2()));
+    connect(sender2, SIGNAL(signal1()), &seq2, SLOT(slot2_reconnectNext()));
+    connect(sender2, SIGNAL(signal1()), seq3, SLOT(slot2()));
+    connect(sender2, SIGNAL(signal1()), &seq4, SLOT(slot2()));
+
+    SequenceObject::sequence = sequence = 0;
+    sender2->emitSignal1();
+    QCOMPARE(seq1.called(1), true);
+    QCOMPARE(seq2.called(1), true);
+    QCOMPARE(seq3->called(1), false);
+    QCOMPARE(seq4.called(1), true);
+    QCOMPARE(seq1.called(2), true);
+    QCOMPARE(seq2.called(2), true);
+    QCOMPARE(seq3->called(2), false);
+    QCOMPARE(seq4.called(2), true);
+    QCOMPARE(seq1.sequence_slot1, ++sequence);
+    QCOMPARE(seq2.sequence_slot1, ++sequence);
+    QCOMPARE(seq4.sequence_slot1, ++sequence);
+    QCOMPARE(seq1.sequence_slot2, ++sequence);
+    QCOMPARE(seq2.sequence_slot2, ++sequence);
+    QCOMPARE(seq4.sequence_slot2, ++sequence);
+
+    // ensure emission order even if objects are destroyed during emission
+    QObject::disconnect(sender2, 0, &seq1, 0);
+    QObject::disconnect(sender2, 0, &seq2, 0);
+    QObject::disconnect(sender2, 0, seq3, 0);
+    QObject::disconnect(sender2, 0, &seq4, 0);
+    seq1.reset();
+    seq2.reset();
+    seq3->reset();
+    seq4.reset();
+
+    connect(sender2, SIGNAL(signal1()), &seq1, SLOT(slot1()));
+    connect(sender2, SIGNAL(signal1()), &seq2, SLOT(slot1_deleteNext()));
+    connect(sender2, SIGNAL(signal1()), seq3, SLOT(slot1()));
+    connect(sender2, SIGNAL(signal1()), &seq4, SLOT(slot1()));
+    connect(sender2, SIGNAL(signal1()), &seq1, SLOT(slot2()));
+    connect(sender2, SIGNAL(signal1()), &seq2, SLOT(slot2_deleteSender()));
+    connect(sender2, SIGNAL(signal1()), seq3, SLOT(slot2()));
+    connect(sender2, SIGNAL(signal1()), &seq4, SLOT(slot2()));
+
+    QPointer<SenderObject> psender = sender2;
+    QPointer<SequenceObject> pseq3 = seq3;
+
+    SequenceObject::sequence = sequence = 0;
+    sender2->emitSignal1();
+    QCOMPARE(static_cast<QObject *>(psender), static_cast<QObject *>(0));
+    QCOMPARE(static_cast<QObject *>(pseq3), static_cast<QObject *>(0));
+    QCOMPARE(seq1.called(1), true);
+    QCOMPARE(seq2.called(1), true);
+    QCOMPARE(seq4.called(1), true);
+    QCOMPARE(seq1.called(2), true);
+    QCOMPARE(seq2.called(2), true);
+    QCOMPARE(seq4.called(2), false);
+    QCOMPARE(seq1.sequence_slot1, ++sequence);
+    QCOMPARE(seq2.sequence_slot1, ++sequence);
+    QCOMPARE(seq4.sequence_slot1, ++sequence);
+    QCOMPARE(seq1.sequence_slot2, ++sequence);
+    QCOMPARE(seq2.sequence_slot2, ++sequence);
+
+    QPointer<SenderObject> psender3 = new SenderObject;
+    connect(psender3, SIGNAL(signal1()), psender3, SIGNAL(signal2()));
+    connect(psender3, SIGNAL(signal2()), &seq1, SLOT(slot2_deleteSender()));
+    psender3->emitSignal1();
+    QVERIFY(!psender3);
+}
+
+static int instanceCount = 0;
+
+struct CustomType
+{
+    CustomType(int l1 = 0, int l2 = 0, int l3 = 0): i1(l1), i2(l2), i3(l3)
+    { ++instanceCount; }
+    CustomType(const CustomType &other): i1(other.i1), i2(other.i2), i3(other.i3)
+    { ++instanceCount; }
+    ~CustomType() { --instanceCount; }
+
+    int i1, i2, i3;
+    int value() { return i1 + i2 + i3; }
+};
+
+Q_DECLARE_METATYPE(CustomType*)
+
+class QCustomTypeChecker: public QObject
+{
+    Q_OBJECT
+
+public:
+    QCustomTypeChecker(QObject *parent = 0): QObject(parent) {}
+    void doEmit(CustomType ct)
+    { emit signal1(ct); }
+
+public slots:
+    void slot1(CustomType ct);
+
+signals:
+    void signal1(CustomType ct);
+
+public:
+    CustomType received;
+};
+
+void QCustomTypeChecker::slot1(CustomType ct)
+{ received = ct; }
+
+
+void tst_QObject::customTypes()
+{
+    CustomType t0;
+    CustomType t1(1, 2, 3);
+    CustomType t2(2, 3, 4);
+
+    {
+        QCustomTypeChecker checker;
+        QCOMPARE(instanceCount, 4);
+
+        connect(&checker, SIGNAL(signal1(CustomType)), &checker, SLOT(slot1(CustomType)),
+                Qt::DirectConnection);
+        QCOMPARE(checker.received.value(), 0);
+        checker.doEmit(t1);
+        QCOMPARE(checker.received.value(), t1.value());
+        checker.received = t0;
+
+        int idx = qRegisterMetaType<CustomType>("CustomType");
+        QCOMPARE(QMetaType::type("CustomType"), idx);
+
+        checker.disconnect();
+        connect(&checker, SIGNAL(signal1(CustomType)), &checker, SLOT(slot1(CustomType)),
+                Qt::QueuedConnection);
+        QCOMPARE(instanceCount, 4);
+        checker.doEmit(t2);
+        QCOMPARE(instanceCount, 5);
+        QCOMPARE(checker.received.value(), t0.value());
+
+        QCoreApplication::processEvents();
+        QCOMPARE(checker.received.value(), t2.value());
+        QCOMPARE(instanceCount, 4);
+
+        QVERIFY(QMetaType::isRegistered(idx));
+        QCOMPARE(qRegisterMetaType<CustomType>("CustomType"), idx);
+        QCOMPARE(QMetaType::type("CustomType"), idx);
+        QVERIFY(QMetaType::isRegistered(idx));
+    }
+    QCOMPARE(instanceCount, 3);
+}
+
+QDataStream &operator<<(QDataStream &stream, const CustomType &ct)
+{
+    stream << ct.i1 << ct.i2 << ct.i3;
+    return stream;
+}
+
+QDataStream &operator>>(QDataStream &stream, CustomType &ct)
+{
+    stream >> ct.i1;
+    stream >> ct.i2;
+    stream >> ct.i3;
+    return stream;
+}
+
+void tst_QObject::streamCustomTypes()
+{
+    QByteArray ba;
+
+    int idx = qRegisterMetaType<CustomType>("CustomType");
+    qRegisterMetaTypeStreamOperators<CustomType>("CustomType");
+
+    {
+        CustomType t1(1, 2, 3);
+        QCOMPARE(instanceCount, 1);
+        QDataStream stream(&ba, (QIODevice::OpenMode)QIODevice::WriteOnly);
+        QMetaType::save(stream, idx, &t1);
+    }
+
+    QCOMPARE(instanceCount, 0);
+
+    {
+        CustomType t2;
+        QCOMPARE(instanceCount, 1);
+        QDataStream stream(&ba, (QIODevice::OpenMode)QIODevice::ReadOnly);
+        QMetaType::load(stream, idx, &t2);
+        QCOMPARE(instanceCount, 1);
+        QCOMPARE(t2.i1, 1);
+        QCOMPARE(t2.i2, 2);
+        QCOMPARE(t2.i3, 3);
+    }
+    QCOMPARE(instanceCount, 0);
+}
+
+typedef QString CustomString;
+
+class PropertyObject : public QObject
+{
+    Q_OBJECT
+    Q_ENUMS(Alpha Priority)
+
+    Q_PROPERTY(Alpha alpha READ alpha WRITE setAlpha)
+    Q_PROPERTY(Priority priority READ priority WRITE setPriority)
+    Q_PROPERTY(int number READ number WRITE setNumber)
+    Q_PROPERTY(QString string READ string WRITE setString)
+    Q_PROPERTY(QVariant variant READ variant WRITE setVariant)
+    Q_PROPERTY(CustomType* custom READ custom WRITE setCustom)
+    Q_PROPERTY(float myFloat READ myFloat WRITE setMyFloat)
+    Q_PROPERTY(qreal myQReal READ myQReal WRITE setMyQReal)
+    Q_PROPERTY(CustomString customString READ customString WRITE setCustomString )
+
+public:
+    enum Alpha {
+        Alpha0,
+        Alpha1,
+        Alpha2
+    };
+
+    enum Priority { High, Low, VeryHigh, VeryLow };
+
+    PropertyObject()
+        : m_alpha(Alpha0), m_priority(High), m_number(0), m_custom(0), m_float(42)
+    {}
+
+    Alpha alpha() const { return m_alpha; }
+    void setAlpha(Alpha alpha) { m_alpha = alpha; }
+
+    Priority priority() const { return m_priority; }
+    void setPriority(Priority priority) { m_priority = priority; }
+
+    int number() const { return m_number; }
+    void setNumber(int number) { m_number = number; }
+
+    QString string() const { return m_string; }
+    void setString(const QString &string) { m_string = string; }
+
+    QVariant variant() const { return m_variant; }
+    void setVariant(const QVariant &variant) { m_variant = variant; }
+
+    CustomType *custom() const { return m_custom; }
+    void setCustom(CustomType *custom) { m_custom = custom; }
+
+    void setMyFloat(float value) { m_float = value; }
+    inline float myFloat() const { return m_float; }
+
+    void setMyQReal(qreal value) { m_qreal = value; }
+    qreal myQReal() const { return m_qreal; }
+
+    CustomString customString() const { return m_customString; }
+    void setCustomString(const QString &string) { m_customString = string; }
+
+private:
+    Alpha m_alpha;
+    Priority m_priority;
+    int m_number;
+    QString m_string;
+    QVariant m_variant;
+    CustomType *m_custom;
+    float m_float;
+    qreal m_qreal;
+    CustomString m_customString;
+};
+
+Q_DECLARE_METATYPE(PropertyObject::Priority)
+
+void tst_QObject::threadSignalEmissionCrash()
+{
+    int loopCount = 1000;
+    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::moveToThread()
+{
+    QThread *currentThread = QThread::currentThread();
+
+    {
+        QObject *object = new QObject;
+        QObject *child = new QObject(object);
+        QThread* otherthread = new QThread();
+        QVERIFY(otherthread != object->thread());
+        QCOMPARE(object->thread(), currentThread);
+        QCOMPARE(child->thread(), currentThread);
+        object->moveToThread(otherthread);
+        QCOMPARE(object->thread(), otherthread);
+        QCOMPARE(child->thread(), otherthread);
+        delete object;
+        delete otherthread;
+    }
+
+    {
+        MoveToThreadThread thread;
+        thread.start();
+
+        QObject *object = new QObject;
+        QObject *child = new QObject(object);
+        QPointer<QObject> opointer = object;
+        QPointer<QObject> cpointer = object;
+
+        QCOMPARE(object->thread(), currentThread);
+        QCOMPARE(child->thread(), currentThread);
+        object->moveToThread(&thread);
+        QCOMPARE(object->thread(), (QThread *)&thread);
+        QCOMPARE(child->thread(), (QThread *)&thread);
+
+        connect(object, SIGNAL(destroyed()), &thread, SLOT(quit()), Qt::DirectConnection);
+        QMetaObject::invokeMethod(object, "deleteLater", Qt::QueuedConnection);
+        thread.wait();
+
+        QVERIFY(opointer == 0);
+        QVERIFY(cpointer == 0);
+    }
+
+    {
+        // make sure posted events are moved with the object
+        MoveToThreadThread thread;
+        thread.start();
+
+        MoveToThreadObject *object = new MoveToThreadObject;
+        MoveToThreadObject *child = new MoveToThreadObject(object);
+
+        connect(object, SIGNAL(theSignal()), &thread, SLOT(quit()), Qt::DirectConnection);
+        QCoreApplication::postEvent(child, new QEvent(QEvent::User));
+        QCoreApplication::postEvent(object, new QEvent(QEvent::User));
+
+        QCOMPARE(object->thread(), currentThread);
+        QCOMPARE(child->thread(), currentThread);
+        object->moveToThread(&thread);
+        QCOMPARE(object->thread(), (QThread *)&thread);
+        QCOMPARE(child->thread(), (QThread *)&thread);
+
+        thread.wait();
+
+        QCOMPARE(object->customEventThread, (QThread *)&thread);
+        QCOMPARE(child->customEventThread, (QThread *)&thread);
+
+        thread.start();
+        connect(object, SIGNAL(destroyed()), &thread, SLOT(quit()), Qt::DirectConnection);
+        QMetaObject::invokeMethod(object, "deleteLater", Qt::QueuedConnection);
+        thread.wait();
+    }
+
+    {
+        // make sure timers are moved with the object
+        MoveToThreadThread thread;
+        thread.start();
+
+        MoveToThreadObject *object = new MoveToThreadObject;
+        MoveToThreadObject *child = new MoveToThreadObject(object);
+
+        connect(object, SIGNAL(theSignal()), &thread, SLOT(quit()), Qt::DirectConnection);
+
+        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 = qvariant_cast<CustomType *>(customVariant);
+    QCOMPARE(customPointer, object.custom());
+
+    CustomType custom;
+    customPointer = &custom;
+    qVariantSetValue(customVariant, customPointer);
+
+    property = mo->property(mo->indexOfProperty("custom"));
+    QVERIFY(property.isWritable());
+    QCOMPARE(property.typeName(), "CustomType*");
+    QCOMPARE(property.type(), QVariant::UserType);
+
+    QVERIFY(object.setProperty("custom", customVariant));
+    QCOMPARE(object.custom(), customPointer);
+
+    customVariant = object.property("custom");
+    customPointer = qvariant_cast<CustomType *>(customVariant);
+    QCOMPARE(object.custom(), customPointer);
+
+    // this enum property has a meta type, but it's not yet registered, so we know this fails
+    QVERIFY(mo->indexOfProperty("priority") != -1);
+    property = mo->property(mo->indexOfProperty("priority"));
+    QVERIFY(property.isEnumType());
+    QCOMPARE(property.typeName(), "Priority");
+    QCOMPARE(property.type(), QVariant::Int);
+
+    var = object.property("priority");
+    QVERIFY(!var.isNull());
+    QCOMPARE(var.toInt(), int(PropertyObject::High));
+    object.setPriority(PropertyObject::Low);
+    QCOMPARE(object.property("priority").toInt(), int(PropertyObject::Low));
+    QVERIFY(object.setProperty("priority", PropertyObject::VeryHigh));
+    QCOMPARE(object.property("priority").toInt(), int(PropertyObject::VeryHigh));
+    QVERIFY(object.setProperty("priority", "High"));
+    QCOMPARE(object.property("priority").toInt(), int(PropertyObject::High));
+    QVERIFY(!object.setProperty("priority", QVariant()));
+
+    // now it's registered, so it works as expected
+    int priorityMetaTypeId = qRegisterMetaType<PropertyObject::Priority>("PropertyObject::Priority");
+
+    QVERIFY(mo->indexOfProperty("priority") != -1);
+    property = mo->property(mo->indexOfProperty("priority"));
+    QVERIFY(property.isEnumType());
+    QCOMPARE(property.typeName(), "Priority");
+    QCOMPARE(property.type(), QVariant::UserType);
+    QCOMPARE(property.userType(), priorityMetaTypeId);
+
+    var = object.property("priority");
+    QVERIFY(!var.isNull());
+    QVERIFY(var.canConvert<PropertyObject::Priority>());
+    QCOMPARE(qvariant_cast<PropertyObject::Priority>(var), PropertyObject::High);
+    object.setPriority(PropertyObject::Low);
+    QCOMPARE(qvariant_cast<PropertyObject::Priority>(object.property("priority")), PropertyObject::Low);
+    QVERIFY(object.setProperty("priority", PropertyObject::VeryHigh));
+    QCOMPARE(qvariant_cast<PropertyObject::Priority>(object.property("priority")), PropertyObject::VeryHigh);
+    QVERIFY(object.setProperty("priority", "High"));
+    QCOMPARE(qvariant_cast<PropertyObject::Priority>(object.property("priority")), PropertyObject::High);
+    QVERIFY(!object.setProperty("priority", QVariant()));
+
+    var = object.property("priority");
+    QCOMPARE(qvariant_cast<PropertyObject::Priority>(var), PropertyObject::High);
+    object.setPriority(PropertyObject::Low);
+    QCOMPARE(qvariant_cast<PropertyObject::Priority>(object.property("priority")), PropertyObject::Low);
+    object.setProperty("priority", var);
+    QCOMPARE(qvariant_cast<PropertyObject::Priority>(object.property("priority")), PropertyObject::High);
+
+    qRegisterMetaType<CustomString>("CustomString");
+    QVERIFY(mo->indexOfProperty("customString") != -1);
+    QCOMPARE(object.property("customString").toString(), QString());
+    object.setCustomString("String1");
+    QCOMPARE(object.property("customString"), QVariant("String1"));
+    QVERIFY(object.setProperty("customString", "String2"));
+    QCOMPARE(object.property("customString"), QVariant("String2"));
+    QVERIFY(!object.setProperty("customString", QVariant()));
+}
+
+void tst_QObject::metamethod()
+{
+    SenderObject obj;
+    const QMetaObject *mobj = obj.metaObject();
+    QMetaMethod m;
+
+    m = mobj->method(mobj->indexOfMethod("invoke1()"));
+    QVERIFY(QByteArray(m.signature()) == "invoke1()");
+    QVERIFY(m.methodType() == QMetaMethod::Method);
+    QVERIFY(m.access() == QMetaMethod::Public);
+    QVERIFY(!(m.attributes() & QMetaMethod::Scriptable));
+
+    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));
+
+    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));
+
+    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));
+
+    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));
+
+    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));
+
+    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));
+
+    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));
+
+    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;
+    };
+}
+
+Q_DECLARE_INTERFACE(Foo::Bar, "com.qtest.foobar")
+
+#define Bleh_iid "com.qtest.bleh"
+Q_DECLARE_INTERFACE(Foo::Bleh, Bleh_iid)
+
+class FooObject: public QObject, public Foo::Bar
+{
+    Q_OBJECT
+    Q_INTERFACES(Foo::Bar)
+public:
+    int rtti() const { return 42; }
+};
+
+class BlehObject : public QObject, public Foo::Bleh
+{
+    Q_OBJECT
+    Q_INTERFACES(Foo::Bleh)
+public:
+    int rtti() const { return 43; }
+};
+
+void tst_QObject::declareInterface()
+{
+    FooObject obj;
+
+    Foo::Bar *bar = qobject_cast<Foo::Bar *>(&obj);
+    QVERIFY(bar);
+    QCOMPARE(bar->rtti(), 42);
+    QCOMPARE(static_cast<Foo::Bar *>(&obj), bar);
+
+    BlehObject bleh;
+
+    bar = qobject_cast<Foo::Bar *>(&bleh);
+    QVERIFY(!bar);
+    Foo::Bleh *b = qobject_cast<Foo::Bleh *>(&bleh);
+    QCOMPARE(b->rtti(), 43);
+    QCOMPARE(static_cast<Foo::Bleh *>(&bleh), b);
+
+}
+
+class DestroyedListener : public QObject
+{
+    Q_OBJECT
+public:
+    inline DestroyedListener() : pointerWasZero(false) {}
+
+    QPointer<QObject> pointer;
+    bool pointerWasZero;
+
+private slots:
+    inline void otherObjectDestroyed()
+    { pointerWasZero = pointer.isNull(); }
+};
+
+void tst_QObject::qpointerResetBeforeDestroyedSignal()
+{
+    QObject *obj = new QObject;
+    DestroyedListener listener;
+    listener.pointer = obj;
+    listener.pointerWasZero = false;
+    connect(obj, SIGNAL(destroyed()), &listener, SLOT(otherObjectDestroyed()));
+    delete obj;
+    QVERIFY(listener.pointerWasZero);
+    QVERIFY(listener.pointer.isNull());
+}
+
+class DefaultArguments : public QObject
+{
+    Q_OBJECT
+
+public slots:
+
+    void theSlot(const QString &s) { result = s; }
+
+signals:
+    void theOriginalSignal();
+    void theSecondSignal(const QString &s = QString("secondDefault"));
+
+public:
+
+    void emitTheOriginalSignal() { emit theOriginalSignal(); }
+    void emitTheSecondSignal() { emit theSecondSignal(); }
+    QString result;
+};
+
+void tst_QObject::connectSignalsToSignalsWithDefaultArguments()
+{
+    DefaultArguments o;
+    connect(&o, SIGNAL(theOriginalSignal()), &o, SIGNAL(theSecondSignal()));
+    connect(&o, SIGNAL(theSecondSignal(QString)), &o, SLOT(theSlot(QString)));
+    QVERIFY( o.result.isEmpty() );
+    o.emitTheSecondSignal();
+    QCOMPARE(o.result, QString("secondDefault"));
+    o.result = "Not called";
+    o.emitTheOriginalSignal();
+    QCOMPARE(o.result, QString("secondDefault"));
+
+}
+
+void tst_QObject::receivers()
+{
+    class Object : public QObject
+    {
+    public:
+        int receivers(const char* signal) const
+        { return QObject::receivers(signal); }
+    };
+
+    Object object;
+    QCOMPARE(object.receivers(SIGNAL(destroyed())), 0);
+    object.connect(&object, SIGNAL(destroyed()), SLOT(deleteLater()));
+    QCOMPARE(object.receivers(SIGNAL(destroyed())), 1);
+    object.connect(&object, SIGNAL(destroyed()), SLOT(deleteLater()));
+    QCOMPARE(object.receivers(SIGNAL(destroyed())), 2);
+    object.disconnect(SIGNAL(destroyed()), &object, SLOT(deleteLater()));
+    QCOMPARE(object.receivers(SIGNAL(destroyed())), 0);
+}
+
+enum Enum { };
+
+struct Struct { };
+class Class { };
+template <typename T> class Template { };
+
+class NormalizeObject : public QObject
+{
+    Q_OBJECT
+
+public:
+
+signals:
+    void uintPointerSignal(uint *);
+    void ulongPointerSignal(ulong *);
+    void constUintPointerSignal(const uint *);
+    void constUlongPointerSignal(const ulong *);
+
+    void structSignal(Struct s);
+    void classSignal(Class c);
+    void enumSignal(Enum e);
+
+    void structPointerSignal(Struct *s);
+    void classPointerSignal(Class *c);
+    void enumPointerSignal(Enum *e);
+
+    void constStructPointerSignal(const Struct *s);
+    void constClassPointerSignal(const Class *c);
+    void constEnumPointerSignal(const Enum *e);
+
+    void constStructPointerConstPointerSignal(const Struct * const *s);
+    void constClassPointerConstPointerSignal(const Class * const *c);
+    void constEnumPointerConstPointerSignal(const Enum * const *e);
+
+    void unsignedintSignal(unsigned int);
+    void unsignedSignal(unsigned);
+    void unsignedlongSignal(unsigned long);
+    void unsignedlonglongSignal(quint64);
+    void unsignedlongintSignal(unsigned long int);
+    void unsignedshortSignal(unsigned short);
+    void unsignedcharSignal(unsigned char);
+
+    void typeRefSignal(Template<Class &> &ref);
+    void constTypeRefSignal(const Template<Class const &> &ref);
+    void typeConstRefSignal(Template<Class const &> const &ref);
+
+    void typePointerConstRefSignal(Class * const &);
+
+    void constTemplateSignal1( Template<int > );
+    void constTemplateSignal2( Template< const int >);
+
+public slots:
+    void uintPointerSlot(uint *) { }
+    void ulongPointerSlot(ulong *) { }
+    void constUintPointerSlot(const uint *) { }
+    void constUlongPointerSlot(const ulong *) { }
+
+    void structSlot(Struct s) { Q_UNUSED(s); }
+    void classSlot(Class c) { Q_UNUSED(c); }
+    void enumSlot(Enum e) { Q_UNUSED(e); }
+
+    void structPointerSlot(Struct *s) { Q_UNUSED(s); }
+    void classPointerSlot(Class *c) { Q_UNUSED(c); }
+    void enumPointerSlot(Enum *e) { Q_UNUSED(e); }
+
+    void constStructPointerSlot(const Struct *s) { Q_UNUSED(s); }
+    void constClassPointerSlot(const Class *c) { Q_UNUSED(c); }
+    void constEnumPointerSlot(const Enum *e) { Q_UNUSED(e); }
+
+    void constStructPointerConstPointerSlot(const Struct * const *s) { Q_UNUSED(s); }
+    void constClassPointerConstPointerSlot(const Class * const *c) { Q_UNUSED(c); }
+    void constEnumPointerConstPointerSlot(const Enum * const *e) { Q_UNUSED(e); }
+
+    void uintSlot(uint) {};
+    void unsignedintSlot(unsigned int) {};
+    void unsignedSlot(unsigned) {};
+    void unsignedlongSlot(unsigned long) {};
+    void unsignedlonglongSlot(quint64) {};
+    void unsignedlongintSlot(unsigned long int) {};
+    void unsignedshortSlot(unsigned short) {};
+    void unsignedcharSlot(unsigned char) {};
+
+    void typeRefSlot(Template<Class &> &) {}
+    void constTypeRefSlot(const Template<const Class &> &) {}
+    void typeConstRefSlot(Template<Class const &> const &) {}
+
+    void typePointerConstRefSlot(Class * const &) {}
+
+    void constTemplateSlot1(Template<int > const) {}
+    void constTemplateSlot2(const Template<int > ) {}
+    void constTemplateSlot3(const Template< const int >) {}
+};
+
+void tst_QObject::normalize()
+{
+    NormalizeObject object;
+
+    // unsigned int -> uint, unsigned long -> ulong
+    QVERIFY(object.connect(&object,
+                           SIGNAL(uintPointerSignal(uint *)),
+                           SLOT(uintPointerSlot(uint *))));
+    QVERIFY(object.connect(&object,
+                           SIGNAL(uintPointerSignal(unsigned int *)),
+                           SLOT(uintPointerSlot(uint *))));
+    QVERIFY(object.connect(&object,
+                           SIGNAL(uintPointerSignal(uint *)),
+                           SLOT(uintPointerSlot(unsigned int *))));
+
+    QVERIFY(object.connect(&object,
+                           SIGNAL(constUintPointerSignal(const uint *)),
+                           SLOT(constUintPointerSlot(const uint *))));
+    QVERIFY(object.connect(&object,
+                           SIGNAL(constUintPointerSignal(const unsigned int *)),
+                           SLOT(constUintPointerSlot(const uint *))));
+    QVERIFY(object.connect(&object,
+                           SIGNAL(constUintPointerSignal(const uint *)),
+                           SLOT(constUintPointerSlot(const unsigned int *))));
+
+    QVERIFY(object.connect(&object,
+                           SIGNAL(ulongPointerSignal(ulong *)),
+                           SLOT(ulongPointerSlot(ulong *))));
+    QVERIFY(object.connect(&object,
+                           SIGNAL(ulongPointerSignal(unsigned long *)),
+                           SLOT(ulongPointerSlot(ulong *))));
+    QVERIFY(object.connect(&object,
+                           SIGNAL(ulongPointerSignal(ulong *)),
+                           SLOT(ulongPointerSlot(unsigned long *))));
+
+    QVERIFY(object.connect(&object,
+                           SIGNAL(constUlongPointerSignal(const ulong *)),
+                           SLOT(constUlongPointerSlot(const ulong *))));
+    QVERIFY(object.connect(&object,
+                           SIGNAL(constUlongPointerSignal(const unsigned long *)),
+                           SLOT(constUlongPointerSlot(const ulong *))));
+    QVERIFY(object.connect(&object,
+                           SIGNAL(constUlongPointerSignal(const ulong *)),
+                           SLOT(constUlongPointerSlot(const unsigned long *))));
+
+    // struct, class, and enum are optional
+    QVERIFY(object.connect(&object,
+                           SIGNAL(structSignal(struct Struct)),
+                           SLOT(structSlot(struct Struct))));
+    QVERIFY(object.connect(&object,
+                           SIGNAL(structSignal(Struct)),
+                           SLOT(structSlot(struct Struct))));
+    QVERIFY(object.connect(&object,
+                           SIGNAL(structSignal(struct Struct)),
+                           SLOT(structSlot(Struct))));
+    QVERIFY(object.connect(&object,
+                           SIGNAL(classSignal(class Class)),
+                           SLOT(classSlot(class Class))));
+    QVERIFY(object.connect(&object,
+                           SIGNAL(classSignal(Class)),
+                           SLOT(classSlot(class Class))));
+    QVERIFY(object.connect(&object,
+                           SIGNAL(classSignal(class Class)),
+                           SLOT(classSlot(Class))));
+    QVERIFY(object.connect(&object,
+                           SIGNAL(enumSignal(enum Enum)),
+                           SLOT(enumSlot(enum Enum))));
+    QVERIFY(object.connect(&object,
+                           SIGNAL(enumSignal(Enum)),
+                           SLOT(enumSlot(enum Enum))));
+    QVERIFY(object.connect(&object,
+                           SIGNAL(enumSignal(enum Enum)),
+                           SLOT(enumSlot(Enum))));
+
+    QVERIFY(object.connect(&object,
+                           SIGNAL(structPointerSignal(struct Struct *)),
+                           SLOT(structPointerSlot(struct Struct *))));
+    QVERIFY(object.connect(&object,
+                           SIGNAL(structPointerSignal(Struct *)),
+                           SLOT(structPointerSlot(struct Struct *))));
+    QVERIFY(object.connect(&object,
+                           SIGNAL(structPointerSignal(struct Struct *)),
+                           SLOT(structPointerSlot(Struct *))));
+    QVERIFY(object.connect(&object,
+                           SIGNAL(classPointerSignal(class Class *)),
+                           SLOT(classPointerSlot(class Class *))));
+    QVERIFY(object.connect(&object,
+                           SIGNAL(classPointerSignal(Class *)),
+                           SLOT(classPointerSlot(class Class *))));
+    QVERIFY(object.connect(&object,
+                           SIGNAL(classPointerSignal(class Class *)),
+                           SLOT(classPointerSlot(Class *))));
+    QVERIFY(object.connect(&object,
+                           SIGNAL(enumPointerSignal(enum Enum *)),
+                           SLOT(enumPointerSlot(enum Enum *))));
+    QVERIFY(object.connect(&object,
+                           SIGNAL(enumPointerSignal(Enum *)),
+                           SLOT(enumPointerSlot(enum Enum *))));
+    QVERIFY(object.connect(&object,
+                           SIGNAL(enumPointerSignal(enum Enum *)),
+                           SLOT(enumPointerSlot(Enum *))));
+
+    QVERIFY(object.connect(&object,
+                           SIGNAL(constStructPointerSignal(const struct Struct *)),
+                           SLOT(constStructPointerSlot(const struct Struct *))));
+    QVERIFY(object.connect(&object,
+                           SIGNAL(constStructPointerSignal(const Struct *)),
+                           SLOT(constStructPointerSlot(const struct Struct *))));
+    QVERIFY(object.connect(&object,
+                           SIGNAL(constStructPointerSignal(const struct Struct *)),
+                           SLOT(constStructPointerSlot(const Struct *))));
+    QVERIFY(object.connect(&object,
+                           SIGNAL(constClassPointerSignal(const class Class *)),
+                           SLOT(constClassPointerSlot(const class Class *))));
+    QVERIFY(object.connect(&object,
+                           SIGNAL(constClassPointerSignal(const Class *)),
+                           SLOT(constClassPointerSlot(const class Class *))));
+    QVERIFY(object.connect(&object,
+                           SIGNAL(constClassPointerSignal(const class Class *)),
+                           SLOT(constClassPointerSlot(const Class *))));
+    QVERIFY(object.connect(&object,
+                           SIGNAL(constEnumPointerSignal(const enum Enum *)),
+                           SLOT(constEnumPointerSlot(const enum Enum *))));
+    QVERIFY(object.connect(&object,
+                           SIGNAL(constEnumPointerSignal(const Enum *)),
+                           SLOT(constEnumPointerSlot(const enum Enum *))));
+    QVERIFY(object.connect(&object,
+                           SIGNAL(constEnumPointerSignal(const enum Enum *)),
+                           SLOT(constEnumPointerSlot(const Enum *))));
+
+    QVERIFY(object.connect(&object,
+                           SIGNAL(constStructPointerSignal(struct Struct const *)),
+                           SLOT(constStructPointerSlot(struct Struct const *))));
+    QVERIFY(object.connect(&object,
+                           SIGNAL(constStructPointerSignal(Struct const *)),
+                           SLOT(constStructPointerSlot(struct Struct const *))));
+    QVERIFY(object.connect(&object,
+                           SIGNAL(constStructPointerSignal(struct Struct const *)),
+                           SLOT(constStructPointerSlot(Struct const *))));
+    QVERIFY(object.connect(&object,
+                           SIGNAL(constClassPointerSignal(class Class const *)),
+                           SLOT(constClassPointerSlot(class Class const *))));
+    QVERIFY(object.connect(&object,
+                           SIGNAL(constClassPointerSignal(Class const *)),
+                           SLOT(constClassPointerSlot(class Class const *))));
+    QVERIFY(object.connect(&object,
+                           SIGNAL(constClassPointerSignal(class Class const *)),
+                           SLOT(constClassPointerSlot(Class const *))));
+    QVERIFY(object.connect(&object,
+                           SIGNAL(constEnumPointerSignal(enum Enum const *)),
+                           SLOT(constEnumPointerSlot(enum Enum const *))));
+    QVERIFY(object.connect(&object,
+                           SIGNAL(constEnumPointerSignal(Enum const *)),
+                           SLOT(constEnumPointerSlot(enum Enum const *))));
+    QVERIFY(object.connect(&object,
+                           SIGNAL(constEnumPointerSignal(enum Enum const *)),
+                           SLOT(constEnumPointerSlot(Enum const *))));
+
+    QVERIFY(object.connect(&object,
+                           SIGNAL(constStructPointerConstPointerSignal(const struct Struct * const *)),
+                           SLOT(constStructPointerConstPointerSlot(const struct Struct * const *))));
+    QVERIFY(object.connect(&object,
+                           SIGNAL(constStructPointerConstPointerSignal(const Struct * const *)),
+                           SLOT(constStructPointerConstPointerSlot(const struct Struct * const *))));
+    QVERIFY(object.connect(&object,
+                           SIGNAL(constStructPointerConstPointerSignal(const struct Struct * const *)),
+                           SLOT(constStructPointerConstPointerSlot(const Struct * const *))));
+    QVERIFY(object.connect(&object,
+                           SIGNAL(constClassPointerConstPointerSignal(const class Class * const *)),
+                           SLOT(constClassPointerConstPointerSlot(const class Class * const *))));
+    QVERIFY(object.connect(&object,
+                           SIGNAL(constClassPointerConstPointerSignal(const Class * const *)),
+                           SLOT(constClassPointerConstPointerSlot(const class Class * const *))));
+    QVERIFY(object.connect(&object,
+                           SIGNAL(constClassPointerConstPointerSignal(const class Class * const *)),
+                           SLOT(constClassPointerConstPointerSlot(const Class * const *))));
+    QVERIFY(object.connect(&object,
+                           SIGNAL(constEnumPointerConstPointerSignal(const enum Enum * const *)),
+                           SLOT(constEnumPointerConstPointerSlot(const enum Enum * const *))));
+    QVERIFY(object.connect(&object,
+                           SIGNAL(constEnumPointerConstPointerSignal(const Enum * const *)),
+                           SLOT(constEnumPointerConstPointerSlot(const enum Enum * const *))));
+    QVERIFY(object.connect(&object,
+                           SIGNAL(constEnumPointerConstPointerSignal(const enum Enum * const *)),
+                           SLOT(constEnumPointerConstPointerSlot(const Enum * const *))));
+
+    QVERIFY(object.connect(&object,
+                           SIGNAL(constStructPointerConstPointerSignal(struct Struct const * const *)),
+                           SLOT(constStructPointerConstPointerSlot(struct Struct const * const *))));
+    QVERIFY(object.connect(&object,
+                           SIGNAL(constStructPointerConstPointerSignal(Struct const * const *)),
+                           SLOT(constStructPointerConstPointerSlot(struct Struct const * const *))));
+    QVERIFY(object.connect(&object,
+                           SIGNAL(constStructPointerConstPointerSignal(struct Struct const * const *)),
+                           SLOT(constStructPointerConstPointerSlot(Struct const * const *))));
+    QVERIFY(object.connect(&object,
+                           SIGNAL(constClassPointerConstPointerSignal(class Class const * const *)),
+                           SLOT(constClassPointerConstPointerSlot(class Class const * const *))));
+    QVERIFY(object.connect(&object,
+                           SIGNAL(constClassPointerConstPointerSignal(Class const * const *)),
+                           SLOT(constClassPointerConstPointerSlot(class Class const * const *))));
+    QVERIFY(object.connect(&object,
+                           SIGNAL(constClassPointerConstPointerSignal(class Class const * const *)),
+                           SLOT(constClassPointerConstPointerSlot(Class const * const *))));
+    QVERIFY(object.connect(&object,
+                           SIGNAL(constEnumPointerConstPointerSignal(enum Enum const * const *)),
+                           SLOT(constEnumPointerConstPointerSlot(enum Enum const * const *))));
+    QVERIFY(object.connect(&object,
+                           SIGNAL(constEnumPointerConstPointerSignal(Enum const * const *)),
+                           SLOT(constEnumPointerConstPointerSlot(enum Enum const * const *))));
+    QVERIFY(object.connect(&object,
+                           SIGNAL(constEnumPointerConstPointerSignal(enum Enum const * const *)),
+                           SLOT(constEnumPointerConstPointerSlot(Enum const * const *))));
+
+    QVERIFY(object.connect(&object,
+                           SIGNAL(unsignedintSignal(unsigned int)),
+                           SLOT(unsignedintSlot(unsigned int))));
+    QVERIFY(object.connect(&object,
+                           SIGNAL(unsignedSignal(unsigned)),
+                           SLOT(unsignedSlot(unsigned))));
+    QVERIFY(object.connect(&object,
+                           SIGNAL(unsignedSignal(unsigned)),
+                           SLOT(uintSlot(uint))));
+    QVERIFY(object.connect(&object,
+                           SIGNAL(unsignedlongSignal(unsigned long)),
+                           SLOT(unsignedlongSlot(unsigned long))));
+    QVERIFY(object.connect(&object,
+                           SIGNAL(unsignedlonglongSignal(quint64)),
+                           SLOT(unsignedlonglongSlot(quint64))));
+    QVERIFY(object.connect(&object,
+                           SIGNAL(unsignedlongintSignal(unsigned long int)),
+                           SLOT(unsignedlongintSlot(unsigned long int))));
+    QVERIFY(object.connect(&object,
+                           SIGNAL(unsignedshortSignal(unsigned short)),
+                           SLOT(unsignedshortSlot(unsigned short))));
+    QVERIFY(object.connect(&object,
+                           SIGNAL(unsignedcharSignal(unsigned char)),
+                           SLOT(unsignedcharSlot(unsigned char))));
+
+    // connect when original template signature and mixed usage of 'T<C const &> const &',
+    // 'const T<const C &> &', and 'T<const C &>'
+
+    QVERIFY(object.connect(&object,
+                           SIGNAL(typeRefSignal(Template<Class &> &)),
+                           SLOT(typeRefSlot(Template<Class &> &))));
+
+    QVERIFY(object.connect(&object,
+                           SIGNAL(constTypeRefSignal(const Template<const Class &> &)),
+                           SLOT(constTypeRefSlot(const Template<const Class &> &))));
+    QVERIFY(object.connect(&object,
+                           SIGNAL(constTypeRefSignal(const Template<const Class &> &)),
+                           SLOT(constTypeRefSlot(const Template<Class const &> &))));
+    QVERIFY(object.connect(&object,
+                           SIGNAL(constTypeRefSignal(const Template<const Class &> &)),
+                           SLOT(constTypeRefSlot(Template<Class const &> const &))));
+    QVERIFY(object.connect(&object,
+                           SIGNAL(constTypeRefSignal(Template<const Class &> const &)),
+                           SLOT(constTypeRefSlot(Template<Class const &> const &))));
+    QVERIFY(object.connect(&object,
+                           SIGNAL(constTypeRefSignal(Template<Class const &> const &)),
+                           SLOT(constTypeRefSlot(Template<Class const &> const &))));
+
+    QVERIFY(object.connect(&object,
+                           SIGNAL(constTypeRefSignal(const Template<const Class &> &)),
+                           SLOT(typeConstRefSlot(const Template<const Class &> &))));
+    QVERIFY(object.connect(&object,
+                           SIGNAL(constTypeRefSignal(const Template<const Class &> &)),
+                           SLOT(typeConstRefSlot(const Template<Class const &> &))));
+    QVERIFY(object.connect(&object,
+                           SIGNAL(constTypeRefSignal(const Template<const Class &> &)),
+                           SLOT(typeConstRefSlot(Template<Class const &> const &))));
+    QVERIFY(object.connect(&object,
+                           SIGNAL(constTypeRefSignal(Template<const Class &> const &)),
+                           SLOT(typeConstRefSlot(Template<Class const &> const &))));
+    QVERIFY(object.connect(&object,
+                           SIGNAL(constTypeRefSignal(Template<Class const &> const &)),
+                           SLOT(typeConstRefSlot(Template<Class const &> const &))));
+
+    QVERIFY(object.connect(&object,
+                           SIGNAL(typeConstRefSignal(const Template<const Class &> &)),
+                           SLOT(constTypeRefSlot(const Template<const Class &> &))));
+    QVERIFY(object.connect(&object,
+                           SIGNAL(typeConstRefSignal(const Template<const Class &> &)),
+                           SLOT(constTypeRefSlot(const Template<Class const &> &))));
+    QVERIFY(object.connect(&object,
+                           SIGNAL(typeConstRefSignal(const Template<const Class &> &)),
+                           SLOT(constTypeRefSlot(Template<Class const &> const &))));
+    QVERIFY(object.connect(&object,
+                           SIGNAL(typeConstRefSignal(Template<const Class &> const &)),
+                           SLOT(constTypeRefSlot(Template<Class const &> const &))));
+    QVERIFY(object.connect(&object,
+                           SIGNAL(typeConstRefSignal(Template<Class const &> const &)),
+                           SLOT(constTypeRefSlot(Template<Class const &> const &))));
+
+    QVERIFY(object.connect(&object,
+                           SIGNAL(typeConstRefSignal(const Template<const Class &> &)),
+                           SLOT(typeConstRefSlot(const Template<const Class &> &))));
+    QVERIFY(object.connect(&object,
+                           SIGNAL(typeConstRefSignal(const Template<const Class &> &)),
+                           SLOT(typeConstRefSlot(const Template<Class const &> &))));
+    QVERIFY(object.connect(&object,
+                           SIGNAL(typeConstRefSignal(const Template<const Class &> &)),
+                           SLOT(typeConstRefSlot(Template<Class const &> const &))));
+    QVERIFY(object.connect(&object,
+                           SIGNAL(typeConstRefSignal(Template<const Class &> const &)),
+                           SLOT(typeConstRefSlot(Template<Class const &> const &))));
+    QVERIFY(object.connect(&object,
+                           SIGNAL(typeConstRefSignal(Template<Class const &> const &)),
+                           SLOT(typeConstRefSlot(Template<Class const &> const &))));
+}
+
+class SiblingDeleter : public QObject
+{
+public:
+    inline SiblingDeleter(QObject *sibling, QObject *parent)
+        : QObject(parent), sibling(sibling) {}
+    inline virtual ~SiblingDeleter() { delete sibling; }
+
+private:
+    QPointer<QObject> sibling;
+};
+
+
+void tst_QObject::childDeletesItsSibling()
+{
+    QObject *commonParent = new QObject(0);
+    QPointer<QObject> child = new QObject(0);
+    QPointer<QObject> siblingDeleter = new SiblingDeleter(child, commonParent);
+    child->setParent(commonParent);
+    delete commonParent; // don't crash
+    QVERIFY(!child);
+    QVERIFY(!siblingDeleter);
+}
+
+void tst_QObject::floatProperty()
+{
+    PropertyObject obj;
+    const int idx = obj.metaObject()->indexOfProperty("myFloat");
+    QVERIFY(idx > 0);
+    QMetaProperty prop = obj.metaObject()->property(idx);
+    QVERIFY(prop.isValid());
+    QVERIFY(prop.type() == uint(QMetaType::type("float")));
+    QVERIFY(!prop.write(&obj, QVariant("Hello")));
+    QVERIFY(prop.write(&obj, qVariantFromValue(128.0f)));
+    QVariant v = prop.read(&obj);
+    QVERIFY(int(v.userType()) == QMetaType::Float);
+    QVERIFY(qvariant_cast<float>(v) == 128.0f);
+}
+
+void tst_QObject::qrealProperty()
+{
+    PropertyObject obj;
+    const int idx = obj.metaObject()->indexOfProperty("myQReal");
+    QVERIFY(idx > 0);
+    QMetaProperty prop = obj.metaObject()->property(idx);
+    QVERIFY(prop.isValid());
+    QVERIFY(prop.type() == uint(QMetaType::type("qreal")));
+    QVERIFY(!prop.write(&obj, QVariant("Hello")));
+
+    QVERIFY(prop.write(&obj, qVariantFromValue(128.0f)));
+    QVariant v = prop.read(&obj);
+    QCOMPARE(v.userType(), qMetaTypeId<qreal>());
+    QVERIFY(qvariant_cast<qreal>(v) == 128.0);
+
+    QVERIFY(prop.write(&obj, qVariantFromValue(double(127))));
+    v = prop.read(&obj);
+    QCOMPARE(v.userType(), qMetaTypeId<qreal>());
+    QVERIFY(qvariant_cast<qreal>(v) == 127.0);
+}
+
+class DynamicPropertyObject : public PropertyObject
+{
+public:
+    inline DynamicPropertyObject() {}
+
+    inline virtual bool event(QEvent *e) {
+        if (e->type() == QEvent::DynamicPropertyChange) {
+            changedDynamicProperties.append(static_cast<QDynamicPropertyChangeEvent *>(e)->propertyName());
+        }
+        return QObject::event(e);
+    }
+
+    QList<QByteArray> changedDynamicProperties;
+};
+
+void tst_QObject::dynamicProperties()
+{
+    DynamicPropertyObject obj;
+
+    QVERIFY(obj.dynamicPropertyNames().isEmpty());
+
+    QVERIFY(obj.setProperty("number", 42));
+    QVERIFY(obj.changedDynamicProperties.isEmpty());
+    QCOMPARE(obj.property("number").toInt(), 42);
+
+    QVERIFY(!obj.setProperty("number", "invalid string"));
+    QVERIFY(obj.changedDynamicProperties.isEmpty());
+
+    QVERIFY(!obj.setProperty("myuserproperty", "Hello"));
+    QCOMPARE(obj.changedDynamicProperties.count(), 1);
+    QCOMPARE(obj.changedDynamicProperties.first(), QByteArray("myuserproperty"));
+    obj.changedDynamicProperties.clear();
+
+    QCOMPARE(obj.property("myuserproperty").toString(), QString("Hello"));
+
+    QCOMPARE(obj.dynamicPropertyNames().count(), 1);
+    QCOMPARE(obj.dynamicPropertyNames().first(), QByteArray("myuserproperty"));
+
+    QVERIFY(!obj.setProperty("myuserproperty", QVariant()));
+
+    QCOMPARE(obj.changedDynamicProperties.count(), 1);
+    QCOMPARE(obj.changedDynamicProperties.first(), QByteArray("myuserproperty"));
+    obj.changedDynamicProperties.clear();
+
+    QVERIFY(obj.property("myuserproperty").isNull());
+
+    QVERIFY(obj.dynamicPropertyNames().isEmpty());
+}
+
+void tst_QObject::recursiveSignalEmission()
+{
+    QProcess proc;
+    proc.start("./signalbug");
+    QVERIFY(proc.waitForFinished());
+    QVERIFY(proc.exitStatus() == QProcess::NormalExit);
+    QCOMPARE(proc.exitCode(), 0);
+}
+
+void tst_QObject::blockingQueuedConnection()
+{
+    {
+        SenderObject sender;
+
+        MoveToThreadThread thread;
+        ReceiverObject receiver;
+        receiver.moveToThread(&thread);
+        thread.start();
+
+        receiver.connect(&sender, SIGNAL(signal1()), SLOT(slot1()), Qt::BlockingQueuedConnection);
+        sender.emitSignal1();
+        QVERIFY(receiver.called(1));
+
+        receiver.reset();
+        QVERIFY(QMetaObject::invokeMethod(&receiver, "slot1", Qt::BlockingQueuedConnection));
+        QVERIFY(receiver.called(1));
+
+        thread.quit();
+        QVERIFY(thread.wait());
+    }
+}
+
+class EventSpy : public QObject
+{
+    Q_OBJECT
+
+public:
+    typedef QList<QPair<QObject *, QEvent::Type> > EventList;
+
+    EventSpy(QObject *parent = 0)
+        : QObject(parent)
+    { }
+
+    EventList eventList()
+    {
+        return events;
+    }
+
+    void clear()
+    {
+        events.clear();
+    }
+
+    bool eventFilter(QObject *object, QEvent *event)
+    {
+        events.append(qMakePair(object, event->type()));
+        return false;
+    }
+
+private:
+    EventList events;
+};
+
+void tst_QObject::compatibilityChildInsertedEvents()
+{
+    EventSpy::EventList expected;
+
+    {
+        // no children created, so we expect no events
+        QObject object;
+        EventSpy spy;
+        object.installEventFilter(&spy);
+
+        QCoreApplication::postEvent(&object, new QEvent(QEvent::Type(QEvent::User + 1)));
+
+        QCoreApplication::processEvents();
+
+        expected =
+            EventSpy::EventList()
+            << qMakePair(&object, QEvent::Type(QEvent::User + 1));
+        QCOMPARE(spy.eventList(), expected);
+    }
+
+    {
+        // 2 children, so we expect 2 ChildAdded and 2 ChildInserted events
+        QObject object;
+        EventSpy spy;
+        object.installEventFilter(&spy);
+
+        QCoreApplication::postEvent(&object, new QEvent(QEvent::Type(QEvent::User + 1)));
+
+        QObject child1(&object);
+        QObject child2;
+        child2.setParent(&object);
+
+        QCoreApplication::postEvent(&object, new QEvent(QEvent::Type(QEvent::User + 2)));
+
+        expected =
+            EventSpy::EventList()
+            << qMakePair(&object, QEvent::ChildAdded)
+            << qMakePair(&object, QEvent::ChildAdded);
+        QCOMPARE(spy.eventList(), expected);
+        spy.clear();
+
+        QCoreApplication::processEvents();
+
+        expected =
+            EventSpy::EventList()
+            << 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);
+
+    QThread* otherthread = new QThread();
+    QVERIFY(otherthread != object.thread());
+
+    // nothing special, should just work
+    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(otherthread);
+    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());
+
+    delete otherthread;
+}
+
+class EmitThread : public QThread
+{
+   Q_OBJECT
+public:
+    void run(void) {
+        emit work();
+    }
+signals:
+    void work();
+};
+
+class DeleteObject : public QObject
+{
+    Q_OBJECT
+
+public slots:
+    void deleteSelf()
+    {
+        delete this;
+    }
+
+    void relaySignalAndProcessEvents()
+    {
+        emit relayedSignal();
+        QCoreApplication::processEvents();
+    }
+
+signals:
+    void relayedSignal();
+};
+
+void tst_QObject::deleteSelfInSlot()
+{
+    {
+        SenderObject sender;
+        DeleteObject *receiver = new DeleteObject();
+        receiver->connect(&sender,
+                          SIGNAL(signal1()),
+                          SLOT(deleteSelf()),
+                          Qt::BlockingQueuedConnection);
+
+        QThread thread;
+        receiver->moveToThread(&thread);
+        thread.connect(receiver, SIGNAL(destroyed()), SLOT(quit()), Qt::DirectConnection);
+        thread.start();
+
+        QPointer<DeleteObject> p = receiver;
+        sender.emitSignal1();
+        QVERIFY(p.isNull());
+
+        QVERIFY(thread.wait(10000));
+    }
+
+    {
+        SenderObject sender;
+        DeleteObject *receiver = new DeleteObject();
+        receiver->connect(&sender,
+                          SIGNAL(signal1()),
+                          SLOT(relaySignalAndProcessEvents()),
+                          Qt::BlockingQueuedConnection);
+        receiver->connect(receiver,
+                          SIGNAL(relayedSignal()),
+                          SLOT(deleteSelf()),
+                          Qt::QueuedConnection);
+
+        QThread thread;
+        receiver->moveToThread(&thread);
+        thread.connect(receiver, SIGNAL(destroyed()), SLOT(quit()), Qt::DirectConnection);
+        thread.start();
+
+        QPointer<DeleteObject> p = receiver;
+        sender.emitSignal1();
+        QVERIFY(p.isNull());
+
+        QVERIFY(thread.wait(10000));
+    }
+
+    {
+        EmitThread sender;
+        DeleteObject *receiver = new DeleteObject();
+        connect(&sender, SIGNAL(work()), receiver, SLOT(deleteSelf()), Qt::DirectConnection);
+        QPointer<DeleteObject> p = receiver;
+        sender.start();
+        QVERIFY(sender.wait(10000));
+        QVERIFY(p.isNull());
+    }
+}
+
+class DisconnectObject : public QObject
+{
+    Q_OBJECT
+
+public slots:
+    void disconnectSelf()
+    {
+        disconnect(sender(), 0, this, 0);
+    }
+
+    void relaySignalAndProcessEvents()
+    {
+        emit relayedSignal();
+        QCoreApplication::processEvents();
+    }
+
+signals:
+    void relayedSignal();
+};
+
+void tst_QObject::disconnectSelfInSlotAndDeleteAfterEmit()
+{
+    {
+        SenderObject sender;
+        DisconnectObject *receiver = new DisconnectObject();
+        receiver->connect(&sender, SIGNAL(signal1()), SLOT(disconnectSelf()));
+        sender.emitSignal1AfterRecursion();
+        delete receiver;
+    }
+
+    {
+        SenderObject sender;
+        DisconnectObject *receiver = new DisconnectObject();
+        receiver->connect(&sender,
+                          SIGNAL(signal1()),
+                          SLOT(disconnectSelf()),
+                          Qt::BlockingQueuedConnection);
+
+        QThread thread;
+        receiver->moveToThread(&thread);
+        thread.connect(receiver, SIGNAL(destroyed()), SLOT(quit()), Qt::DirectConnection);
+        thread.start();
+
+        QPointer<DisconnectObject> p = receiver;
+        sender.emitSignal1();
+        QVERIFY(!p.isNull());
+
+        receiver->deleteLater();
+
+        QVERIFY(thread.wait(10000));
+        QVERIFY(p.isNull());
+    }
+
+    {
+        SenderObject sender;
+        DisconnectObject *receiver = new DisconnectObject();
+        receiver->connect(&sender,
+                          SIGNAL(signal1()),
+                          SLOT(relaySignalAndProcessEvents()),
+                          Qt::BlockingQueuedConnection);
+        receiver->connect(receiver,
+                          SIGNAL(relayedSignal()),
+                          SLOT(disconnectSelf()),
+                          Qt::QueuedConnection);
+
+        QThread thread;
+        receiver->moveToThread(&thread);
+        thread.connect(receiver, SIGNAL(destroyed()), SLOT(quit()), Qt::DirectConnection);
+        thread.start();
+
+        QPointer<DisconnectObject> p = receiver;
+        sender.emitSignal1();
+        QVERIFY(!p.isNull());
+
+        receiver->deleteLater();
+
+        QVERIFY(thread.wait(10000));
+        QVERIFY(p.isNull());
+    }
+}
+
+void tst_QObject::dumpObjectInfo()
+{
+    QObject a, b;
+    QObject::connect(&a, SIGNAL(destroyed(QObject *)), &b, SLOT(deleteLater()));
+    a.disconnect(&b);
+    a.dumpObjectInfo(); // should not crash
+}
+
+class ConnectToSender : public QObject
+{
+    Q_OBJECT
+public slots:
+    void uselessSlot() { count++; }
+
+    void harmfullSlot() {
+        //this used to crash
+        connect(sender(), SIGNAL(signal4()), this, SLOT(uselessSlot()));
+        //play a little bit with the memory in order to really get a segfault.
+        connect(sender(), SIGNAL(signal1()), this, SLOT(uselessSlot()));
+        QList<double>() << 45 << 78 << 65 << 121 << 45 << 78 << 12;
+    }
+public:
+    int count;
+};
+
+void tst_QObject::connectToSender()
+{
+    SenderObject s;
+    ConnectToSender r;
+    r.count = 0;
+    QObject::connect(&s, SIGNAL(signal1()), &r, SLOT(harmfullSlot()));
+    QObject::connect(&s, SIGNAL(signal1()), &r, SLOT(uselessSlot()));
+
+    s.emitSignal1();
+
+    QCOMPARE(r.count, 1);
+    s.emitSignal4();
+    QCOMPARE(r.count, 2);
+}
+
+void tst_QObject::qobjectConstCast()
+{
+    FooObject obj;
+
+    QObject *ptr = &obj;
+    const QObject *cptr = &obj;
+
+    QVERIFY(qobject_cast<FooObject *>(ptr));
+    QVERIFY(qobject_cast<const FooObject *>(cptr));
+}
+
+void tst_QObject::uniqConnection()
+{
+    SenderObject *s = new SenderObject;
+    ReceiverObject *r1 = new ReceiverObject;
+    ReceiverObject *r2 = new ReceiverObject;
+    r1->reset();
+    r2->reset();
+    ReceiverObject::sequence = 0;
+
+    QVERIFY( connect( s, SIGNAL( signal1() ), r1, SLOT( slot1() ) , Qt::UniqueConnection) );
+    QVERIFY( connect( s, SIGNAL( signal1() ), r2, SLOT( slot1() ) , Qt::UniqueConnection) );
+    QVERIFY( connect( s, SIGNAL( signal1() ), r1, SLOT( slot3() ) , Qt::UniqueConnection) );
+    QVERIFY( connect( s, SIGNAL( signal3() ), r1, SLOT( slot3() ) , Qt::UniqueConnection) );
+
+    s->emitSignal1();
+    s->emitSignal2();
+    s->emitSignal3();
+    s->emitSignal4();
+
+    QCOMPARE( r1->count_slot1, 1 );
+    QCOMPARE( r1->count_slot2, 0 );
+    QCOMPARE( r1->count_slot3, 2 );
+    QCOMPARE( r1->count_slot4, 0 );
+    QCOMPARE( r2->count_slot1, 1 );
+    QCOMPARE( r2->count_slot2, 0 );
+    QCOMPARE( r2->count_slot3, 0 );
+    QCOMPARE( r2->count_slot4, 0 );
+    QCOMPARE( r1->sequence_slot1, 1 );
+    QCOMPARE( r2->sequence_slot1, 2 );
+    QCOMPARE( r1->sequence_slot3, 4 );
+
+    r1->reset();
+    r2->reset();
+    ReceiverObject::sequence = 0;
+
+    QVERIFY( connect( s, SIGNAL( signal4() ), r1, SLOT( slot4() ) , Qt::UniqueConnection) );
+    QVERIFY( connect( s, SIGNAL( signal4() ), r2, SLOT( slot4() ) , Qt::UniqueConnection) );
+    QVERIFY(!connect( s, SIGNAL( signal4() ), r2, SLOT( slot4() ) , Qt::UniqueConnection) );
+    QVERIFY( connect( s, SIGNAL( signal1() ), r2, SLOT( slot4() ) , Qt::UniqueConnection) );
+    QVERIFY(!connect( s, SIGNAL( signal4() ), r1, SLOT( slot4() ) , Qt::UniqueConnection) );
+
+    s->emitSignal4();
+    QCOMPARE( r1->count_slot4, 1 );
+    QCOMPARE( r2->count_slot4, 1 );
+    QCOMPARE( r1->sequence_slot4, 1 );
+    QCOMPARE( r2->sequence_slot4, 2 );
+
+    r1->reset();
+    r2->reset();
+    ReceiverObject::sequence = 0;
+
+    connect( s, SIGNAL( signal4() ), r1, SLOT( slot4() ) );
+
+    s->emitSignal4();
+    QCOMPARE( r1->count_slot4, 2 );
+    QCOMPARE( r2->count_slot4, 1 );
+    QCOMPARE( r1->sequence_slot4, 3 );
+    QCOMPARE( r2->sequence_slot4, 2 );
+
+    delete s;
+    delete r1;
+    delete r2;
+}
+
+void tst_QObject::interfaceIid()
+{
+    QCOMPARE(QByteArray(qobject_interface_iid<Foo::Bleh *>()),
+             QByteArray(Bleh_iid));
+    QCOMPARE(QByteArray(qobject_interface_iid<Foo::Bar *>()),
+             QByteArray("com.qtest.foobar"));
+    QCOMPARE(QByteArray(qobject_interface_iid<FooObject *>()),
+             QByteArray());
+}
+
+void tst_QObject::deleteQObjectWhenDeletingEvent()
+{
+    //this is related to task 259514
+    //before the fix this used to dead lock when the QObject from the event was destroyed
+
+    struct MyEvent : public QEvent
+    {
+        MyEvent() : QEvent(QEvent::User) { }
+        QObject obj;
+    };
+
+    QObject o;
+    QApplication::postEvent(&o, new MyEvent);
+    QCoreApplication::removePostedEvents(&o); // here you would get a deadlock
+}
+
+class OverloadObject : public QObject
+{
+    friend class tst_QObject;
+    Q_OBJECT
+signals:
+    void sig(int i, char c, qreal m = 12);
+    void sig(int i, int j = 12);
+    void sig(QObject *o, QObject *p, QObject *q = 0, QObject *r = 0) const;
+    void other(int a = 0);
+    void sig(QObject *o, OverloadObject *p = 0, QObject *q = 0, QObject *r = 0);
+    void sig(double r = 0.5);
+public slots:
+    void slo(int i, int j = 43)
+    {
+        s_num += 1;
+        i1_num = i;
+        i2_num = j;
+    }
+    void slo(QObject *o, QObject *p = qApp, QObject *q = qApp, QObject *r = qApp)
+    {
+        s_num += 10;
+        o1_obj = o;
+        o2_obj = p;
+        o3_obj = q;
+        o4_obj = r;
+    }
+    void slo()
+    {
+        s_num += 100;
+    }
+
+public:
+    int s_num;
+    int i1_num;
+    int i2_num;
+    QObject *o1_obj;
+    QObject *o2_obj;
+    QObject *o3_obj;
+    QObject *o4_obj;
+};
+
+void tst_QObject::overloads()
+{
+    OverloadObject obj1;
+    OverloadObject obj2;
+    QObject obj3;
+    obj1.s_num = 0;
+    obj2.s_num = 0;
+
+    connect (&obj1, SIGNAL(sig(int)) , &obj1, SLOT(slo(int)));
+    connect (&obj1, SIGNAL(sig(QObject *, QObject *, QObject *)) , &obj1, SLOT(slo(QObject * , QObject *, QObject *)));
+
+    connect (&obj1, SIGNAL(sig(QObject *, QObject *, QObject *, QObject *)) , &obj2, SLOT(slo(QObject * , QObject *, QObject *)));
+    connect (&obj1, SIGNAL(sig(QObject *)) , &obj2, SLOT(slo()));
+    connect (&obj1, SIGNAL(sig(int, int)) , &obj2, SLOT(slo(int, int)));
+
+    emit obj1.sig(0.5); //connected to nothing
+    emit obj1.sig(1, 'a'); //connected to nothing
+    QCOMPARE(obj1.s_num, 0);
+    QCOMPARE(obj2.s_num, 0);
+
+    emit obj1.sig(1); //this signal is connected
+    QCOMPARE(obj1.s_num, 1);
+    QCOMPARE(obj1.i1_num, 1);
+    QCOMPARE(obj1.i2_num, 43); //default argument of the slot
+
+    QCOMPARE(obj2.s_num, 1);
+    QCOMPARE(obj2.i1_num, 1);
+    QCOMPARE(obj2.i2_num, 12); //default argument of the signal
+
+
+    emit obj1.sig(&obj2); //this signal is conencted to obj2
+    QCOMPARE(obj1.s_num, 1);
+    QCOMPARE(obj2.s_num, 101);
+    emit obj1.sig(&obj2, &obj3); //this signal is connected
+    QCOMPARE(obj1.s_num, 11);
+    QCOMPARE(obj1.o1_obj, (QObject *)&obj2);
+    QCOMPARE(obj1.o2_obj, &obj3);
+    QCOMPARE(obj1.o3_obj, (QObject *)0); //default arg of the signal
+    QCOMPARE(obj1.o4_obj, (QObject *)qApp); //default arg of the slot
+
+    QCOMPARE(obj2.s_num, 111);
+    QCOMPARE(obj2.o1_obj, (QObject *)&obj2);
+    QCOMPARE(obj2.o2_obj, &obj3);
+    QCOMPARE(obj2.o3_obj, (QObject *)0); //default arg of the signal
+    QCOMPARE(obj2.o4_obj, (QObject *)qApp); //default arg of the slot
+}
+
+class ManySignals : public QObject
+{   Q_OBJECT
+    friend class tst_QObject;
+signals:
+    void sig00(); void sig01(); void sig02(); void sig03(); void sig04();
+    void sig05(); void sig06(); void sig07(); void sig08(); void sig09();
+    void sig10(); void sig11(); void sig12(); void sig13(); void sig14();
+    void sig15(); void sig16(); void sig17(); void sig18(); void sig19();
+    void sig20(); void sig21(); void sig22(); void sig23(); void sig24();
+    void sig25(); void sig26(); void sig27(); void sig28(); void sig29();
+    void sig30(); void sig31(); void sig32(); void sig33(); void sig34();
+    void sig35(); void sig36(); void sig37(); void sig38(); void sig39();
+    void sig40(); void sig41(); void sig42(); void sig43(); void sig44();
+    void sig45(); void sig46(); void sig47(); void sig48(); void sig49();
+    void sig50(); void sig51(); void sig52(); void sig53(); void sig54();
+    void sig55(); void sig56(); void sig57(); void sig58(); void sig59();
+    void sig60(); void sig61(); void sig62(); void sig63(); void sig64();
+    void sig65(); void sig66(); void sig67(); void sig68(); void sig69();
+
+public slots:
+    void received() { rec++; }
+public:
+    int rec;
+};
+
+
+void tst_QObject::isSignalConnected()
+{
+    ManySignals o;
+    o.rec = 0;
+    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()")));
+
+    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()));
+
+    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()")));
+
+    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()));
+
+    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()")));
+
+    QCOMPARE(o.rec, 0);
+    emit o.sig01();
+    emit o.sig34();
+    QCOMPARE(o.rec, 0);
+
+    QObject::connect(&o, SIGNAL(sig27()), &o, SLOT(received()));
+
+    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()")));
+
+    emit o.sig00();
+    QCOMPARE(o.rec, 1);
+    emit o.sig69();
+    QCOMPARE(o.rec, 2);
+    emit o.sig36();
+    QCOMPARE(o.rec, 2);
+}
+
+void tst_QObject::qMetaObjectConnect()
+{
+    SenderObject *s = new SenderObject;
+    ReceiverObject *r1 = new ReceiverObject;
+    ReceiverObject *r2 = new ReceiverObject;
+    r1->reset();
+    r2->reset();
+    ReceiverObject::sequence = 0;
+
+    int signal1Index = s->metaObject()->indexOfSignal("signal1()");
+    int signal3Index = s->metaObject()->indexOfSignal("signal3()");
+    int slot1Index = r1->metaObject()->indexOfSlot("slot1()");
+    int slot2Index = r1->metaObject()->indexOfSlot("slot2()");
+    int slot3Index = r1->metaObject()->indexOfSlot("slot3()");
+
+    QVERIFY(slot1Index > 0);
+    QVERIFY(slot2Index > 0);
+    QVERIFY(slot3Index > 0);
+
+    QVERIFY( QMetaObject::connect( s, signal1Index, r1, slot1Index) );
+    QVERIFY( QMetaObject::connect( s, signal3Index, r2, slot3Index) );
+    QVERIFY( QMetaObject::connect( s, -1, r2, slot2Index) );
+
+    QCOMPARE( r1->count_slot1, 0 );
+    QCOMPARE( r1->count_slot2, 0 );
+    QCOMPARE( r1->count_slot3, 0 );
+    QCOMPARE( r2->count_slot1, 0 );
+    QCOMPARE( r2->count_slot2, 0 );
+    QCOMPARE( r2->count_slot3, 0 );
+
+    s->emitSignal1();
+
+    QCOMPARE( r1->count_slot1, 1 );
+    QCOMPARE( r1->count_slot2, 0 );
+    QCOMPARE( r1->count_slot3, 0 );
+    QCOMPARE( r2->count_slot1, 0 );
+    QCOMPARE( r2->count_slot2, 1 );
+    QCOMPARE( r2->count_slot3, 0 );
+
+    s->emitSignal2();
+    s->emitSignal3();
+    s->emitSignal4();
+
+    QCOMPARE( r1->count_slot1, 1 );
+    QCOMPARE( r1->count_slot2, 0 );
+    QCOMPARE( r1->count_slot3, 0 );
+    QCOMPARE( r2->count_slot1, 0 );
+    QCOMPARE( r2->count_slot2, 4 );
+    QCOMPARE( r2->count_slot3, 1 );
+
+    QVERIFY( QMetaObject::disconnect( s, signal1Index, r1, slot1Index) );
+    QVERIFY( QMetaObject::disconnect( s, signal3Index, r2, slot3Index) );
+    QVERIFY( QMetaObject::disconnect( s, -1, r2, slot2Index) );
+
+    s->emitSignal1();
+    s->emitSignal2();
+    s->emitSignal3();
+    s->emitSignal4();
+
+    QCOMPARE( r1->count_slot1, 1 );
+    QCOMPARE( r1->count_slot2, 0 );
+    QCOMPARE( r1->count_slot3, 0 );
+    QCOMPARE( r2->count_slot1, 0 );
+    QCOMPARE( r2->count_slot2, 4 );
+    QCOMPARE( r2->count_slot3, 1 );
+
+    //some "dynamic" signal
+    QVERIFY( QMetaObject::connect( s, s->metaObject()->methodOffset() + 20, r1, slot3Index) );
+    QVERIFY( QMetaObject::connect( s, s->metaObject()->methodOffset() + 35, r2, slot1Index) );
+    QVERIFY( QMetaObject::connect( s, -1, r1, slot2Index) );
+
+    r1->reset();
+    r2->reset();
+
+    void *args[] = { 0 , 0 };
+    QMetaObject::activate(s, s->metaObject()->methodOffset() + 20, args);
+    QMetaObject::activate(s, s->metaObject()->methodOffset() + 48, args);
+    QCOMPARE( r1->count_slot1, 0 );
+    QCOMPARE( r1->count_slot2, 2 );
+    QCOMPARE( r1->count_slot3, 1 );
+    QCOMPARE( r2->count_slot1, 0 );
+    QCOMPARE( r2->count_slot2, 0 );
+    QCOMPARE( r2->count_slot3, 0 );
+
+    QMetaObject::activate(s, s->metaObject()->methodOffset() + 35, args);
+    s->emitSignal1();
+    s->emitSignal2();
+
+    QCOMPARE( r1->count_slot1, 0 );
+    QCOMPARE( r1->count_slot2, 5 );
+    QCOMPARE( r1->count_slot3, 1 );
+    QCOMPARE( r2->count_slot1, 1 );
+    QCOMPARE( r2->count_slot2, 0 );
+    QCOMPARE( r2->count_slot3, 0 );
+
+    delete s;
+    r1->reset();
+    r2->reset();
+
+#define SIGNAL_INDEX(S)  obj1.metaObject()->indexOfSignal(QMetaObject::normalizedSignature(#S))
+    OverloadObject obj1;
+    QObject obj2, obj3;
+
+    QMetaObject::connect(&obj1, SIGNAL_INDEX(sig(int)) , r1, slot1Index);
+    QMetaObject::connect(&obj1, SIGNAL_INDEX(sig(QObject *, QObject *, QObject *)) , r2, slot1Index);
+
+    QMetaObject::connect(&obj1, SIGNAL_INDEX(sig(QObject *, QObject *, QObject *, QObject *)) , r1, slot2Index);
+    QMetaObject::connect(&obj1, SIGNAL_INDEX(sig(QObject *)) , r2, slot2Index);
+    QMetaObject::connect(&obj1, SIGNAL_INDEX(sig(int, int)) , r1, slot3Index);
+
+    emit obj1.sig(0.5); //connected to nothing
+    emit obj1.sig(1, 'a'); //connected to nothing
+    QCOMPARE( r1->count_slot1, 0 );
+    QCOMPARE( r1->count_slot2, 0 );
+    QCOMPARE( r1->count_slot3, 0 );
+    QCOMPARE( r2->count_slot1, 0 );
+    QCOMPARE( r2->count_slot2, 0 );
+    QCOMPARE( r2->count_slot3, 0 );
+
+    emit obj1.sig(1); //this signal is connected
+    emit obj1.sig(&obj2);
+
+    QCOMPARE( r1->count_slot1, 1 );
+    QCOMPARE( r1->count_slot2, 0 );
+    QCOMPARE( r1->count_slot3, 1 );
+    QCOMPARE( r2->count_slot1, 0 );
+    QCOMPARE( r2->count_slot2, 1 );
+    QCOMPARE( r2->count_slot3, 0 );
+
+    emit obj1.sig(&obj2, &obj3); //this signal is connected
+
+    QCOMPARE( r1->count_slot1, 1 );
+    QCOMPARE( r1->count_slot2, 1 );
+    QCOMPARE( r1->count_slot3, 1 );
+    QCOMPARE( r2->count_slot1, 1 );
+    QCOMPARE( r2->count_slot2, 1 );
+    QCOMPARE( r2->count_slot3, 0 );
+
+    delete r1;
+    delete r2;
+
+}
+
+void tst_QObject::qMetaObjectDisconnectOne()
+{
+    SenderObject *s = new SenderObject;
+    ReceiverObject *r1 = new ReceiverObject;
+
+    int signal1Index = s->metaObject()->indexOfSignal("signal1()");
+    int signal3Index = s->metaObject()->indexOfSignal("signal3()");
+    int slot1Index = r1->metaObject()->indexOfSlot("slot1()");
+    int slot2Index = r1->metaObject()->indexOfSlot("slot2()");
+
+    QVERIFY(signal1Index > 0);
+    QVERIFY(signal3Index > 0);
+    QVERIFY(slot1Index > 0);
+    QVERIFY(slot2Index > 0);
+
+    QVERIFY( QMetaObject::connect(s, signal1Index, r1, slot1Index) );
+    QVERIFY( QMetaObject::connect(s, signal3Index, r1, slot2Index) );
+    QVERIFY( QMetaObject::connect(s, signal3Index, r1, slot2Index) );
+    QVERIFY( QMetaObject::connect(s, signal3Index, r1, slot2Index) );
+
+    r1->reset();
+    QCOMPARE( r1->count_slot1, 0 );
+    QCOMPARE( r1->count_slot2, 0 );
+
+    s->emitSignal1();
+    QCOMPARE( r1->count_slot1, 1 );
+    QCOMPARE( r1->count_slot2, 0 );
+
+    s->emitSignal3();
+    QCOMPARE( r1->count_slot1, 1 );
+    QCOMPARE( r1->count_slot2, 3 );
+
+    r1->reset();
+    QVERIFY( QMetaObject::disconnectOne(s, signal1Index, r1, slot1Index) );
+    QVERIFY( QMetaObject::disconnectOne(s, signal3Index, r1, slot2Index) );
+
+    s->emitSignal1();
+    QCOMPARE( r1->count_slot1, 0 );
+    QCOMPARE( r1->count_slot2, 0 );
+
+    s->emitSignal3();
+    QCOMPARE( r1->count_slot1, 0 );
+    QCOMPARE( r1->count_slot2, 2 );
+
+    r1->reset();
+    QVERIFY( false == QMetaObject::disconnectOne(s, signal1Index, r1, slot1Index) );
+    QVERIFY( QMetaObject::disconnectOne(s, signal3Index, r1, slot2Index) );
+
+    s->emitSignal1();
+    QCOMPARE( r1->count_slot1, 0 );
+    QCOMPARE( r1->count_slot2, 0 );
+
+    s->emitSignal3();
+    QCOMPARE( r1->count_slot1, 0 );
+    QCOMPARE( r1->count_slot2, 1 );
+
+    r1->reset();
+    QVERIFY( false == QMetaObject::disconnectOne(s, signal1Index, r1, slot1Index) );
+    QVERIFY( QMetaObject::disconnectOne(s, signal3Index, r1, slot2Index) );
+
+    s->emitSignal1();
+    QCOMPARE( r1->count_slot1, 0 );
+    QCOMPARE( r1->count_slot2, 0 );
+
+    s->emitSignal3();
+    QCOMPARE( r1->count_slot1, 0 );
+    QCOMPARE( r1->count_slot2, 0 );
+
+    delete s;
+    delete r1;
+}
+
+class ConfusingObject : public SenderObject
+{
+    Q_OBJECT
+public slots:
+    void signal1() { s++; }
+signals:
+    void aPublicSlot();
+public:
+    int s;
+    ConfusingObject() : s(0) {}
+    friend class tst_QObject;
+};
+
+void tst_QObject::sameName()
+{
+    ConfusingObject c1, c2;
+    QVERIFY(connect(&c1, SIGNAL(signal1()), &c1, SLOT(signal1())));
+    c1.emitSignal1();
+    QCOMPARE(c1.s, 1);
+
+    QVERIFY(connect(&c2, SIGNAL(signal1()), &c1, SIGNAL(signal1())));
+    c2.emitSignal1();
+    QCOMPARE(c1.s, 2);
+
+    QVERIFY(connect(&c2, SIGNAL(aPublicSlot()), &c1, SLOT(signal1())));
+    c2.aPublicSlot();
+    QCOMPARE(c2.aPublicSlotCalled, 0);
+    QCOMPARE(c1.aPublicSlotCalled, 0);
+    QCOMPARE(c1.s, 3);
+
+    QVERIFY(connect(&c2, SIGNAL(aPublicSlot()), &c1, SLOT(aPublicSlot())));
+    c2.aPublicSlot();
+    QCOMPARE(c2.aPublicSlotCalled, 0);
+    QCOMPARE(c1.aPublicSlotCalled, 1);
+    QCOMPARE(c1.s, 4);
+}
+
+void tst_QObject::connectByMetaMethods()
+{
+    SenderObject s;
+    ReceiverObject r;
+    const QMetaObject *smeta = s.metaObject();
+    const QMetaObject *rmeta = r.metaObject();
+    int sigIndx = smeta->indexOfSignal(QMetaObject::normalizedSignature("signal1()"));
+    int slotIndx = rmeta->indexOfSlot(QMetaObject::normalizedSignature("slot1()"));
+    QVERIFY( sigIndx != -1 );
+    QVERIFY( slotIndx != -1 );
+    QMetaMethod signal = smeta->method(sigIndx);
+    QMetaMethod slot = rmeta->method(slotIndx);
+
+    QVERIFY(connect(&s,signal, &r,slot));
+
+    QVERIFY(!r.called(1));
+    s.emitSignal1();
+    QVERIFY(r.called(1));
+}
+
+void tst_QObject::connectByMetaMethodSlotInsteadOfSignal()
+{
+    SenderObject s;
+    ReceiverObject r;
+    const QMetaObject *smeta = s.metaObject();
+    const QMetaObject *rmeta = r.metaObject();
+    int badIndx = smeta->indexOfSlot(QMetaObject::normalizedSignature("aPublicSlot()"));
+    int slotIndx = rmeta->indexOfSlot(QMetaObject::normalizedSignature("slot1()"));
+    QVERIFY( badIndx != -1 );
+    QVERIFY( slotIndx != -1 );
+    QMetaMethod badMethod = smeta->method(badIndx);
+    QMetaMethod slot = rmeta->method(slotIndx);
+
+    QTest::ignoreMessage(QtWarningMsg,"QObject::connect: Cannot connect SenderObject::aPublicSlot() to ReceiverObject::slot1()");
+    QVERIFY(!connect(&s,badMethod, &r,slot));
+}
+
+class Constructable: public QObject
+{
+    Q_OBJECT
+
+public:
+    Q_INVOKABLE Constructable(){}
+
+};
+
+void tst_QObject::connectConstructorByMetaMethod()
+{
+    Constructable sc;
+    Constructable rc;
+    SenderObject s;
+    ReceiverObject r;
+
+    const QMetaObject cmeta = Constructable::staticMetaObject;
+    const QMetaObject *smeta = s.metaObject();
+    const QMetaObject *rmeta = r.metaObject();
+    int constructorIndx = cmeta.indexOfConstructor(QMetaObject::normalizedSignature("Constructable()"));
+    int sigIndx = smeta->indexOfSignal(QMetaObject::normalizedSignature("signal1()"));
+    int slotIndx = rmeta->indexOfSlot(QMetaObject::normalizedSignature("slot1()"));
+    QVERIFY( constructorIndx != -1 );
+    QVERIFY( sigIndx != -1 );
+    QVERIFY( slotIndx != -1 );
+
+    QMetaMethod constructor = cmeta.constructor(constructorIndx);
+    QMetaMethod signal = smeta->method(sigIndx);
+    QMetaMethod slot = rmeta->method(slotIndx);
+
+    QTest::ignoreMessage(QtWarningMsg,"QObject::connect: Cannot connect Constructable::Constructable() to ReceiverObject::slot1()");
+    QVERIFY(!connect(&sc,constructor, &r,slot));
+    QTest::ignoreMessage(QtWarningMsg,"QObject::connect: Cannot connect SenderObject::signal1() to Constructable::Constructable()");
+    QVERIFY(!connect(&s,signal, &rc,constructor));
+    QTest::ignoreMessage(QtWarningMsg,"QObject::connect: Cannot connect Constructable::Constructable() to Constructable::Constructable()");
+    QVERIFY(!connect(&sc,constructor, &rc,constructor));
+}
+
+void tst_QObject::disconnectByMetaMethod()
+{
+    SenderObject *s = new SenderObject;
+    ReceiverObject *r1 = new ReceiverObject;
+    ReceiverObject *r2 = new ReceiverObject;
+
+    QMetaMethod signal1 = s->metaObject()->method(
+            s->metaObject()->indexOfMethod("signal1()"));
+    QMetaMethod signal2 = s->metaObject()->method(
+            s->metaObject()->indexOfMethod("signal2()"));
+    QMetaMethod signal3 = s->metaObject()->method(
+            s->metaObject()->indexOfMethod("signal3()"));
+    QMetaMethod signal4 = s->metaObject()->method(
+            s->metaObject()->indexOfMethod("signal4()"));
+
+    QMetaMethod slot1 = r1->metaObject()->method(
+            r1->metaObject()->indexOfMethod("slot1()"));
+    QMetaMethod slot2 = r1->metaObject()->method(
+            r1->metaObject()->indexOfMethod("slot2()"));
+    QMetaMethod slot3 = r1->metaObject()->method(
+            r1->metaObject()->indexOfMethod("slot3()"));
+    QMetaMethod slot4 = r1->metaObject()->method(
+            r1->metaObject()->indexOfMethod("slot4()"));
+
+    connect(s, signal1, r1, slot1);
+
+    s->emitSignal1();
+
+    QVERIFY(r1->called(1));
+    r1->reset();
+
+    // usual disconnect with all parameters given
+    bool ret = QObject::disconnect(s, signal1, r1, slot1);
+
+    s->emitSignal1();
+
+    QVERIFY(!r1->called(1));
+    r1->reset();
+
+    QVERIFY(ret);
+    ret = QObject::disconnect(s, signal1, r1, slot1);
+    QVERIFY(!ret);
+
+    r1->reset();
+
+    connect( s, signal1, r1, slot1 );
+    connect( s, signal1, r1, slot2 );
+    connect( s, signal1, r1, slot3 );
+    connect( s, signal2, r1, slot4 );
+
+    // disconnect s's signal1() from all slots of r1
+    QObject::disconnect(s, signal1, r1, QMetaMethod());
+
+    s->emitSignal1();
+    s->emitSignal2();
+
+    QVERIFY(!r1->called(1));
+    QVERIFY(!r1->called(2));
+    QVERIFY(!r1->called(3));
+    QVERIFY(r1->called(4));
+    r1->reset();
+    // make sure all is disconnected again
+    QObject::disconnect(s, 0, r1, 0);
+
+    connect(s, signal1, r1, slot1);
+    connect(s, signal1, r2, slot1);
+    connect(s, signal2, r1, slot2);
+    connect(s, signal2, r2, slot2);
+    connect(s, signal3, r1, slot3);
+    connect(s, signal3, r2, slot3);
+
+    // disconnect signal1() from all receivers
+    QObject::disconnect(s, signal1, 0, QMetaMethod());
+    s->emitSignal1();
+    s->emitSignal2();
+    s->emitSignal3();
+
+    QVERIFY(!r1->called(1));
+    QVERIFY(!r2->called(1));
+    QVERIFY(r1->called(2));
+    QVERIFY(r2->called(2));
+    QVERIFY(r1->called(2));
+    QVERIFY(r2->called(2));
+
+    r1->reset();
+    r2->reset();
+
+    // disconnect all signals of s from all receivers
+    QObject::disconnect( s, 0, 0, 0 );
+
+    connect( s, signal1, r1, slot1 );
+    connect( s, signal1, r2, slot1 );
+
+    // disconnect all signals from slot1 of r1
+    QObject::disconnect(s, QMetaMethod(), r1, slot1);
+
+    s->emitSignal1();
+
+    QVERIFY(!r1->called(1));
+    QVERIFY(r2->called(1));
+
+    delete r2;
+    delete r1;
+    delete s;
+}
+
+void tst_QObject::disconnectNotSignalMetaMethod()
+{
+    SenderObject s;
+    ReceiverObject r;
+
+    connect(&s, SIGNAL(signal1()), &r, SLOT(slot1()));
+
+    QMetaMethod slot = s.metaObject()->method(
+            s.metaObject()->indexOfMethod("aPublicSlot()"));
+
+    QTest::ignoreMessage(QtWarningMsg,"Object::disconnect: Attempt to unbind non-signal SenderObject::aPublicSlot()");
+    QVERIFY(!QObject::disconnect(&s, slot, &r, QMetaMethod()));
+}
+
+class ThreadAffinityThread : public QThread
+{
+public:
+    SenderObject *sender;
+
+    ThreadAffinityThread(SenderObject *sender)
+        : sender(sender)
+    { }
+    void run()
+    {
+        sender->emitSignal1();
+    }
+};
+
+void tst_QObject::autoConnectionBehavior()
+{
+    SenderObject *sender = new SenderObject;
+    ReceiverObject *receiver = new ReceiverObject;
+    connect(sender, SIGNAL(signal1()), receiver, SLOT(slot1()));
+
+    // at emit, currentThread == sender->thread(), currentThread == receiver->thread(), sender->thread() == receiver->thread()
+    QVERIFY(!receiver->called(1));
+    sender->emitSignal1();
+    QVERIFY(receiver->called(1));
+    receiver->reset();
+
+    // at emit, currentThread != sender->thread(), currentThread != receiver->thread(), sender->thread() == receiver->thread()
+    ThreadAffinityThread emitThread1(sender);
+    QVERIFY(!receiver->called(1));
+    emitThread1.start();
+    QVERIFY(emitThread1.wait(30000));
+    QVERIFY(!receiver->called(1));
+    QCoreApplication::sendPostedEvents(receiver, QEvent::MetaCall);
+    QVERIFY(receiver->called(1));
+    receiver->reset();
+
+    // at emit, currentThread == sender->thread(), currentThread != receiver->thread(), sender->thread() != receiver->thread()
+    sender->moveToThread(&emitThread1);
+    QVERIFY(!receiver->called(1));
+    emitThread1.start();
+    QVERIFY(emitThread1.wait(30000));
+    QVERIFY(!receiver->called(1));
+    QCoreApplication::sendPostedEvents(receiver, QEvent::MetaCall);
+    QVERIFY(receiver->called(1));
+    receiver->reset();
+
+    // at emit, currentThread != sender->thread(), currentThread == receiver->thread(), sender->thread() != receiver->thread()
+    QVERIFY(!receiver->called(1));
+    sender->emitSignal1();
+    QVERIFY(receiver->called(1));
+    receiver->reset();
+
+    // at emit, currentThread != sender->thread(), currentThread != receiver->thread(), sender->thread() != receiver->thread()
+    ThreadAffinityThread emitThread2(sender);
+    QThread receiverThread;
+    QTimer *timer = new QTimer;
+    timer->setSingleShot(true);
+    timer->setInterval(100);
+    connect(&receiverThread, SIGNAL(started()), timer, SLOT(start()));
+    connect(timer, SIGNAL(timeout()), &receiverThread, SLOT(quit()), Qt::DirectConnection);
+    connect(&receiverThread, SIGNAL(finished()), timer, SLOT(deleteLater()));
+    timer->moveToThread(&receiverThread);
+
+    receiver->moveToThread(&receiverThread);
+    QVERIFY(!receiver->called(1));
+    emitThread2.start();
+    QVERIFY(emitThread2.wait(30000));
+    QVERIFY(!receiver->called(1));
+    receiverThread.start();
+    QVERIFY(receiverThread.wait(30000));
+    QVERIFY(receiver->called(1));
+    receiver->reset();
+
+    delete sender;
+    delete receiver;
+}
+
+class BaseDestroyed : public QObject
+{
+    Q_OBJECT
+    QList<QString> fooList;
+    bool destroyed;
+public:
+    BaseDestroyed() : destroyed(false)
+    { fooList << "a" << "b"; }
+    ~BaseDestroyed()
+    {
+        QVERIFY(!destroyed);
+        destroyed = true;
+    }
+
+public slots:
+    void slotUseList()
+    {
+        QVERIFY(!destroyed);
+        fooList << "c" << "d";
+    }
+};
+
+void tst_QObject::baseDestroyed()
+{
+    BaseDestroyed d;
+    connect(&d, SIGNAL(destroyed()), &d, SLOT(slotUseList()));
+    //When d goes out of scope, slotUseList should not be called as the BaseDestroyed has
+    // already been destroyed while ~QObject emit destroyed
+}
+
+QTEST_MAIN(tst_QObject)
+
+#include "moc_tst_qobject.cpp"