diff options
Diffstat (limited to 'tests/auto/corelib/kernel/qmetaobject/tst_qmetaobject.cpp')
-rw-r--r-- | tests/auto/corelib/kernel/qmetaobject/tst_qmetaobject.cpp | 1124 |
1 files changed, 1049 insertions, 75 deletions
diff --git a/tests/auto/corelib/kernel/qmetaobject/tst_qmetaobject.cpp b/tests/auto/corelib/kernel/qmetaobject/tst_qmetaobject.cpp index 86501b74ea..182ec6daae 100644 --- a/tests/auto/corelib/kernel/qmetaobject/tst_qmetaobject.cpp +++ b/tests/auto/corelib/kernel/qmetaobject/tst_qmetaobject.cpp @@ -1,42 +1,42 @@ -/**************************************************************************** -** -** Copyright (C) 2016 The Qt Company Ltd. -** Contact: https://www.qt.io/licensing/ -** -** This file is part of the test suite of the Qt Toolkit. -** -** $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 https://www.qt.io/terms-conditions. For further -** information use the contact form at https://www.qt.io/contact-us. -** -** 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$ -** -****************************************************************************/ +// Copyright (C) 2016 The Qt Company Ltd. +// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only #include <QTest> #include <QSignalSpy> +#if QT_CONFIG(sortfilterproxymodel) #include <QSortFilterProxyModel> +#endif #include <qobject.h> #include <qmetaobject.h> +#if QT_CONFIG(proxymodel) #include <qabstractproxymodel.h> +#endif #include <private/qmetaobject_p.h> Q_DECLARE_METATYPE(const QMetaObject *) +#include "forwarddeclared.h" + +#ifdef USE_COMPAT_Q_ARG +# define tst_QMetaObject tst_QMetaObject_CompatQArg +# if QT_VERSION >= QT_VERSION_CHECK(7, 0, 0) +# error "This is a Qt 6 compatibility check test" +# endif + +# undef Q_ARG +# undef Q_RETURN_ARG +# define Q_ARG(type, data) QArgument<type >(#type, data) +# define Q_RETURN_ARG(type, data) QReturnArgument<type >(#type, data) +# define Q_NO_ARG , QGenericArgument() +#else +// This macro is used to force the overload selection to the compat +// (non-variadic) code above +# define Q_NO_ARG +#endif + +using namespace Qt::StringLiterals; + struct MyStruct { int i; @@ -240,8 +240,7 @@ namespace MyNamespace { int m_value2 = 0; int m_value3 = 0; }; -} - +} // namespace MyNamespace class tst_QMetaObject : public QObject { @@ -290,35 +289,46 @@ public: QList<QVariant> value4; QVariantList value5; + tst_QMetaObject(); + private slots: void connectSlotsByName(); void invokeMetaMember(); + void invokeMetaMemberNoMacros(); void invokePointer(); void invokeQueuedMetaMember(); + void invokeQueuedMetaMemberNoMacro(); void invokeQueuedPointer(); void invokeBlockingQueuedMetaMember(); + void invokeBlockingQueuedMetaMemberNoMacros(); void invokeBlockingQueuedPointer(); void invokeCustomTypes(); void invokeMetaConstructor(); + void invokeMetaConstructorNoMacro(); void invokeTypedefTypes(); void invokeException(); void invokeQueuedAutoRegister(); + void invokeFreeFunction(); + void invokeBind(); void qtMetaObjectInheritance(); void normalizedSignature_data(); void normalizedSignature(); void normalizedType_data(); void normalizedType(); void customPropertyType(); - void checkScope_data(); - void checkScope(); + void keysToValue_data(); + void keysToValue(); // Also keyToValue() void propertyNotify(); void propertyConstant(); void propertyFinal(); + void metaType(); + void stdSet(); void classInfo(); void metaMethod(); + void metaMethodNoMacro(); void indexOfMethod_data(); void indexOfMethod(); @@ -424,6 +434,11 @@ private slots: #define FUNCTION(x) "QMetaObject::" x ": " +tst_QMetaObject::tst_QMetaObject() +{ + qRegisterMetaType<qlonglong *>(); +} + void tst_QMetaObject::connectSlotsByName() { CTestObject obj; @@ -458,8 +473,6 @@ void tst_QMetaObject::connectSlotsByName() QCOMPARE(obj2.invokeCount2, 1); } -struct MyUnregisteredType { }; - static int countedStructObjectsCount = 0; struct CountedStruct { @@ -482,6 +495,8 @@ public: QtTestObject(); QtTestObject(const QString &s) : slotResult(s) {} Q_INVOKABLE QtTestObject(QObject *parent); + Q_INVOKABLE QtTestObject(QObject *parent, int, int); + Q_INVOKABLE QtTestObject(QObject *parent, int); public slots: void sl0(); @@ -502,17 +517,24 @@ public slots: const char *sl12(); QList<QString> sl13(QList<QString> l1); qint64 sl14(); - void testSender(); + qlonglong *sl15(qlonglong *); + MyForwardDeclaredType *sl16(MyForwardDeclaredType *); - void testReference(QString &str); + void sl17(int *i) { *i = 242; } + void overloadedSlot(); + void overloadedSlot(int, int); + void overloadedSlot(int); + + void testSender(); + void testReference(QString &str); void testLongLong(qint64 ll1, quint64 ll2); void moveToThread(QThread *t) { QObject::moveToThread(t); } - void slotWithUnregisteredParameterType(MyUnregisteredType); - void slotWithOneUnregisteredParameterType(QString a1, MyUnregisteredType a2); + void slotWithUnregisteredParameterType(const MyForwardDeclaredType &); + void slotWithOneUnregisteredParameterType(QString a1, const MyForwardDeclaredType &a2); CountedStruct throwingSlot(const CountedStruct &, CountedStruct s2) { #ifndef QT_NO_EXCEPTIONS @@ -563,6 +585,14 @@ QtTestObject::QtTestObject(QObject *parent) { } +QtTestObject::QtTestObject(QObject *parent, int, int) + : QObject(parent) +{ slotResult = "ii"; } + +QtTestObject::QtTestObject(QObject *parent, int) + : QObject(parent) +{ slotResult = "i"; } + void QtTestObject::sl0() { slotResult = "sl0"; }; QString QtTestObject::sl1(QString s1) { slotResult = "sl1:" + s1; return "yessir"; } void QtTestObject::sl2(QString s1, QString s2) { slotResult = "sl2:" + s1 + s2; } @@ -595,6 +625,27 @@ QList<QString> QtTestObject::sl13(QList<QString> l1) { slotResult = "sl13"; return l1; } qint64 QtTestObject::sl14() { slotResult = "sl14"; return Q_INT64_C(123456789)*123456789; } +qlonglong *QtTestObject::sl15(qlonglong *ptr) +{ slotResult = "sl15"; return ptr; } +MyForwardDeclaredType *QtTestObject::sl16(MyForwardDeclaredType *ptr) +{ + slotResult = "sl16:"; + if (ptr) { + slotResult += "notnull"; + return nullptr; + } + slotResult += "null"; + return getForwardDeclaredPointer(); +} + +void QtTestObject::overloadedSlot() +{ slotResult = "overloadedSlot"; } + +void QtTestObject::overloadedSlot(int x, int y) +{ slotResult = "overloadedSlot:" + QString::number(x) + ',' + QString::number(y); } + +void QtTestObject::overloadedSlot(int x) +{ slotResult = "overloadedSlot:" + QString::number(x); } void QtTestObject::testReference(QString &str) { slotResult = "testReference:" + str; str = "gotcha"; } @@ -607,10 +658,10 @@ void QtTestObject::testSender() slotResult = QString::asprintf("%p", sender()); } -void QtTestObject::slotWithUnregisteredParameterType(MyUnregisteredType) +void QtTestObject::slotWithUnregisteredParameterType(const MyForwardDeclaredType &) { slotResult = "slotWithUnregisteredReturnType"; } -void QtTestObject::slotWithOneUnregisteredParameterType(QString a1, MyUnregisteredType) +void QtTestObject::slotWithOneUnregisteredParameterType(QString a1, const MyForwardDeclaredType &) { slotResult = "slotWithUnregisteredReturnType-" + a1; } void QtTestObject::staticFunction0() @@ -621,6 +672,7 @@ void QtTestObject::staticFunction0() qint64 QtTestObject::staticFunction1() { staticResult = "staticFunction1"; return Q_INT64_C(123456789)*123456789; } +// this test is duplicated below void tst_QMetaObject::invokeMetaMember() { QtTestObject obj; @@ -631,17 +683,17 @@ void tst_QMetaObject::invokeMetaMember() // Test nullptr char *nullCharArray = nullptr; const char *nullConstCharArray = nullptr; - QVERIFY(!QMetaObject::invokeMethod(nullptr, nullCharArray)); - QVERIFY(!QMetaObject::invokeMethod(nullptr, nullConstCharArray)); - QVERIFY(!QMetaObject::invokeMethod(nullptr, "sl0")); - QVERIFY(!QMetaObject::invokeMethod(&obj, nullCharArray)); - QVERIFY(!QMetaObject::invokeMethod(&obj, nullConstCharArray)); - QVERIFY(!QMetaObject::invokeMethod(&obj, nullCharArray, Qt::AutoConnection)); - QVERIFY(!QMetaObject::invokeMethod(&obj, nullConstCharArray, Qt::AutoConnection)); + QVERIFY(!QMetaObject::invokeMethod(nullptr, nullCharArray Q_NO_ARG)); + QVERIFY(!QMetaObject::invokeMethod(nullptr, nullConstCharArray Q_NO_ARG)); + QVERIFY(!QMetaObject::invokeMethod(nullptr, "sl0" Q_NO_ARG)); + QVERIFY(!QMetaObject::invokeMethod(&obj, nullCharArray Q_NO_ARG)); + QVERIFY(!QMetaObject::invokeMethod(&obj, nullConstCharArray Q_NO_ARG)); + QVERIFY(!QMetaObject::invokeMethod(&obj, nullCharArray, Qt::AutoConnection Q_NO_ARG)); + QVERIFY(!QMetaObject::invokeMethod(&obj, nullConstCharArray, Qt::AutoConnection Q_NO_ARG)); QVERIFY(!QMetaObject::invokeMethod(&obj, nullCharArray, Qt::AutoConnection, QGenericReturnArgument())); QVERIFY(!QMetaObject::invokeMethod(&obj, nullConstCharArray, Qt::AutoConnection, QGenericReturnArgument())); - QVERIFY(QMetaObject::invokeMethod(&obj, "sl0")); + QVERIFY(QMetaObject::invokeMethod(&obj, "sl0" Q_NO_ARG)); QCOMPARE(obj.slotResult, QString("sl0")); QVERIFY(QMetaObject::invokeMethod(&obj, "sl1", Q_ARG(QString, t1))); @@ -680,16 +732,23 @@ void tst_QMetaObject::invokeMetaMember() Q_ARG(QString, t7), Q_ARG(QString, t8), Q_ARG(QString, t9))); QCOMPARE(obj.slotResult, QString("sl9:123456789")); - QVERIFY(QMetaObject::invokeMethod(&obj, "sl11")); + QVERIFY(QMetaObject::invokeMethod(&obj, "sl11" Q_NO_ARG)); QCOMPARE(obj.slotResult, QString("sl11")); - QVERIFY(QMetaObject::invokeMethod(&obj, "testSender")); + QVERIFY(QMetaObject::invokeMethod(&obj, "testSender" Q_NO_ARG)); QCOMPARE(obj.slotResult, QString("0x0")); QString refStr("whatever"); +#ifdef USE_COMPAT_Q_ARG QVERIFY(QMetaObject::invokeMethod(&obj, "testReference", QGenericArgument("QString&", &refStr))); QCOMPARE(obj.slotResult, QString("testReference:whatever")); QCOMPARE(refStr, QString("gotcha")); + obj.slotResult.clear(); +#endif + refStr = "whatever"; + QVERIFY(QMetaObject::invokeMethod(&obj, "testReference", Q_ARG(QString&, refStr))); + QCOMPARE(obj.slotResult, QString("testReference:whatever")); + QCOMPARE(refStr, QString("gotcha")); qint64 ll1 = -1; quint64 ll2 = 0; @@ -740,8 +799,37 @@ void tst_QMetaObject::invokeMetaMember() QCOMPARE(return64, Q_INT64_C(123456789)*123456789); QCOMPARE(obj.slotResult, QString("sl14")); + // pointers + QVERIFY(QMetaObject::invokeMethod(&obj, "sl15", Q_ARG(qlonglong*, &return64))); + QCOMPARE(obj.slotResult, QString("sl15")); + QVERIFY(QMetaObject::invokeMethod(&obj, "sl16", Q_ARG(MyForwardDeclaredType*, getForwardDeclaredPointer()))); + QCOMPARE(obj.slotResult, QString("sl16:notnull")); + + obj.slotResult.clear(); + qint64 *return64Ptr; + QVERIFY(QMetaObject::invokeMethod(&obj, "sl15", Q_RETURN_ARG(qlonglong*, return64Ptr), Q_ARG(qlonglong*, &return64))); + QCOMPARE(return64Ptr, &return64); + QCOMPARE(obj.slotResult, QString("sl15")); + + obj.slotResult.clear(); + MyForwardDeclaredType *forwardPtr; + QVERIFY(QMetaObject::invokeMethod(&obj, "sl16", Q_RETURN_ARG(MyForwardDeclaredType*, forwardPtr), + Q_ARG(MyForwardDeclaredType*, nullptr))); + QCOMPARE(forwardPtr, getForwardDeclaredPointer()); + QCOMPARE(obj.slotResult, QString("sl16:null")); + +#ifndef QT_NO_DATA_RELOCATION // this doesn't work with the new API on Windows +#endif + // test overloads + QVERIFY(QMetaObject::invokeMethod(&obj, "overloadedSlot" Q_NO_ARG)); + QCOMPARE(obj.slotResult, QString("overloadedSlot")); + QVERIFY(QMetaObject::invokeMethod(&obj, "overloadedSlot", Q_ARG(int, 1))); + QCOMPARE(obj.slotResult, QString("overloadedSlot:1")); + QVERIFY(QMetaObject::invokeMethod(&obj, "overloadedSlot", Q_ARG(int, 1), Q_ARG(int, 42))); + QCOMPARE(obj.slotResult, QString("overloadedSlot:1,42")); + //test signals - QVERIFY(QMetaObject::invokeMethod(&obj, "sig0")); + QVERIFY(QMetaObject::invokeMethod(&obj, "sig0" Q_NO_ARG)); QCOMPARE(obj.slotResult, QString("sl0")); QVERIFY(QMetaObject::invokeMethod(&obj, "sig1", Q_ARG(QString, "baba"))); @@ -762,6 +850,175 @@ void tst_QMetaObject::invokeMetaMember() QTest::ignoreMessage(QtWarningMsg, "QMetaObject::invokeMethod: No such method QtTestObject::sl1(QString,QString,QString)\n" "Candidates are:\n sl1(QString)"); QVERIFY(!QMetaObject::invokeMethod(&obj, "sl1", Q_ARG(QString, "arg"), Q_ARG(QString, "arg"), Q_ARG(QString, "arg"))); + QTest::ignoreMessage(QtWarningMsg, "QMetaObject::invokeMethod: No such method QtTestObject::testReference(QString)\n" + "Candidates are:\n testReference(QString&)"); + QVERIFY(!QMetaObject::invokeMethod(&obj, "testReference", Q_ARG(QString, exp))); + + //should not have changed since last test. + QCOMPARE(exp, QString("yessir")); + QCOMPARE(obj.slotResult, QString("sl1:hehe")); +} + +// this is a copy-paste-adapt of the above +void tst_QMetaObject::invokeMetaMemberNoMacros() +{ + QtTestObject obj; + + QString t1("1"); QString t2("2"); QString t3("3"); QString t4("4"); QString t5("5"); + QString t6("6"); QString t7("7"); QString t8("8"); QString t9("9"); QString t10("X"); + + QVERIFY(QMetaObject::invokeMethod(&obj, "sl0")); + QCOMPARE(obj.slotResult, QString("sl0")); + + QVERIFY(QMetaObject::invokeMethod(&obj, "sl1", t1)); + QCOMPARE(obj.slotResult, QString("sl1:1")); + + QVERIFY(QMetaObject::invokeMethod(&obj, "sl2", std::as_const(t1), t2)); + QCOMPARE(obj.slotResult, QString("sl2:12")); + + QVERIFY(QMetaObject::invokeMethod(&obj, "sl3", t1, t2, t3)); + QCOMPARE(obj.slotResult, QString("sl3:123")); + + QVERIFY(QMetaObject::invokeMethod(&obj, "sl4", t1, t2, t3, + t4)); + QCOMPARE(obj.slotResult, QString("sl4:1234")); + + QVERIFY(QMetaObject::invokeMethod(&obj, "sl5", t1, t2, t3, + t4, QStringLiteral("5"))); + QCOMPARE(obj.slotResult, QString("sl5:12345")); + + QVERIFY(QMetaObject::invokeMethod(&obj, "sl6", t1, t2, t3, + t4, t5, t6)); + QCOMPARE(obj.slotResult, QString("sl6:123456")); + + QVERIFY(QMetaObject::invokeMethod(&obj, "sl7", t1, t2, t3, + t4, t5, t6, + t7)); + QCOMPARE(obj.slotResult, QString("sl7:1234567")); + + QVERIFY(QMetaObject::invokeMethod(&obj, "sl8", t1, t2, t3, + t4, t5, t6, + t7, t8)); + QCOMPARE(obj.slotResult, QString("sl8:12345678")); + + QVERIFY(QMetaObject::invokeMethod(&obj, "sl9", t1, t2, t3, + t4, t5, t6, + t7, t8, t9)); + QCOMPARE(obj.slotResult, QString("sl9:123456789")); + + QVERIFY(QMetaObject::invokeMethod(&obj, "sl11")); + QCOMPARE(obj.slotResult, QString("sl11")); + + QVERIFY(QMetaObject::invokeMethod(&obj, "testSender")); + QCOMPARE(obj.slotResult, QString("0x0")); + + // this is not working for now +// QString refStr("whatever"); +// QVERIFY(QMetaObject::invokeMethod(&obj, "testReference", refStr)); +// QCOMPARE(obj.slotResult, QString("testReference:whatever")); +// QCOMPARE(refStr, QString("gotcha")); + + qint64 ll1 = -1; + quint64 ll2 = 0; + QVERIFY(QMetaObject::invokeMethod(&obj, + "testLongLong", + ll1, + ll2)); + QCOMPARE(obj.slotResult, QString("testLongLong:-1,0")); + + QString exp; + QVERIFY(QMetaObject::invokeMethod(&obj, "sl1", qReturnArg(exp), QStringLiteral("bubu"))); + QCOMPARE(exp, QString("yessir")); + QCOMPARE(obj.slotResult, QString("sl1:bubu")); + + QObject *ptr = nullptr; + QVERIFY(QMetaObject::invokeMethod(&obj, "sl11", qReturnArg(ptr))); + QCOMPARE(ptr, (QObject *)&obj); + QCOMPARE(obj.slotResult, QString("sl11")); + // try again with a space: + ptr = nullptr; + QVERIFY(QMetaObject::invokeMethod(&obj, "sl11", qReturnArg(ptr))); + QCOMPARE(ptr, (QObject *)&obj); + QCOMPARE(obj.slotResult, QString("sl11")); + + const char *ptr2 = nullptr; + QVERIFY(QMetaObject::invokeMethod(&obj, "sl12", qReturnArg(ptr2))); + QVERIFY(ptr2 != nullptr); + QCOMPARE(obj.slotResult, QString("sl12")); + // try again with a space: + ptr2 = nullptr; + QVERIFY(QMetaObject::invokeMethod(&obj, "sl12", qReturnArg(ptr2))); + QVERIFY(ptr2 != nullptr); + QCOMPARE(obj.slotResult, QString("sl12")); + + // test w/ template args + QList<QString> returnValue, argument; + argument << QString("one") << QString("two") << QString("three"); + QVERIFY(QMetaObject::invokeMethod(&obj, "sl13", + qReturnArg(returnValue), + argument)); + QCOMPARE(returnValue, argument); + QCOMPARE(obj.slotResult, QString("sl13")); + + // return qint64 + qint64 return64; + QVERIFY(QMetaObject::invokeMethod(&obj, "sl14", + qReturnArg(return64))); + QCOMPARE(return64, Q_INT64_C(123456789)*123456789); + QCOMPARE(obj.slotResult, QString("sl14")); + + // pointers + QVERIFY(QMetaObject::invokeMethod(&obj, "sl15", &return64)); + QCOMPARE(obj.slotResult, QString("sl15")); + QVERIFY(QMetaObject::invokeMethod(&obj, "sl16", getForwardDeclaredPointer())); + QCOMPARE(obj.slotResult, QString("sl16:notnull")); + + obj.slotResult.clear(); + qint64 *return64Ptr; + QVERIFY(QMetaObject::invokeMethod(&obj, "sl15", qReturnArg(return64Ptr), &return64)); + QCOMPARE(return64Ptr, &return64); + QCOMPARE(obj.slotResult, QString("sl15")); + + obj.slotResult.clear(); + MyForwardDeclaredType *forwardPtr = nullptr; + QVERIFY(QMetaObject::invokeMethod(&obj, "sl16", qReturnArg(forwardPtr), + forwardPtr)); + QCOMPARE(forwardPtr, getForwardDeclaredPointer()); + QCOMPARE(obj.slotResult, QString("sl16:null")); + + // test overloads + QVERIFY(QMetaObject::invokeMethod(&obj, "overloadedSlot")); + QCOMPARE(obj.slotResult, QString("overloadedSlot")); + QVERIFY(QMetaObject::invokeMethod(&obj, "overloadedSlot", 1)); + QCOMPARE(obj.slotResult, QString("overloadedSlot:1")); + QVERIFY(QMetaObject::invokeMethod(&obj, "overloadedSlot", 1, 42)); + QCOMPARE(obj.slotResult, QString("overloadedSlot:1,42")); + + //test signals + QVERIFY(QMetaObject::invokeMethod(&obj, "sig0")); + QCOMPARE(obj.slotResult, QString("sl0")); + + QVERIFY(QMetaObject::invokeMethod(&obj, "sig1", QStringLiteral("baba"))); + QCOMPARE(obj.slotResult, QString("sl1:baba")); + + exp.clear(); + QVERIFY(QMetaObject::invokeMethod(&obj, "sig1", qReturnArg(exp), QStringLiteral("hehe"))); + QCOMPARE(exp, QString("yessir")); + QCOMPARE(obj.slotResult, QString("sl1:hehe")); + + QTest::ignoreMessage(QtWarningMsg, "QMetaObject::invokeMethod: No such method QtTestObject::doesNotExist()"); + QVERIFY(!QMetaObject::invokeMethod(&obj, "doesNotExist")); + QTest::ignoreMessage(QtWarningMsg, "QMetaObject::invokeMethod: No such method QtTestObject::sl1(QString)(QString)"); + QVERIFY(!QMetaObject::invokeMethod(&obj, "sl1(QString)", QStringLiteral("arg"))); + QTest::ignoreMessage(QtWarningMsg, "QMetaObject::invokeMethod: No such method QtTestObject::sl3(QString)\n" + "Candidates are:\n sl3(QString,QString,QString)"); + QVERIFY(!QMetaObject::invokeMethod(&obj, "sl3", QStringLiteral("arg"))); + QTest::ignoreMessage(QtWarningMsg, "QMetaObject::invokeMethod: No such method QtTestObject::sl1(QString,QString,QString)\n" + "Candidates are:\n sl1(QString)"); + QVERIFY(!QMetaObject::invokeMethod(&obj, "sl1", QStringLiteral("arg"), QStringLiteral("arg"), QStringLiteral("arg"))); + QTest::ignoreMessage(QtWarningMsg, "QMetaObject::invokeMethod: No such method QtTestObject::testReference(QString)\n" + "Candidates are:\n testReference(QString&)"); + QVERIFY(!QMetaObject::invokeMethod(&obj, "testReference", exp)); //should not have changed since last test. QCOMPARE(exp, QString("yessir")); @@ -825,7 +1082,6 @@ void tst_QMetaObject::invokePointer() QCOMPARE(obj.slotResult, QString("sl1:bubu")); } QCOMPARE(countedStructObjectsCount, 0); -#ifdef __cpp_init_captures { CountedStruct str; std::unique_ptr<int> ptr( new int ); @@ -833,14 +1089,123 @@ void tst_QMetaObject::invokePointer() QCOMPARE(obj.slotResult, QString("sl1:1")); } QCOMPARE(countedStructObjectsCount, 0); -#endif + + // Invoking with parameters + QString result; + QVERIFY(QMetaObject::invokeMethod(&obj, &QtTestObject::sl1, qReturnArg(result), u"bubu"_s)); + QCOMPARE(obj.slotResult, u"sl1:bubu"); + QCOMPARE(result, u"yessir"); + + // without taking return value + QVERIFY(QMetaObject::invokeMethod(&obj, &QtTestObject::sl1, u"bubu"_s)); + QCOMPARE(obj.slotResult, u"sl1:bubu"); + + QVERIFY(QMetaObject::invokeMethod(&obj, &QtTestObject::sl1, Qt::DirectConnection, qReturnArg(result), + u"byebye"_s)); + QCOMPARE(obj.slotResult, u"sl1:byebye"); + QCOMPARE(result, u"yessir"); + + QVERIFY(QMetaObject::invokeMethod(&obj, qOverload<int, int>(&QtTestObject::overloadedSlot), 1, 2)); + QCOMPARE(obj.slotResult, u"overloadedSlot:1,2"); + + // non-const ref parameter + QString original = u"bubu"_s; + QString &ref = original; + QVERIFY(QMetaObject::invokeMethod(&obj, &QtTestObject::sl1, qReturnArg(result), ref)); + QCOMPARE(obj.slotResult, u"sl1:bubu"); + QCOMPARE(result, u"yessir"); + + struct R { + bool operator()(int) { return true; } + int operator()(char) { return 15; } + int operator()(QString = {}, int = {}, int = {}) { return 242; } + } r; + + // Test figuring out which operator() to call: + { + bool res = false; + QVERIFY(QMetaObject::invokeMethod(&obj, r, qReturnArg(res), 1)); + QCOMPARE(res, true); + } + { + int res; + QVERIFY(QMetaObject::invokeMethod(&obj, r, qReturnArg(res), 'c')); + QCOMPARE(res, 15); + } + { + int res; + QVERIFY(QMetaObject::invokeMethod(&obj, r, qReturnArg(res))); + QCOMPARE(res, 242); + res = 0; + QVERIFY(QMetaObject::invokeMethod(&obj, r, qReturnArg(res), u"bu"_s)); + QCOMPARE(res, 242); + res = 0; + QVERIFY(QMetaObject::invokeMethod(&obj, r, qReturnArg(res), u"bu"_s, 1)); + QCOMPARE(res, 242); + res = 0; + QVERIFY(QMetaObject::invokeMethod(&obj, r, qReturnArg(res), u"bu"_s, 1, 2)); + QCOMPARE(res, 242); + } + + { + auto lambda = [](const QString &s) { return s + s; }; + QVERIFY(QMetaObject::invokeMethod(&obj, lambda, qReturnArg(result), u"bu"_s)); + QCOMPARE(result, u"bubu"); + } + + { + auto lambda = [](const QString &s = u"bu"_s) { return s + s; }; + QVERIFY(QMetaObject::invokeMethod(&obj, lambda, qReturnArg(result))); + QCOMPARE(result, u"bubu"); + + QVERIFY(QMetaObject::invokeMethod(&obj, lambda, qReturnArg(result), u"bye"_s)); + QCOMPARE(result, u"byebye"); + } + + { + auto lambda = [](const QString &s, qint64 a, qint16 b, qint8 c) { + return s + QString::number(a) + QString::number(b) + QString::number(c); + }; + // Testing mismatching argument (int for qint64). The other arguments + // would static_assert for potential truncation if they were ints. + QVERIFY(QMetaObject::invokeMethod(&obj, lambda, qReturnArg(result), u"bu"_s, 1, qint16(2), qint8(3))); + QCOMPARE(result, u"bu123"); + } + { + // Testing deduction + auto lambda = [](const QString &s, auto a) { return s + a; }; + QVERIFY(QMetaObject::invokeMethod(&obj, lambda, qReturnArg(result), u"bu"_s, "bu"_L1)); + QCOMPARE(result, u"bubu"); + + auto variadic = [](const QString &s, auto... a) { return s + (QString::number(a) + ...); }; + QVERIFY(QMetaObject::invokeMethod(&obj, variadic, qReturnArg(result), u"bu"_s, 1, 2, 3, 4, 5, 6)); + QCOMPARE(result, u"bu123456"); + } + { + // Testing a functor returning void and accepting a pointer, + // this may trigger the pointer to be interpreted as the old void* + // return parameter. + bool invoked = false; + auto lambda = [&invoked](void *ptr) -> void { + Q_UNUSED(ptr); + invoked = true; + }; + int i = 242; + QVERIFY(QMetaObject::invokeMethod(&obj, lambda, &i)); + QVERIFY(invoked); + + // member fn + i = 0; + QVERIFY(QMetaObject::invokeMethod(&obj, &QtTestObject::sl17, &i)); + QCOMPARE(i, 242); + } } void tst_QMetaObject::invokeQueuedMetaMember() { QtTestObject obj; - QVERIFY(QMetaObject::invokeMethod(&obj, "sl0", Qt::QueuedConnection)); + QVERIFY(QMetaObject::invokeMethod(&obj, "sl0", Qt::QueuedConnection Q_NO_ARG)); QVERIFY(obj.slotResult.isEmpty()); qApp->processEvents(QEventLoop::AllEvents); QCOMPARE(obj.slotResult, QString("sl0")); @@ -860,10 +1225,36 @@ void tst_QMetaObject::invokeQueuedMetaMember() qApp->processEvents(QEventLoop::AllEvents); QCOMPARE(obj.slotResult, QString("sl9:123456789")); + // pointers + qint64 return64; + obj.slotResult.clear(); + QVERIFY(QMetaObject::invokeMethod(&obj, "sl15", Qt::QueuedConnection, Q_ARG(qlonglong*, &return64))); + qApp->processEvents(QEventLoop::AllEvents); + QCOMPARE(obj.slotResult, QString("sl15")); + + // since Qt 6.5, this works even for pointers to forward-declared types + obj.slotResult.clear(); + QVERIFY(QMetaObject::invokeMethod(&obj, "sl16", Qt::QueuedConnection, Q_ARG(MyForwardDeclaredType*, getForwardDeclaredPointer()))); + qApp->processEvents(QEventLoop::AllEvents); + QCOMPARE(obj.slotResult, QString("sl16:notnull")); + +#ifndef QT_NO_DATA_RELOCATION // this doesn't work with the new API on Windows +#endif + // test overloads + QVERIFY(QMetaObject::invokeMethod(&obj, "overloadedSlot", Qt::QueuedConnection Q_NO_ARG)); + qApp->processEvents(QEventLoop::AllEvents); + QCOMPARE(obj.slotResult, QString("overloadedSlot")); + QVERIFY(QMetaObject::invokeMethod(&obj, "overloadedSlot", Qt::QueuedConnection, Q_ARG(int, 1))); + qApp->processEvents(QEventLoop::AllEvents); + QCOMPARE(obj.slotResult, QString("overloadedSlot:1")); + QVERIFY(QMetaObject::invokeMethod(&obj, "overloadedSlot", Qt::QueuedConnection, Q_ARG(int, 1), Q_ARG(int, 42))); + qApp->processEvents(QEventLoop::AllEvents); + QCOMPARE(obj.slotResult, QString("overloadedSlot:1,42")); + // signals obj.slotResult.clear(); - QVERIFY(QMetaObject::invokeMethod(&obj, "sig0", Qt::QueuedConnection)); + QVERIFY(QMetaObject::invokeMethod(&obj, "sig0", Qt::QueuedConnection Q_NO_ARG)); QVERIFY(obj.slotResult.isEmpty()); qApp->processEvents(QEventLoop::AllEvents); QCOMPARE(obj.slotResult, QString("sl0")); @@ -887,23 +1278,142 @@ void tst_QMetaObject::invokeQueuedMetaMember() qApp->processEvents(QEventLoop::AllEvents); QCOMPARE(obj.slotResult, QString("testLongLong:-1,0")); + QTest::ignoreMessage(QtWarningMsg, "QMetaObject::invokeMethod: No such method QtTestObject::testReference(QString)\n" + "Candidates are:\n testReference(QString&)"); + QVERIFY(!QMetaObject::invokeMethod(&obj, "testReference", Qt::QueuedConnection, Q_ARG(QString, exp))); + + QString refStr = "whatever"; + QTest::ignoreMessage(QtWarningMsg, "QMetaMethod::invoke: Unable to handle unregistered datatype 'QString&'"); + QVERIFY(!QMetaObject::invokeMethod(&obj, "testReference", Qt::QueuedConnection, Q_ARG(QString&, refStr))); + QCOMPARE(refStr, "whatever"); + +#ifdef USE_COMPAT_Q_ARG // this doesn't compile with the new API obj.slotResult.clear(); { - MyUnregisteredType t; - QTest::ignoreMessage(QtWarningMsg, "QMetaMethod::invoke: Unable to handle unregistered datatype 'MyUnregisteredType'"); - QVERIFY(!QMetaObject::invokeMethod(&obj, "slotWithUnregisteredParameterType", Qt::QueuedConnection, Q_ARG(MyUnregisteredType, t))); + const MyForwardDeclaredType &t = getForwardDeclaredType(); + QTest::ignoreMessage(QtWarningMsg, "QMetaMethod::invoke: Unable to handle unregistered datatype 'MyForwardDeclaredType'"); + QVERIFY(!QMetaObject::invokeMethod(&obj, "slotWithUnregisteredParameterType", Qt::QueuedConnection, Q_ARG(MyForwardDeclaredType, t))); QVERIFY(obj.slotResult.isEmpty()); } obj.slotResult.clear(); { QString a1("Cannot happen"); - MyUnregisteredType t; - QTest::ignoreMessage(QtWarningMsg, "QMetaMethod::invoke: Unable to handle unregistered datatype 'MyUnregisteredType'"); + const MyForwardDeclaredType &t = getForwardDeclaredType(); + QTest::ignoreMessage(QtWarningMsg, "QMetaMethod::invoke: Unable to handle unregistered datatype 'MyForwardDeclaredType'"); QVERIFY(!QMetaObject::invokeMethod(&obj, "slotWithOneUnregisteredParameterType", Qt::QueuedConnection, - Q_ARG(QString, a1), Q_ARG(MyUnregisteredType, t))); + Q_ARG(QString, a1), Q_ARG(MyForwardDeclaredType, t))); QVERIFY(obj.slotResult.isEmpty()); } +#endif +} + +// this is a copy-paste-adapt of the above +void tst_QMetaObject::invokeQueuedMetaMemberNoMacro() +{ + QtTestObject obj; + + QVERIFY(QMetaObject::invokeMethod(&obj, "sl0", Qt::QueuedConnection)); + QVERIFY(obj.slotResult.isEmpty()); + qApp->processEvents(QEventLoop::AllEvents); + QCOMPARE(obj.slotResult, QString("sl0")); + obj.slotResult = QString(); + + QVERIFY(QMetaObject::invokeMethod(&obj, "sl1", Qt::QueuedConnection, QString("hallo"))); + QVERIFY(obj.slotResult.isEmpty()); + qApp->processEvents(QEventLoop::AllEvents); + QCOMPARE(obj.slotResult, QString("sl1:hallo")); + obj.slotResult = QString(); + + QVERIFY(QMetaObject::invokeMethod(&obj, "sl9", Qt::QueuedConnection, QStringLiteral("1"), QStringLiteral("2"), + QStringLiteral("3"), QStringLiteral("4"), QStringLiteral("5"), + QStringLiteral("6"), QStringLiteral("7"), QStringLiteral("8"), + QStringLiteral("9"))); + QVERIFY(obj.slotResult.isEmpty()); + qApp->processEvents(QEventLoop::AllEvents); + QCOMPARE(obj.slotResult, QString("sl9:123456789")); + + // pointers + qint64 return64; + obj.slotResult.clear(); + QVERIFY(QMetaObject::invokeMethod(&obj, "sl15", Qt::QueuedConnection, &return64)); + qApp->processEvents(QEventLoop::AllEvents); + QCOMPARE(obj.slotResult, QString("sl15")); + + obj.slotResult.clear(); + QVERIFY(QMetaObject::invokeMethod(&obj, "sl16", Qt::QueuedConnection, getForwardDeclaredPointer())); + qApp->processEvents(QEventLoop::AllEvents); + QCOMPARE(obj.slotResult, QString("sl16:notnull")); + + // test overloads + QVERIFY(QMetaObject::invokeMethod(&obj, "overloadedSlot", Qt::QueuedConnection)); + qApp->processEvents(QEventLoop::AllEvents); + QCOMPARE(obj.slotResult, QString("overloadedSlot")); + QVERIFY(QMetaObject::invokeMethod(&obj, "overloadedSlot", Qt::QueuedConnection, 1)); + qApp->processEvents(QEventLoop::AllEvents); + QCOMPARE(obj.slotResult, QString("overloadedSlot:1")); + QVERIFY(QMetaObject::invokeMethod(&obj, "overloadedSlot", Qt::QueuedConnection, 1, 42)); + qApp->processEvents(QEventLoop::AllEvents); + QCOMPARE(obj.slotResult, QString("overloadedSlot:1,42")); + + // signals + + obj.slotResult.clear(); + QVERIFY(QMetaObject::invokeMethod(&obj, "sig0", Qt::QueuedConnection)); + QVERIFY(obj.slotResult.isEmpty()); + qApp->processEvents(QEventLoop::AllEvents); + QCOMPARE(obj.slotResult, QString("sl0")); + + QVERIFY(QMetaObject::invokeMethod(&obj, "sig1", Qt::QueuedConnection, QStringLiteral("gogo"))); + qApp->processEvents(QEventLoop::AllEvents); + QCOMPARE(obj.slotResult, QString("sl1:gogo")); + + QString exp; + QTest::ignoreMessage(QtWarningMsg, "QMetaMethod::invoke: Unable to invoke methods with return values in queued connections"); + QVERIFY(!QMetaObject::invokeMethod(&obj, "sig1", Qt::QueuedConnection, qReturnArg(exp), + QStringLiteral("nono"))); + + qint64 ll1 = -1; + quint64 ll2 = 0; + QVERIFY(QMetaObject::invokeMethod(&obj, + "testLongLong", + Qt::QueuedConnection, + ll1, + ll2)); + qApp->processEvents(QEventLoop::AllEvents); + QCOMPARE(obj.slotResult, QString("testLongLong:-1,0")); + + QTest::ignoreMessage(QtWarningMsg, "QMetaObject::invokeMethod: No such method QtTestObject::testReference(QString)\n" + "Candidates are:\n testReference(QString&)"); + QVERIFY(!QMetaObject::invokeMethod(&obj, "testReference", exp)); + QCOMPARE(obj.slotResult, QString("testLongLong:-1,0")); + QVERIFY(exp.isEmpty()); + + // this doesn't work yet +// QString refStr = "whatever"; +// QTest::ignoreMessage(QtWarningMsg, "QMetaMethod::invoke: Unable to handle unregistered datatype 'QString&'"); +// QVERIFY(!QMetaObject::invokeMethod(&obj, "testReference", Qt::QueuedConnection, Q_ARG(QString&, refStr))); +// QCOMPARE(refStr, "whatever"); + +#if 0 // this won't even compile any more + obj.slotResult.clear(); + { + const MyForwardDeclaredType &t = getForwardDeclaredType(); + QTest::ignoreMessage(QtWarningMsg, "QMetaMethod::invoke: Unable to handle unregistered datatype 'MyForwardDeclaredType'"); + QVERIFY(!QMetaObject::invokeMethod(&obj, "slotWithUnregisteredParameterType", Qt::QueuedConnection, t)); + QVERIFY(obj.slotResult.isEmpty()); + } + + obj.slotResult.clear(); + { + QString a1("Cannot happen"); + const MyForwardDeclaredType &t = getForwardDeclaredType(); + QTest::ignoreMessage(QtWarningMsg, "QMetaMethod::invoke: Unable to handle unregistered datatype 'MyForwardDeclaredType'"); + QVERIFY(!QMetaObject::invokeMethod(&obj, "slotWithOneUnregisteredParameterType", Qt::QueuedConnection, + a1, t)); + QVERIFY(obj.slotResult.isEmpty()); + } +#endif } void tst_QMetaObject::invokeQueuedPointer() @@ -953,9 +1463,15 @@ void tst_QMetaObject::invokeQueuedPointer() QCOMPARE(var, 0); } QCOMPARE(countedStructObjectsCount, 0); -} + // Invoking with parameters + using namespace Qt::StringLiterals; + QVERIFY(QMetaObject::invokeMethod(&obj, &QtTestObject::sl1, Qt::QueuedConnection, u"bubu"_s)); + qApp->processEvents(QEventLoop::AllEvents); + QCOMPARE(obj.slotResult, u"sl1:bubu"); +} +// this test is duplicated below void tst_QMetaObject::invokeBlockingQueuedMetaMember() { QThread t; @@ -1002,16 +1518,23 @@ void tst_QMetaObject::invokeBlockingQueuedMetaMember() Q_ARG(QString, t7), Q_ARG(QString, t8), Q_ARG(QString, t9))); QCOMPARE(obj.slotResult, QString("sl9:123456789")); - QVERIFY(QMetaObject::invokeMethod(&obj, "sl11", Qt::BlockingQueuedConnection)); + QVERIFY(QMetaObject::invokeMethod(&obj, "sl11", Qt::BlockingQueuedConnection Q_NO_ARG)); QCOMPARE(obj.slotResult, QString("sl11")); - QVERIFY(QMetaObject::invokeMethod(&obj, "testSender", Qt::BlockingQueuedConnection)); + QVERIFY(QMetaObject::invokeMethod(&obj, "testSender", Qt::BlockingQueuedConnection Q_NO_ARG)); QCOMPARE(obj.slotResult, QString("0x0")); QString refStr("whatever"); +#ifdef USE_COMPAT_Q_ARG QVERIFY(QMetaObject::invokeMethod(&obj, "testReference", Qt::BlockingQueuedConnection, QGenericArgument("QString&", &refStr))); QCOMPARE(obj.slotResult, QString("testReference:whatever")); QCOMPARE(refStr, QString("gotcha")); + obj.slotResult.clear(); +#endif + refStr = "whatever"; + QVERIFY(QMetaObject::invokeMethod(&obj, "testReference", Qt::BlockingQueuedConnection, Q_ARG(QString&, refStr))); + QCOMPARE(obj.slotResult, QString("testReference:whatever")); + QCOMPARE(refStr, QString("gotcha")); qint64 ll1 = -1; quint64 ll2 = 0; @@ -1056,8 +1579,44 @@ void tst_QMetaObject::invokeBlockingQueuedMetaMember() QCOMPARE(returnValue, argument); QCOMPARE(obj.slotResult, QString("sl13")); + // return qint64 + qint64 return64; + QVERIFY(QMetaObject::invokeMethod(&obj, "sl14", Qt::BlockingQueuedConnection, + Q_RETURN_ARG(qint64, return64))); + QCOMPARE(return64, Q_INT64_C(123456789)*123456789); + QCOMPARE(obj.slotResult, QString("sl14")); + + // pointers + QVERIFY(QMetaObject::invokeMethod(&obj, "sl15", Qt::BlockingQueuedConnection, Q_ARG(qlonglong*, &return64))); + QCOMPARE(obj.slotResult, QString("sl15")); + QVERIFY(QMetaObject::invokeMethod(&obj, "sl16", Qt::BlockingQueuedConnection, Q_ARG(MyForwardDeclaredType*, getForwardDeclaredPointer()))); + QCOMPARE(obj.slotResult, QString("sl16:notnull")); + + obj.slotResult.clear(); + qint64 *return64Ptr; + QVERIFY(QMetaObject::invokeMethod(&obj, "sl15", Qt::BlockingQueuedConnection, Q_RETURN_ARG(qlonglong*, return64Ptr), Q_ARG(qlonglong*, &return64))); + QCOMPARE(return64Ptr, &return64); + QCOMPARE(obj.slotResult, QString("sl15")); + + obj.slotResult.clear(); + MyForwardDeclaredType *forwardPtr; + QVERIFY(QMetaObject::invokeMethod(&obj, "sl16", Qt::BlockingQueuedConnection, Q_RETURN_ARG(MyForwardDeclaredType*, forwardPtr), + Q_ARG(MyForwardDeclaredType*, nullptr))); + QCOMPARE(forwardPtr, getForwardDeclaredPointer()); + QCOMPARE(obj.slotResult, QString("sl16:null")); + +#ifndef QT_NO_DATA_RELOCATION // this doesn't work with the new API on Windows +#endif + // test overloads + QVERIFY(QMetaObject::invokeMethod(&obj, "overloadedSlot", Qt::BlockingQueuedConnection Q_NO_ARG)); + QCOMPARE(obj.slotResult, QString("overloadedSlot")); + QVERIFY(QMetaObject::invokeMethod(&obj, "overloadedSlot", Qt::BlockingQueuedConnection, Q_ARG(int, 1))); + QCOMPARE(obj.slotResult, QString("overloadedSlot:1")); + QVERIFY(QMetaObject::invokeMethod(&obj, "overloadedSlot", Qt::BlockingQueuedConnection, Q_ARG(int, 1), Q_ARG(int, 42))); + QCOMPARE(obj.slotResult, QString("overloadedSlot:1,42")); + //test signals - QVERIFY(QMetaObject::invokeMethod(&obj, "sig0", Qt::BlockingQueuedConnection)); + QVERIFY(QMetaObject::invokeMethod(&obj, "sig0", Qt::BlockingQueuedConnection Q_NO_ARG)); QCOMPARE(obj.slotResult, QString("sl0")); QVERIFY(QMetaObject::invokeMethod(&obj, "sig1", Qt::BlockingQueuedConnection, Q_ARG(QString, "baba"))); @@ -1069,7 +1628,7 @@ void tst_QMetaObject::invokeBlockingQueuedMetaMember() QCOMPARE(obj.slotResult, QString("sl1:hehe")); QTest::ignoreMessage(QtWarningMsg, "QMetaObject::invokeMethod: No such method QtTestObject::doesNotExist()"); - QVERIFY(!QMetaObject::invokeMethod(&obj, "doesNotExist", Qt::BlockingQueuedConnection)); + QVERIFY(!QMetaObject::invokeMethod(&obj, "doesNotExist", Qt::BlockingQueuedConnection Q_NO_ARG)); QTest::ignoreMessage(QtWarningMsg, "QMetaObject::invokeMethod: No such method QtTestObject::sl1(QString)(QString)"); QVERIFY(!QMetaObject::invokeMethod(&obj, "sl1(QString)", Qt::BlockingQueuedConnection, Q_ARG(QString, "arg"))); QTest::ignoreMessage(QtWarningMsg, "QMetaObject::invokeMethod: No such method QtTestObject::sl3(QString)\n" @@ -1078,6 +1637,9 @@ void tst_QMetaObject::invokeBlockingQueuedMetaMember() QTest::ignoreMessage(QtWarningMsg, "QMetaObject::invokeMethod: No such method QtTestObject::sl1(QString,QString,QString)\n" "Candidates are:\n sl1(QString)"); QVERIFY(!QMetaObject::invokeMethod(&obj, "sl1", Qt::BlockingQueuedConnection, Q_ARG(QString, "arg"), Q_ARG(QString, "arg"), Q_ARG(QString, "arg"))); + QTest::ignoreMessage(QtWarningMsg, "QMetaObject::invokeMethod: No such method QtTestObject::testReference(QString)\n" + "Candidates are:\n testReference(QString&)"); + QVERIFY(!QMetaObject::invokeMethod(&obj, "testReference", Qt::BlockingQueuedConnection, Q_ARG(QString, exp))); //should not have changed since last test. QCOMPARE(exp, QString("yessir")); @@ -1086,7 +1648,177 @@ void tst_QMetaObject::invokeBlockingQueuedMetaMember() QVERIFY(QMetaObject::invokeMethod(&obj, "moveToThread", Qt::BlockingQueuedConnection, Q_ARG(QThread*, QThread::currentThread()))); t.quit(); QVERIFY(t.wait()); +} + +// this is a copy-paste-adapt of the above +void tst_QMetaObject::invokeBlockingQueuedMetaMemberNoMacros() +{ + QThread t; + t.start(); + QtTestObject obj; + obj.moveToThread(&t); + + QString t1("1"); QString t2("2"); QString t3("3"); QString t4("4"); QString t5("5"); + QString t6("6"); QString t7("7"); QString t8("8"); QString t9("9"); QString t10("X"); + + QVERIFY(QMetaObject::invokeMethod(&obj, "sl1", Qt::BlockingQueuedConnection, t1)); + QCOMPARE(obj.slotResult, QString("sl1:1")); + + QVERIFY(QMetaObject::invokeMethod(&obj, "sl2", Qt::BlockingQueuedConnection, t1, t2)); + QCOMPARE(obj.slotResult, QString("sl2:12")); + + QVERIFY(QMetaObject::invokeMethod(&obj, "sl3", Qt::BlockingQueuedConnection, t1, t2, t3)); + QCOMPARE(obj.slotResult, QString("sl3:123")); + + QVERIFY(QMetaObject::invokeMethod(&obj, "sl4", Qt::BlockingQueuedConnection, t1, t2, + t3, t4)); + QCOMPARE(obj.slotResult, QString("sl4:1234")); + + QVERIFY(QMetaObject::invokeMethod(&obj, "sl5", Qt::BlockingQueuedConnection, t1, t2, + t3, t4, QStringLiteral("5"))); + QCOMPARE(obj.slotResult, QString("sl5:12345")); + + QVERIFY(QMetaObject::invokeMethod(&obj, "sl6", Qt::BlockingQueuedConnection, t1, t2, + t3, t4, t5, t6)); + QCOMPARE(obj.slotResult, QString("sl6:123456")); + + QVERIFY(QMetaObject::invokeMethod(&obj, "sl7", Qt::BlockingQueuedConnection, t1, t2, + t3, t4, t5, t6, + t7)); + QCOMPARE(obj.slotResult, QString("sl7:1234567")); + QVERIFY(QMetaObject::invokeMethod(&obj, "sl8", Qt::BlockingQueuedConnection, t1, t2, + t3, t4, t5, t6, + t7, t8)); + QCOMPARE(obj.slotResult, QString("sl8:12345678")); + + QVERIFY(QMetaObject::invokeMethod(&obj, "sl9", Qt::BlockingQueuedConnection, t1, t2, + t3, t4, t5, t6, + t7, t8, t9)); + QCOMPARE(obj.slotResult, QString("sl9:123456789")); + + QVERIFY(QMetaObject::invokeMethod(&obj, "sl11", Qt::BlockingQueuedConnection)); + QCOMPARE(obj.slotResult, QString("sl11")); + + QVERIFY(QMetaObject::invokeMethod(&obj, "testSender", Qt::BlockingQueuedConnection)); + QCOMPARE(obj.slotResult, QString("0x0")); + + // this is not working +// QString refStr("whatever"); +// QVERIFY(QMetaObject::invokeMethod(&obj, "testReference", Qt::BlockingQueuedConnection, refStr)); +// QCOMPARE(obj.slotResult, QString("testReference:whatever")); +// QCOMPARE(refStr, QString("gotcha")); + + qint64 ll1 = -1; + quint64 ll2 = 0; + QVERIFY(QMetaObject::invokeMethod(&obj, + "testLongLong", + Qt::BlockingQueuedConnection, + ll1, + ll2)); + QCOMPARE(obj.slotResult, QString("testLongLong:-1,0")); + + QString exp; + QVERIFY(QMetaObject::invokeMethod(&obj, "sl1", Qt::BlockingQueuedConnection, qReturnArg(exp), QStringLiteral("bubu"))); + QCOMPARE(exp, QString("yessir")); + QCOMPARE(obj.slotResult, QString("sl1:bubu")); + + QObject *ptr = nullptr; + QVERIFY(QMetaObject::invokeMethod(&obj, "sl11", Qt::BlockingQueuedConnection, qReturnArg(ptr))); + QCOMPARE(ptr, (QObject *)&obj); + QCOMPARE(obj.slotResult, QString("sl11")); + // try again with a space: + ptr = nullptr; + QVERIFY(QMetaObject::invokeMethod(&obj, "sl11", Qt::BlockingQueuedConnection, qReturnArg(ptr))); + QCOMPARE(ptr, (QObject *)&obj); + QCOMPARE(obj.slotResult, QString("sl11")); + + const char *ptr2 = 0; + QVERIFY(QMetaObject::invokeMethod(&obj, "sl12", Qt::BlockingQueuedConnection, qReturnArg(ptr2))); + QVERIFY(ptr2 != 0); + QCOMPARE(obj.slotResult, QString("sl12")); + // try again with a space: + ptr2 = 0; + QVERIFY(QMetaObject::invokeMethod(&obj, "sl12", Qt::BlockingQueuedConnection, qReturnArg(ptr2))); + QVERIFY(ptr2 != 0); + QCOMPARE(obj.slotResult, QString("sl12")); + + // test w/ template args + QList<QString> returnValue, argument; + argument << QString("one") << QString("two") << QString("three"); + QVERIFY(QMetaObject::invokeMethod(&obj, "sl13", Qt::BlockingQueuedConnection, + qReturnArg(returnValue), + argument)); + QCOMPARE(returnValue, argument); + QCOMPARE(obj.slotResult, QString("sl13")); + + // return qint64 + qint64 return64; + QVERIFY(QMetaObject::invokeMethod(&obj, "sl14", Qt::BlockingQueuedConnection, + qReturnArg(return64))); + QCOMPARE(return64, Q_INT64_C(123456789)*123456789); + QCOMPARE(obj.slotResult, QString("sl14")); + + // pointers + QVERIFY(QMetaObject::invokeMethod(&obj, "sl15", Qt::BlockingQueuedConnection, &return64)); + QCOMPARE(obj.slotResult, QString("sl15")); + QVERIFY(QMetaObject::invokeMethod(&obj, "sl16", Qt::BlockingQueuedConnection, getForwardDeclaredPointer())); + QCOMPARE(obj.slotResult, QString("sl16:notnull")); + + obj.slotResult.clear(); + qint64 *return64Ptr; + QVERIFY(QMetaObject::invokeMethod(&obj, "sl15", Qt::BlockingQueuedConnection, qReturnArg(return64Ptr), &return64)); + QCOMPARE(return64Ptr, &return64); + QCOMPARE(obj.slotResult, QString("sl15")); + + obj.slotResult.clear(); + MyForwardDeclaredType *forwardPtr = nullptr; + QVERIFY(QMetaObject::invokeMethod(&obj, "sl16", Qt::BlockingQueuedConnection, qReturnArg(forwardPtr), + forwardPtr)); + QCOMPARE(forwardPtr, getForwardDeclaredPointer()); + QCOMPARE(obj.slotResult, QString("sl16:null")); + + // test overloads + QVERIFY(QMetaObject::invokeMethod(&obj, "overloadedSlot", Qt::BlockingQueuedConnection)); + QCOMPARE(obj.slotResult, QString("overloadedSlot")); + QVERIFY(QMetaObject::invokeMethod(&obj, "overloadedSlot", Qt::BlockingQueuedConnection, 1)); + QCOMPARE(obj.slotResult, QString("overloadedSlot:1")); + QVERIFY(QMetaObject::invokeMethod(&obj, "overloadedSlot", Qt::BlockingQueuedConnection, 1, 42)); + QCOMPARE(obj.slotResult, QString("overloadedSlot:1,42")); + + //test signals + QVERIFY(QMetaObject::invokeMethod(&obj, "sig0", Qt::BlockingQueuedConnection)); + QCOMPARE(obj.slotResult, QString("sl0")); + + QVERIFY(QMetaObject::invokeMethod(&obj, "sig1", Qt::BlockingQueuedConnection, QStringLiteral("baba"))); + QCOMPARE(obj.slotResult, QString("sl1:baba")); + + exp.clear(); + QVERIFY(QMetaObject::invokeMethod(&obj, "sig1", Qt::BlockingQueuedConnection, qReturnArg(exp), QStringLiteral("hehe"))); + QCOMPARE(exp, QString("yessir")); + QCOMPARE(obj.slotResult, QString("sl1:hehe")); + + QTest::ignoreMessage(QtWarningMsg, "QMetaObject::invokeMethod: No such method QtTestObject::doesNotExist()"); + QVERIFY(!QMetaObject::invokeMethod(&obj, "doesNotExist", Qt::BlockingQueuedConnection)); + QTest::ignoreMessage(QtWarningMsg, "QMetaObject::invokeMethod: No such method QtTestObject::sl1(QString)(QString)"); + QVERIFY(!QMetaObject::invokeMethod(&obj, "sl1(QString)", Qt::BlockingQueuedConnection, QStringLiteral("arg"))); + QTest::ignoreMessage(QtWarningMsg, "QMetaObject::invokeMethod: No such method QtTestObject::sl3(QString)\n" + "Candidates are:\n sl3(QString,QString,QString)"); + QVERIFY(!QMetaObject::invokeMethod(&obj, "sl3", Qt::BlockingQueuedConnection, QStringLiteral("arg"))); + QTest::ignoreMessage(QtWarningMsg, "QMetaObject::invokeMethod: No such method QtTestObject::sl1(QString,QString,QString)\n" + "Candidates are:\n sl1(QString)"); + QVERIFY(!QMetaObject::invokeMethod(&obj, "sl1", Qt::BlockingQueuedConnection, QStringLiteral("arg"), QStringLiteral("arg"), QStringLiteral("arg"))); + QTest::ignoreMessage(QtWarningMsg, "QMetaObject::invokeMethod: No such method QtTestObject::testReference(QString)\n" + "Candidates are:\n testReference(QString&)"); + QVERIFY(!QMetaObject::invokeMethod(&obj, "testReference", Qt::BlockingQueuedConnection, exp)); + + //should not have changed since last test. + QCOMPARE(exp, QString("yessir")); + QCOMPARE(obj.slotResult, QString("sl1:hehe")); + + QVERIFY(QMetaObject::invokeMethod(&obj, "moveToThread", Qt::BlockingQueuedConnection, QThread::currentThread())); + t.quit(); + QVERIFY(t.wait()); } void tst_QMetaObject::invokeBlockingQueuedPointer() @@ -1149,7 +1881,6 @@ void tst_QMetaObject::invokeBlockingQueuedPointer() QCOMPARE(exp, QString("yessir")); QCOMPARE(obj.slotResult, QString("sl1:bubu")); } -#ifdef __cpp_init_captures { std::unique_ptr<int> ptr(new int); QVERIFY(QMetaObject::invokeMethod(&obj, @@ -1157,7 +1888,18 @@ void tst_QMetaObject::invokeBlockingQueuedPointer() Qt::BlockingQueuedConnection)); QCOMPARE(obj.slotResult, QString("sl1:hehe")); } -#endif + + // Test with parameters + QString result; + QVERIFY(QMetaObject::invokeMethod(&obj, &QtTestObject::sl1, Qt::BlockingQueuedConnection, + qReturnArg(result), u"bubu"_s)); + QCOMPARE(result, u"yessir"); + QCOMPARE(obj.slotResult, u"sl1:bubu"); + + QVERIFY(QMetaObject::invokeMethod(&obj, &QtTestObject::sl2, Qt::BlockingQueuedConnection, + u"bubu"_s, u"baba"_s)); + QCOMPARE(obj.slotResult, u"sl2:bububaba"); + QVERIFY(QMetaObject::invokeMethod(&obj, [&](){obj.moveToThread(QThread::currentThread());}, Qt::BlockingQueuedConnection)); t.quit(); QVERIFY(t.wait()); @@ -1168,6 +1910,7 @@ void tst_QMetaObject::invokeBlockingQueuedPointer() void tst_QMetaObject::qtMetaObjectInheritance() { QVERIFY(!QObject::staticMetaObject.superClass()); +#if QT_CONFIG(sortfilterproxymodel) QCOMPARE(QSortFilterProxyModel::staticMetaObject.indexOfEnumerator("Qt::CaseSensitivity"), -1); QCOMPARE(QSortFilterProxyModel::staticMetaObject.indexOfEnumerator("CaseSensitivity"), -1); int indexOfSortCaseSensitivity = QSortFilterProxyModel::staticMetaObject.indexOfProperty("sortCaseSensitivity"); @@ -1175,6 +1918,7 @@ void tst_QMetaObject::qtMetaObjectInheritance() QMetaProperty sortCaseSensitivity = QSortFilterProxyModel::staticMetaObject.property(indexOfSortCaseSensitivity); QVERIFY(sortCaseSensitivity.isValid()); QCOMPARE(sortCaseSensitivity.enumerator().name(), "CaseSensitivity"); +#endif } struct MyType @@ -1214,6 +1958,10 @@ void tst_QMetaObject::invokeCustomTypes() QCOMPARE(obj.sum, 0); QVERIFY(QMetaObject::invokeMethod(&obj, "sl1", Q_ARG(MyType, tp))); QCOMPARE(obj.sum, 3); + + obj.sum = 0; + QVERIFY(QMetaObject::invokeMethod(&obj, "sl1", tp)); + QCOMPARE(obj.sum, 3); } namespace NamespaceWithConstructibleClass @@ -1229,13 +1977,16 @@ public: } +// this test is duplicated below void tst_QMetaObject::invokeMetaConstructor() { const QMetaObject *mo = &QtTestObject::staticMetaObject; +#ifdef USE_COMPAT_Q_ARG { - QObject *obj = mo->newInstance(); + QObject *obj = mo->newInstance(QGenericArgument()); QVERIFY(!obj); } +#endif { QtTestObject obj; QObject *obj2 = mo->newInstance(Q_ARG(QObject*, &obj)); @@ -1258,6 +2009,56 @@ void tst_QMetaObject::invokeMetaConstructor() QTest::ignoreMessage(QtWarningMsg, "QMetaObject::newInstance: type MyGadget does not inherit QObject"); QVERIFY(!MyGadget::staticMetaObject.newInstance()); } + + // overloaded constructors + QObject parent; + { + QObject *obj = mo->newInstance(Q_ARG(QObject*, &parent)); + QVERIFY(obj); + QCOMPARE(static_cast<QtTestObject*>(obj)->slotResult, ""); + } + { + QObject *obj = mo->newInstance(Q_ARG(QObject*, &parent), Q_ARG(int, 1)); + QVERIFY(obj); + QCOMPARE(static_cast<QtTestObject*>(obj)->slotResult, "i"); + } + { + QObject *obj = mo->newInstance(Q_ARG(QObject*, &parent), Q_ARG(int, 1), Q_ARG(int, 42)); + QVERIFY(obj); + QCOMPARE(static_cast<QtTestObject*>(obj)->slotResult, "ii"); + } +} + +// this is a copy-paste-adapt of the above +void tst_QMetaObject::invokeMetaConstructorNoMacro() +{ + const QMetaObject *mo = &QtTestObject::staticMetaObject; + { + QObject *obj = mo->newInstance(); + QVERIFY(!obj); + } + { + QtTestObject obj; + QObject *obj2 = mo->newInstance(static_cast<QObject *>(&obj)); + QVERIFY(obj2 != 0); + QCOMPARE(obj2->parent(), (QObject*)&obj); + QVERIFY(qobject_cast<QtTestObject*>(obj2) != 0); + } + // class in namespace + const QMetaObject *nsmo = &NamespaceWithConstructibleClass::ConstructibleClass::staticMetaObject; + { + QtTestObject obj; + QObject *obj2 = nsmo->newInstance(static_cast<QObject *>(&obj)); + QVERIFY(obj2 != 0); + QCOMPARE(obj2->parent(), (QObject*)&obj); + QVERIFY(qobject_cast<NamespaceWithConstructibleClass::ConstructibleClass*>(obj2) != 0); + } + // gadget shouldn't return a valid pointer + { + QCOMPARE(MyGadget::staticMetaObject.constructorCount(), 1); + QTest::ignoreMessage(QtWarningMsg, "QMetaObject::newInstance: type MyGadget does not inherit QObject"); + QVERIFY(!MyGadget::staticMetaObject.newInstance()); + } } void tst_QMetaObject::invokeTypedefTypes() @@ -1267,11 +2068,17 @@ void tst_QMetaObject::invokeTypedefTypes() QSignalSpy spy(&obj, &QtTestCustomObject::sig_custom); QVERIFY(spy.isValid()); - QCOMPARE(spy.count(), 0); + QCOMPARE(spy.size(), 0); CustomString arg("hello"); QVERIFY(QMetaObject::invokeMethod(&obj, "sig_custom", Q_ARG(CustomString, arg))); - QCOMPARE(spy.count(), 1); - QCOMPARE(spy.at(0).count(), 1); + QCOMPARE(spy.size(), 1); + QCOMPARE(spy.at(0).size(), 1); + QCOMPARE(spy.at(0).at(0), QVariant(arg)); + + spy.clear(); + QVERIFY(QMetaObject::invokeMethod(&obj, "sig_custom", arg)); + QCOMPARE(spy.size(), 1); + QCOMPARE(spy.at(0).size(), 1); QCOMPARE(spy.at(0).at(0), QVariant(arg)); } @@ -1287,6 +2094,14 @@ void tst_QMetaObject::invokeException() QFAIL("Did not throw"); } catch(ObjectException &) {} QCOMPARE(countedStructObjectsCount, 0); + + try { + CountedStruct s; + QVERIFY(QMetaObject::invokeMethod(&obj, "throwingSlot", qReturnArg(s), + s, s)); + QFAIL("Did not throw"); + } catch(ObjectException &) {} + QCOMPARE(countedStructObjectsCount, 0); #else QSKIP("Needs exceptions"); #endif @@ -1308,6 +2123,61 @@ void tst_QMetaObject::invokeQueuedAutoRegister() qApp->processEvents(QEventLoop::AllEvents); QCOMPARE(obj.slotResult, QString("slotWithRegistrableArgument:myShared-myShared-myShared-myShared-00")); + + obj.slotResult.clear(); + QVERIFY(QMetaObject::invokeMethod( + &obj, "slotWithRegistrableArgument", Qt::QueuedConnection, + shared.data(), QPointer<QtTestObject>(shared.data()), + QSharedPointer<QtTestObject>(shared), QWeakPointer<QtTestObject>(shared), + QList<QtTestObject *>(), + QList<QtTestObject *>())); + QVERIFY(obj.slotResult.isEmpty()); + qApp->processEvents(QEventLoop::AllEvents); + QCOMPARE(obj.slotResult, + QString("slotWithRegistrableArgument:myShared-myShared-myShared-myShared-00")); +} + +namespace FunctionTest { + static void function0() {} + static int functionNoExcept() noexcept + { + return 42; + } +} + +void tst_QMetaObject::invokeFreeFunction() +{ + using namespace FunctionTest; + QtTestObject obj; + QMetaObject::invokeMethod(&obj, function0); + int retInt = -1; + QMetaObject::invokeMethod(&obj, functionNoExcept, &retInt); + QCOMPARE(retInt, functionNoExcept()); +} + +void tst_QMetaObject::invokeBind() +{ + QtTestObject obj; + + struct { + int number; + QString string; + } results; + + const auto function = [&results](int number, const QString &string) -> bool { + results.number = number; + results.string = string; + return true; + }; + + const int number = 42; + const QString string("Test"); + const auto binding = std::bind(function, number, string); + bool ret = false; + QMetaObject::invokeMethod(&obj, binding, &ret); + QVERIFY(ret); + QCOMPARE(results.number, number); + QCOMPARE(results.string, string); } void tst_QMetaObject::normalizedSignature_data() @@ -1475,7 +2345,7 @@ void tst_QMetaObject::customPropertyType() QCOMPARE(prop.metaType().id(), QMetaType::QVariantList); } -void tst_QMetaObject::checkScope_data() +void tst_QMetaObject::keysToValue_data() { QTest::addColumn<QObject *>("object"); QTest::addColumn<QByteArray>("name"); @@ -1489,7 +2359,7 @@ void tst_QMetaObject::checkScope_data() } -void tst_QMetaObject::checkScope() +void tst_QMetaObject::keysToValue() { QFETCH(QObject *, object); QFETCH(QByteArray, name); @@ -1502,6 +2372,8 @@ void tst_QMetaObject::checkScope() QVERIFY(!me.isFlag()); QCOMPARE(QByteArray(me.scope()), QByteArray("MyNamespace::" + name)); QCOMPARE(me.keyToValue("MyNamespace::" + name + "::MyEnum2", &ok), 1); + // Fully qualified unscoped enumerator + QCOMPARE(me.keyToValue("MyNamespace::" + name + "::MyEnum::MyEnum2", &ok), 1); QCOMPARE(ok, true); QCOMPARE(me.keyToValue(name + "::MyEnum2", &ok), -1); QCOMPARE(ok, false); @@ -1531,6 +2403,9 @@ void tst_QMetaObject::checkScope() QCOMPARE(QByteArray(mf.scope()), QByteArray("MyNamespace::" + name)); QCOMPARE(mf.keysToValue("MyNamespace::" + name + "::MyFlag2", &ok), 2); QCOMPARE(ok, true); + // Fully qualified + QCOMPARE(mf.keysToValue("MyNamespace::" + name + "::MyFlag::MyFlag2", &ok), 2); + QCOMPARE(ok, true); QCOMPARE(mf.keysToValue(name + "::MyFlag2", &ok), -1); QCOMPARE(ok, false); QCOMPARE(mf.keysToValue("MyNamespace::MyFlag2", &ok), -1); @@ -1540,7 +2415,12 @@ void tst_QMetaObject::checkScope() QCOMPARE(mf.keysToValue("MyFlag", &ok), -1); QCOMPARE(ok, false); QCOMPARE(QLatin1String(mf.valueToKey(2)), QLatin1String("MyFlag2")); - QCOMPARE(mf.keysToValue("MyNamespace::" + name + "::MyFlag1|MyNamespace::" + name + "::MyFlag2", &ok), 3); + + const QByteArray prefix = "MyNamespace::" + name; + QCOMPARE(mf.keysToValue(prefix + "::MyFlag1|" + prefix + "::MyFlag2", &ok), 3); + QCOMPARE(ok, true); + // Fully qualified + QCOMPARE(mf.keysToValue(prefix + "::MyFlag::MyFlag1|" + prefix + "::MyFlag::MyFlag2", &ok), 3); QCOMPARE(ok, true); QCOMPARE(mf.keysToValue(name + "::MyFlag1|" + name + "::MyFlag2", &ok), -1); QCOMPARE(ok, false); @@ -1552,9 +2432,34 @@ void tst_QMetaObject::checkScope() QCOMPARE(ok, true); QCOMPARE(mf.keysToValue("MyFlag1|MyNamespace::" + name + "::MyFlag2", &ok), 3); QCOMPARE(ok, true); - QCOMPARE(mf.keysToValue("MyNamespace::" + name + "::MyFlag2|MyNamespace::" + name + "::MyFlag2", &ok), 2); + QCOMPARE(mf.keysToValue(prefix + "::MyFlag2|" + prefix + "::MyFlag2", &ok), 2); + QCOMPARE(ok, true); + // Fully qualified + QCOMPARE(mf.keysToValue(prefix + "::MyFlag::MyFlag2|" + prefix + "::MyFlag::MyFlag2", &ok), 2); QCOMPARE(ok, true); QCOMPARE(QLatin1String(mf.valueToKeys(3)), QLatin1String("MyFlag1|MyFlag2")); + + // Test flags with extra '|' + QTest::ignoreMessage(QtWarningMsg, + QRegularExpression(u"QMetaEnum::keysToValue: malformed keys string, ends with '|'.+"_s)); + QCOMPARE(mf.keysToValue("MyFlag1|MyFlag2|", &ok), -1); + QCOMPARE(ok, false); + + QTest::ignoreMessage(QtWarningMsg, + QRegularExpression(u"QMetaEnum::keysToValue: malformed keys string, starts with '|'.+"_s)); + QCOMPARE(mf.keysToValue("|MyFlag1|MyFlag2|", &ok), -1); + QCOMPARE(ok, false); + + QTest::ignoreMessage(QtWarningMsg, + QRegularExpression( + u"QMetaEnum::keysToValue: malformed keys string, has two consecutive '|'.+"_s)); + QCOMPARE(mf.keysToValue("MyFlag1||MyFlag2", &ok), -1); + QCOMPARE(ok, false); + + // Test empty string + QTest::ignoreMessage(QtWarningMsg, "QMetaEnum::keysToValue: empty keys string."); + QCOMPARE(mf.keysToValue("", &ok), -1); + QCOMPARE(ok, false); } void tst_QMetaObject::propertyNotify() @@ -1612,6 +2517,17 @@ void tst_QMetaObject::propertyFinal() QVERIFY(!prop.isFinal()); } +void tst_QMetaObject::metaType() +{ + QCOMPARE(QObject::staticMetaObject.metaType(), QMetaType::fromType<QObject>()); + QCOMPARE(MyGadget::staticMetaObject.metaType(), QMetaType::fromType<MyGadget>()); +#if QT_CONFIG(proxymodel) + QCOMPARE(QAbstractProxyModel::staticMetaObject.metaType(), QMetaType::fromType<QAbstractProxyModel>()); +#endif + auto qtNameSpaceMetaType = Qt::staticMetaObject.metaType(); + QVERIFY2(!qtNameSpaceMetaType.isValid(), qtNameSpaceMetaType.name()); +} + class ClassInfoTestObjectA : public QObject { Q_OBJECT @@ -1632,6 +2548,7 @@ void tst_QMetaObject::classInfo() QCOMPARE(QLatin1String(b.metaObject()->classInfo(index).value()), QLatin1String("Christopher Pike")); } +// this test is duplicated below void tst_QMetaObject::metaMethod() { QString str("foo"); @@ -1651,9 +2568,13 @@ void tst_QMetaObject::metaMethod() QVERIFY(index > 0); method = QtTestObject::staticMetaObject.method(index); //wrong args + QTest::ignoreMessage(QtWarningMsg, "QMetaMethod::invoke: too few arguments (5) in call to QtTestObject::sl5(QString,QString,QString,QString,QString)"); QVERIFY(!method.invoke(&obj, Q_ARG(QString, "1"), Q_ARG(QString, "2"), Q_ARG(QString, "3"), Q_ARG(QString, "4"))); //QVERIFY(!method.invoke(&obj, Q_ARG(QString, "1"), Q_ARG(QString, "2"), Q_ARG(QString, "3"), Q_ARG(QString, "4"), Q_ARG(QString, "5"), Q_ARG(QString, "6"))); //QVERIFY(!method.invoke(&obj, Q_ARG(QString, "1"), Q_ARG(QString, "2"), Q_ARG(QString, "3"), Q_ARG(QString, "4"), Q_ARG(int, 5))); + QTest::ignoreMessage(QtWarningMsg, "QMetaMethod::invokeMethod: return type mismatch for method " + "QtTestObject::sl5(QString,QString,QString,QString,QString): " + "cannot convert from void to QString during invocation"); QVERIFY(!method.invoke(&obj, Q_RETURN_ARG(QString, ret), Q_ARG(QString, "1"), Q_ARG(QString, "2"), Q_ARG(QString, "3"), Q_ARG(QString, "4"), Q_ARG(QString, "5"))); //wrong object @@ -1680,6 +2601,59 @@ void tst_QMetaObject::metaMethod() QCOMPARE(obj.slotResult, QString("sl13")); } +// this is a copy-paste-adapt of the above +void tst_QMetaObject::metaMethodNoMacro() +{ + QString str("foo"); + QString ret("bar"); + QMetaMethod method; + QVERIFY(!method.invoke(this)); + QVERIFY(!method.invoke(this, str)); + QVERIFY(!method.invoke(this, qReturnArg(ret), str)); + QCOMPARE(str, QString("foo")); + QCOMPARE(ret, QString("bar")); + + QtTestObject obj; + QString t1("1"); QString t2("2"); QString t3("3"); QString t4("4"); QString t5("5"); + QString t6("6"); QString t7("7"); QString t8("8"); QString t9("9"); QString t10("X"); + + int index = QtTestObject::staticMetaObject.indexOfMethod("sl5(QString,QString,QString,QString,QString)"); + QVERIFY(index > 0); + method = QtTestObject::staticMetaObject.method(index); + //wrong args + QTest::ignoreMessage(QtWarningMsg, "QMetaMethod::invoke: too few arguments (5) in call to QtTestObject::sl5(QString,QString,QString,QString,QString)"); + QVERIFY(!method.invoke(&obj, QStringLiteral("1"), QStringLiteral("2"), QStringLiteral("3"), QStringLiteral("4"))); + //QVERIFY(!method.invoke(&obj, "1", "2", "3", "4", "5", "6")); + //QVERIFY(!method.invoke(&obj, "1", "2", "3", "4", 5)); + QTest::ignoreMessage(QtWarningMsg, "QMetaMethod::invokeMethod: return type mismatch for method " + "QtTestObject::sl5(QString,QString,QString,QString,QString): " + "cannot convert from void to QString during invocation"); + QVERIFY(!method.invoke(&obj, qReturnArg(ret), QStringLiteral("1"), QStringLiteral("2"), QStringLiteral("3"), QStringLiteral("4"), QStringLiteral("5"))); + + //wrong object + //QVERIFY(!method.invoke(this, "1", "2", "3", "4", "5")); + QVERIFY(!method.invoke(0, QStringLiteral("1"), QStringLiteral("2"), QStringLiteral("3"), QStringLiteral("4"), QStringLiteral("5"))); + QCOMPARE(ret, QString("bar")); + QCOMPARE(obj.slotResult, QString()); + + QVERIFY(method.invoke(&obj, QStringLiteral("1"), QStringLiteral("2"), QStringLiteral("3"), QStringLiteral("4"), QStringLiteral("5"))); + QCOMPARE(obj.slotResult, QString("sl5:12345")); + + index = QtTestObject::staticMetaObject.indexOfMethod("sl13(QList<QString>)"); + QVERIFY(index > 0); + QMetaMethod sl13 = QtTestObject::staticMetaObject.method(index); + QList<QString> returnValue, argument; + argument << QString("one") << QString("two") << QString("three"); + //wrong object + //QVERIFY(!sl13.invoke(this, qReturnArg(returnValue), argument)); + QVERIFY(!sl13.invoke(0, qReturnArg(returnValue), argument)); + QVERIFY(returnValue.isEmpty()); + + QVERIFY(sl13.invoke(&obj, qReturnArg(returnValue), argument)); + QCOMPARE(returnValue, argument); + QCOMPARE(obj.slotResult, QString("sl13")); +} + void tst_QMetaObject::indexOfMethod_data() { QTest::addColumn<QObject *>("object"); |