summaryrefslogtreecommitdiffstats
path: root/tests/auto/corelib/kernel/qobject/tst_qobject.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'tests/auto/corelib/kernel/qobject/tst_qobject.cpp')
-rw-r--r--tests/auto/corelib/kernel/qobject/tst_qobject.cpp281
1 files changed, 240 insertions, 41 deletions
diff --git a/tests/auto/corelib/kernel/qobject/tst_qobject.cpp b/tests/auto/corelib/kernel/qobject/tst_qobject.cpp
index 4417aa2353..333305d603 100644
--- a/tests/auto/corelib/kernel/qobject/tst_qobject.cpp
+++ b/tests/auto/corelib/kernel/qobject/tst_qobject.cpp
@@ -1,32 +1,27 @@
/****************************************************************************
**
-** Copyright (C) 2015 The Qt Company Ltd.
+** Copyright (C) 2016 The Qt Company Ltd.
** Copyright (C) 2015 Olivier Goffart <ogoffart@woboq.com>
-** Contact: http://www.qt.io/licensing/
+** Contact: https://www.qt.io/licensing/
**
** This file is part of the test suite of the Qt Toolkit.
**
-** $QT_BEGIN_LICENSE:LGPL21$
+** $QT_BEGIN_LICENSE:GPL-EXCEPT$
** Commercial License Usage
** Licensees holding valid commercial Qt licenses may use this file in
** accordance with the commercial license agreement provided with the
** Software or, alternatively, in accordance with the terms contained in
** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see http://www.qt.io/terms-conditions. For further
-** information use the contact form at http://www.qt.io/contact-us.
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 2.1 or version 3 as published by the Free
-** Software Foundation and appearing in the file LICENSE.LGPLv21 and
-** LICENSE.LGPLv3 included in the packaging of this file. Please review the
-** following information to ensure the GNU Lesser General Public License
-** requirements will be met: https://www.gnu.org/licenses/lgpl.html and
-** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
-**
-** As a special exception, The Qt Company gives you certain additional
-** rights. These rights are described in The Qt Company LGPL Exception
-** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3 as published by the Free Software
+** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-3.0.html.
**
** $QT_END_LICENSE$
**
@@ -134,6 +129,7 @@ private slots:
void returnValue2_data();
void returnValue2();
void connectVirtualSlots();
+ void connectSlotsVMIClass(); // VMI = Virtual or Multiple Inheritance
void connectPrivateSlots();
void connectFunctorArgDifference();
void connectFunctorOverloads();
@@ -148,6 +144,7 @@ private slots:
void qmlConnect();
void exceptions();
void noDeclarativeParentChangedOnDestruction();
+ void deleteLaterInAboutToBlockHandler();
void mutableFunctor();
};
@@ -2045,57 +2042,57 @@ void tst_QObject::metamethod()
m = mobj->method(mobj->indexOfMethod("invoke1()"));
QVERIFY(m.methodSignature() == "invoke1()");
- QVERIFY(m.methodType() == QMetaMethod::Method);
- QVERIFY(m.access() == QMetaMethod::Public);
+ QCOMPARE(m.methodType(), QMetaMethod::Method);
+ QCOMPARE(m.access(), QMetaMethod::Public);
QVERIFY(!(m.attributes() & QMetaMethod::Scriptable));
QVERIFY(!(m.attributes() & QMetaMethod::Compatibility));
m = mobj->method(mobj->indexOfMethod("sinvoke1()"));
QVERIFY(m.methodSignature() == "sinvoke1()");
- QVERIFY(m.methodType() == QMetaMethod::Method);
- QVERIFY(m.access() == QMetaMethod::Public);
+ QCOMPARE(m.methodType(), QMetaMethod::Method);
+ QCOMPARE(m.access(), QMetaMethod::Public);
QVERIFY((m.attributes() & QMetaMethod::Scriptable));
QVERIFY(!(m.attributes() & QMetaMethod::Compatibility));
m = mobj->method(mobj->indexOfMethod("invoke2()"));
QVERIFY(m.methodSignature() == "invoke2()");
- QVERIFY(m.methodType() == QMetaMethod::Method);
- QVERIFY(m.access() == QMetaMethod::Protected);
+ QCOMPARE(m.methodType(), QMetaMethod::Method);
+ QCOMPARE(m.access(), QMetaMethod::Protected);
QVERIFY(!(m.attributes() & QMetaMethod::Scriptable));
QVERIFY((m.attributes() & QMetaMethod::Compatibility));
m = mobj->method(mobj->indexOfMethod("sinvoke2()"));
QVERIFY(m.methodSignature() == "sinvoke2()");
- QVERIFY(m.methodType() == QMetaMethod::Method);
- QVERIFY(m.access() == QMetaMethod::Protected);
+ QCOMPARE(m.methodType(), QMetaMethod::Method);
+ QCOMPARE(m.access(), QMetaMethod::Protected);
QVERIFY((m.attributes() & QMetaMethod::Scriptable));
QVERIFY((m.attributes() & QMetaMethod::Compatibility));
m = mobj->method(mobj->indexOfMethod("invoke3()"));
QVERIFY(m.methodSignature() == "invoke3()");
- QVERIFY(m.methodType() == QMetaMethod::Method);
- QVERIFY(m.access() == QMetaMethod::Private);
+ QCOMPARE(m.methodType(), QMetaMethod::Method);
+ QCOMPARE(m.access(), QMetaMethod::Private);
QVERIFY(!(m.attributes() & QMetaMethod::Scriptable));
QVERIFY(!(m.attributes() & QMetaMethod::Compatibility));
m = mobj->method(mobj->indexOfMethod("sinvoke3()"));
QVERIFY(m.methodSignature() == "sinvoke3()");
- QVERIFY(m.methodType() == QMetaMethod::Method);
- QVERIFY(m.access() == QMetaMethod::Private);
+ QCOMPARE(m.methodType(), QMetaMethod::Method);
+ QCOMPARE(m.access(), QMetaMethod::Private);
QVERIFY((m.attributes() & QMetaMethod::Scriptable));
QVERIFY(!(m.attributes() & QMetaMethod::Compatibility));
m = mobj->method(mobj->indexOfMethod("signal5()"));
QVERIFY(m.methodSignature() == "signal5()");
- QVERIFY(m.methodType() == QMetaMethod::Signal);
- QVERIFY(m.access() == QMetaMethod::Public);
+ QCOMPARE(m.methodType(), QMetaMethod::Signal);
+ QCOMPARE(m.access(), QMetaMethod::Public);
QVERIFY(!(m.attributes() & QMetaMethod::Scriptable));
QVERIFY((m.attributes() & QMetaMethod::Compatibility));
m = mobj->method(mobj->indexOfMethod("aPublicSlot()"));
QVERIFY(m.methodSignature() == "aPublicSlot()");
- QVERIFY(m.methodType() == QMetaMethod::Slot);
- QVERIFY(m.access() == QMetaMethod::Public);
+ QCOMPARE(m.methodType(), QMetaMethod::Slot);
+ QCOMPARE(m.access(), QMetaMethod::Public);
QVERIFY(!(m.attributes() & QMetaMethod::Scriptable));
QVERIFY(!(m.attributes() & QMetaMethod::Compatibility));
@@ -2367,7 +2364,7 @@ void tst_QObject::testUserData()
int id = user_data_ids[i];
CustomData *data = static_cast<CustomData *>(my_test_object.userData(id));
QVERIFY(data != 0);
- QVERIFY(data->id == id);
+ QCOMPARE(data->id, id);
}
}
@@ -2909,12 +2906,12 @@ void tst_QObject::floatProperty()
QVERIFY(idx > 0);
QMetaProperty prop = obj.metaObject()->property(idx);
QVERIFY(prop.isValid());
- QVERIFY(prop.type() == uint(QMetaType::type("float")));
+ QCOMPARE(int(prop.type()), QMetaType::type("float"));
QVERIFY(!prop.write(&obj, QVariant("Hello")));
QVERIFY(prop.write(&obj, QVariant::fromValue(128.0f)));
QVariant v = prop.read(&obj);
- QVERIFY(int(v.userType()) == QMetaType::Float);
- QVERIFY(qvariant_cast<float>(v) == 128.0f);
+ QCOMPARE(v.userType(), int(QMetaType::Float));
+ QCOMPARE(qvariant_cast<float>(v), 128.0f);
}
void tst_QObject::qrealProperty()
@@ -2924,18 +2921,18 @@ void tst_QObject::qrealProperty()
QVERIFY(idx > 0);
QMetaProperty prop = obj.metaObject()->property(idx);
QVERIFY(prop.isValid());
- QVERIFY(prop.type() == uint(QMetaType::type("qreal")));
+ QCOMPARE(int(prop.type()), QMetaType::type("qreal"));
QVERIFY(!prop.write(&obj, QVariant("Hello")));
QVERIFY(prop.write(&obj, QVariant::fromValue(128.0f)));
QVariant v = prop.read(&obj);
QCOMPARE(v.userType(), qMetaTypeId<qreal>());
- QVERIFY(qvariant_cast<qreal>(v) == 128.0);
+ QCOMPARE(qvariant_cast<qreal>(v), 128.0);
QVERIFY(prop.write(&obj, QVariant::fromValue(double(127))));
v = prop.read(&obj);
QCOMPARE(v.userType(), qMetaTypeId<qreal>());
- QVERIFY(qvariant_cast<qreal>(v) == 127.0);
+ QCOMPARE(qvariant_cast<qreal>(v), 127.0);
}
class DynamicPropertyObject : public PropertyObject
@@ -3001,7 +2998,7 @@ void tst_QObject::recursiveSignalEmission()
proc.start(path);
QVERIFY2(proc.waitForStarted(), qPrintable(QString::fromLatin1("Cannot start '%1': %2").arg(path, proc.errorString())));
QVERIFY(proc.waitForFinished());
- QVERIFY(proc.exitStatus() == QProcess::NormalExit);
+ QCOMPARE(proc.exitStatus(), QProcess::NormalExit);
QCOMPARE(proc.exitCode(), 0);
#endif
}
@@ -5611,6 +5608,112 @@ void tst_QObject::connectVirtualSlots()
*/
}
+struct VirtualBase
+{
+ int virtual_base_count;
+ VirtualBase() : virtual_base_count(0) {}
+ virtual ~VirtualBase() {}
+ virtual void slot2() = 0;
+};
+
+class ObjectWithVirtualBase : public VirtualSlotsObject, public virtual VirtualBase
+{
+ Q_OBJECT
+public:
+ ObjectWithVirtualBase() : regular_call_count(0), derived_counter2(0) {}
+ int regular_call_count;
+ int derived_counter2;
+
+public slots:
+ void regularSlot() { ++regular_call_count; }
+ virtual void slot1() { ++derived_counter2; }
+ virtual void slot2() { ++virtual_base_count; }
+};
+
+// VMI = Virtual or Multiple Inheritance
+// (in this case, both)
+void tst_QObject::connectSlotsVMIClass()
+{
+ // test connecting by the base
+ {
+ ObjectWithVirtualBase obj;
+ QVERIFY( QObject::connect(&obj, &VirtualSlotsObjectBase::signal1, &obj, &VirtualSlotsObjectBase::slot1, Qt::UniqueConnection));
+ QVERIFY(!QObject::connect(&obj, &VirtualSlotsObjectBase::signal1, &obj, &VirtualSlotsObjectBase::slot1, Qt::UniqueConnection));
+
+ emit obj.signal1();
+ QCOMPARE(obj.base_counter1, 0);
+ QCOMPARE(obj.derived_counter1, 0);
+ QCOMPARE(obj.derived_counter2, 1);
+ QCOMPARE(obj.virtual_base_count, 0);
+
+ QVERIFY(QObject::disconnect(&obj, &VirtualSlotsObjectBase::signal1, &obj, &VirtualSlotsObjectBase::slot1));
+ QVERIFY(!QObject::disconnect(&obj, &VirtualSlotsObjectBase::signal1, &obj, &VirtualSlotsObjectBase::slot1));
+
+ emit obj.signal1();
+ QCOMPARE(obj.base_counter1, 0);
+ QCOMPARE(obj.derived_counter1, 0);
+ QCOMPARE(obj.derived_counter2, 1);
+ QCOMPARE(obj.virtual_base_count, 0);
+ }
+
+ // test connecting with the actual class
+ {
+ ObjectWithVirtualBase obj;
+ QVERIFY( QObject::connect(&obj, &VirtualSlotsObjectBase::signal1, &obj, &ObjectWithVirtualBase::regularSlot, Qt::UniqueConnection));
+ QVERIFY(!QObject::connect(&obj, &VirtualSlotsObjectBase::signal1, &obj, &ObjectWithVirtualBase::regularSlot, Qt::UniqueConnection));
+ QVERIFY( QObject::connect(&obj, &VirtualSlotsObjectBase::signal1, &obj, &ObjectWithVirtualBase::slot1, Qt::UniqueConnection));
+ QVERIFY(!QObject::connect(&obj, &VirtualSlotsObjectBase::signal1, &obj, &ObjectWithVirtualBase::slot1, Qt::UniqueConnection));
+
+ emit obj.signal1();
+ QCOMPARE(obj.base_counter1, 0);
+ QCOMPARE(obj.derived_counter1, 0);
+ QCOMPARE(obj.derived_counter2, 1);
+ QCOMPARE(obj.regular_call_count, 1);
+ QCOMPARE(obj.virtual_base_count, 0);
+
+ QVERIFY( QObject::disconnect(&obj, &VirtualSlotsObjectBase::signal1, &obj, &ObjectWithVirtualBase::regularSlot));
+ QVERIFY(!QObject::disconnect(&obj, &VirtualSlotsObjectBase::signal1, &obj, &ObjectWithVirtualBase::regularSlot));
+ QVERIFY( QObject::disconnect(&obj, &VirtualSlotsObjectBase::signal1, &obj, &ObjectWithVirtualBase::slot1));
+ QVERIFY(!QObject::disconnect(&obj, &VirtualSlotsObjectBase::signal1, &obj, &ObjectWithVirtualBase::slot1));
+
+ emit obj.signal1();
+ QCOMPARE(obj.base_counter1, 0);
+ QCOMPARE(obj.derived_counter1, 0);
+ QCOMPARE(obj.derived_counter2, 1);
+ QCOMPARE(obj.regular_call_count, 1);
+ QCOMPARE(obj.virtual_base_count, 0);
+
+ /* the C++ standard say the comparison between pointer to virtual member function is unspecified
+ QVERIFY( QObject::connect(&obj, &VirtualSlotsObjectBase::signal1, &obj, &VirtualSlotsObjectBase::slot1, Qt::UniqueConnection));
+ QVERIFY(!QObject::connect(&obj, &VirtualSlotsObjectBase::signal1, &obj, &ObjectWithVirtualBase::slot1, Qt::UniqueConnection));
+ */
+ }
+
+ // test connecting a slot that is virtual from the virtual base
+ {
+ ObjectWithVirtualBase obj;
+ QVERIFY( QObject::connect(&obj, &VirtualSlotsObjectBase::signal1, &obj, &ObjectWithVirtualBase::slot2, Qt::UniqueConnection));
+ QVERIFY(!QObject::connect(&obj, &VirtualSlotsObjectBase::signal1, &obj, &ObjectWithVirtualBase::slot2, Qt::UniqueConnection));
+
+ emit obj.signal1();
+ QCOMPARE(obj.base_counter1, 0);
+ QCOMPARE(obj.derived_counter1, 0);
+ QCOMPARE(obj.derived_counter2, 0);
+ QCOMPARE(obj.virtual_base_count, 1);
+ QCOMPARE(obj.regular_call_count, 0);
+
+ QVERIFY( QObject::disconnect(&obj, &VirtualSlotsObjectBase::signal1, &obj, &ObjectWithVirtualBase::slot2));
+ QVERIFY(!QObject::disconnect(&obj, &VirtualSlotsObjectBase::signal1, &obj, &ObjectWithVirtualBase::slot2));
+
+ emit obj.signal1();
+ QCOMPARE(obj.base_counter1, 0);
+ QCOMPARE(obj.derived_counter1, 0);
+ QCOMPARE(obj.derived_counter2, 0);
+ QCOMPARE(obj.virtual_base_count, 1);
+ QCOMPARE(obj.regular_call_count, 0);
+ }
+}
+
#ifndef QT_BUILD_INTERNAL
void tst_QObject::connectPrivateSlots()
{QSKIP("Needs QT_BUILD_INTERNAL");}
@@ -5801,6 +5904,102 @@ void tst_QObject::connectFunctorWithContext()
context->deleteLater();
}
+class StatusChanger : public QObject
+{
+ Q_OBJECT
+public:
+ StatusChanger(int *status) : m_status(status)
+ {
+ }
+ ~StatusChanger()
+ {
+ *m_status = 2;
+ }
+private:
+ int *m_status;
+};
+
+class DispatcherWatcher : public QObject
+{
+ Q_OBJECT
+public:
+ DispatcherWatcher(QEventLoop &e, int *statusAwake, int *statusAboutToBlock) :
+ m_eventLoop(&e),
+ m_statusAwake(statusAwake),
+ m_statusAboutToBlock(statusAboutToBlock),
+ m_aboutToBlocks(0),
+ m_awakes(0)
+ {
+ awake = new StatusChanger(statusAwake);
+ abouttoblock = new StatusChanger(statusAboutToBlock);
+ QCOMPARE(*statusAwake, 1);
+ QCOMPARE(*statusAboutToBlock, 1);
+ connect(QAbstractEventDispatcher::instance(), SIGNAL(awake()), this, SLOT(onAwake()));
+ connect(QAbstractEventDispatcher::instance(), SIGNAL(aboutToBlock()), this, SLOT(onAboutToBlock()));
+
+ }
+
+ ~DispatcherWatcher()
+ {
+ if (awake)
+ awake->deleteLater();
+ if (abouttoblock)
+ abouttoblock->deleteLater();
+ }
+
+public slots:
+ // The order of these 2 handlers differs on different event dispatchers
+ void onAboutToBlock()
+ {
+ if (abouttoblock) {
+ abouttoblock->deleteLater();
+ abouttoblock = 0;
+ }
+ ++m_aboutToBlocks;
+ }
+ void onAwake()
+ {
+ if (awake) {
+ awake->deleteLater();
+ awake = 0;
+ }
+ ++m_awakes;
+
+ }
+ void onSignal1()
+ {
+ // Status check. At this point the event loop should have spinned enough to delete all the objects.
+ QCOMPARE(*m_statusAwake, 2);
+ QCOMPARE(*m_statusAboutToBlock, 2);
+ QMetaObject::invokeMethod(m_eventLoop, "quit", Qt::QueuedConnection);
+ }
+
+private:
+ StatusChanger *awake;
+ StatusChanger *abouttoblock;
+ QEventLoop *m_eventLoop;
+ int *m_statusAwake;
+ int *m_statusAboutToBlock;
+ int m_aboutToBlocks;
+ int m_awakes;
+};
+
+
+void tst_QObject::deleteLaterInAboutToBlockHandler()
+{
+ int statusAwake = 1;
+ int statusAboutToBlock = 1;
+ QEventLoop e;
+ DispatcherWatcher dw(e, &statusAwake, &statusAboutToBlock);
+ QTimer::singleShot(2000, &dw, &DispatcherWatcher::onSignal1);
+
+ QCOMPARE(statusAwake, 1);
+ QCOMPARE(statusAboutToBlock, 1);
+ e.exec();
+ QCOMPARE(statusAwake, 2);
+ QCOMPARE(statusAboutToBlock, 2);
+}
+
void tst_QObject::connectFunctorWithContextUnique()
{
// Qt::UniqueConnections currently don't work for functors, but we need to