diff options
Diffstat (limited to 'tests/auto/corelib/kernel/qmetaobject/tst_qmetaobject.cpp')
-rw-r--r-- | tests/auto/corelib/kernel/qmetaobject/tst_qmetaobject.cpp | 886 |
1 files changed, 852 insertions, 34 deletions
diff --git a/tests/auto/corelib/kernel/qmetaobject/tst_qmetaobject.cpp b/tests/auto/corelib/kernel/qmetaobject/tst_qmetaobject.cpp index 01f9617be1..182ec6daae 100644 --- a/tests/auto/corelib/kernel/qmetaobject/tst_qmetaobject.cpp +++ b/tests/auto/corelib/kernel/qmetaobject/tst_qmetaobject.cpp @@ -1,19 +1,42 @@ // Copyright (C) 2016 The Qt Company Ltd. -// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0 +// 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; @@ -271,24 +294,30 @@ public: 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(); @@ -299,6 +328,7 @@ private slots: void classInfo(); void metaMethod(); + void metaMethodNoMacro(); void indexOfMethod_data(); void indexOfMethod(); @@ -490,6 +520,8 @@ public slots: qlonglong *sl15(qlonglong *); MyForwardDeclaredType *sl16(MyForwardDeclaredType *); + void sl17(int *i) { *i = 242; } + void overloadedSlot(); void overloadedSlot(int, int); void overloadedSlot(int); @@ -640,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; @@ -650,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))); @@ -699,17 +732,19 @@ 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")); @@ -783,8 +818,10 @@ void tst_QMetaObject::invokeMetaMember() 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")); + 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")); @@ -792,7 +829,7 @@ void tst_QMetaObject::invokeMetaMember() 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"))); @@ -822,6 +859,172 @@ void tst_QMetaObject::invokeMetaMember() 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")); + QCOMPARE(obj.slotResult, QString("sl1:hehe")); +} + void testFunction(){} @@ -886,13 +1089,123 @@ void tst_QMetaObject::invokePointer() QCOMPARE(obj.slotResult, QString("sl1:1")); } QCOMPARE(countedStructObjectsCount, 0); + + // 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")); @@ -919,8 +1232,16 @@ void tst_QMetaObject::invokeQueuedMetaMember() 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)); + 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))); @@ -933,7 +1254,7 @@ void tst_QMetaObject::invokeQueuedMetaMember() // 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")); @@ -966,6 +1287,7 @@ void tst_QMetaObject::invokeQueuedMetaMember() 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(); { const MyForwardDeclaredType &t = getForwardDeclaredType(); @@ -983,12 +1305,115 @@ void tst_QMetaObject::invokeQueuedMetaMember() 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(); - QTest::ignoreMessage(QtWarningMsg, "QMetaMethod::invoke: Unable to handle unregistered datatype 'MyForwardDeclaredType*'"); - QVERIFY(!QMetaObject::invokeMethod(&obj, "sl16", Qt::QueuedConnection, Q_ARG(MyForwardDeclaredType*, getForwardDeclaredPointer()))); + 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() @@ -1038,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; @@ -1087,17 +1518,19 @@ 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")); @@ -1172,8 +1605,10 @@ void tst_QMetaObject::invokeBlockingQueuedMetaMember() 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)); + 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")); @@ -1181,7 +1616,7 @@ void tst_QMetaObject::invokeBlockingQueuedMetaMember() 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"))); @@ -1193,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" @@ -1213,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() @@ -1283,6 +1888,18 @@ void tst_QMetaObject::invokeBlockingQueuedPointer() Qt::BlockingQueuedConnection)); QCOMPARE(obj.slotResult, QString("sl1:hehe")); } + + // 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()); @@ -1293,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"); @@ -1300,6 +1918,7 @@ void tst_QMetaObject::qtMetaObjectInheritance() QMetaProperty sortCaseSensitivity = QSortFilterProxyModel::staticMetaObject.property(indexOfSortCaseSensitivity); QVERIFY(sortCaseSensitivity.isValid()); QCOMPARE(sortCaseSensitivity.enumerator().name(), "CaseSensitivity"); +#endif } struct MyType @@ -1339,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 @@ -1354,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)); @@ -1403,6 +2029,38 @@ void tst_QMetaObject::invokeMetaConstructor() } } +// 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() { qRegisterMetaType<CustomString>("CustomString"); @@ -1410,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)); } @@ -1430,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 @@ -1451,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() @@ -1618,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"); @@ -1632,7 +2359,7 @@ void tst_QMetaObject::checkScope_data() } -void tst_QMetaObject::checkScope() +void tst_QMetaObject::keysToValue() { QFETCH(QObject *, object); QFETCH(QByteArray, name); @@ -1645,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); @@ -1674,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); @@ -1683,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); @@ -1695,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() @@ -1759,7 +2521,9 @@ 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()); } @@ -1784,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"); @@ -1836,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"); |