diff options
author | Ulf Hermann <ulf.hermann@qt.io> | 2022-12-22 14:45:04 +0100 |
---|---|---|
committer | Ulf Hermann <ulf.hermann@qt.io> | 2023-01-02 21:50:34 +0100 |
commit | 3fd3a2a9d06505d549cc4a7c18819a17c6622dfd (patch) | |
tree | aa266f8c45a9f81537a3820223f04387e57ddeb1 /tests/auto/qml/qqmllanguage/tst_qqmllanguage.cpp | |
parent | e39b4572c272f8a0a7be048a24808cb028480e82 (diff) |
QObjectWrapper: Fix calling attached methods on different objects
You can generally store a method in a value and call it on a different
object. However, since we've ignored the thisObject basically forever,
we cannot just accept it right away. Add an opt-in mechanism via a
pragma that allows you to pass (implicitly via context or explicitly via
call()) specific thisObjects to QObject methods.
Fixes: QTBUG-109585
Pick-to: 6.5
Change-Id: I4c81b8ecf6317af55104ac9ebb62d98862ff24e7
Reviewed-by: Fabian Kosmale <fabian.kosmale@qt.io>
Diffstat (limited to 'tests/auto/qml/qqmllanguage/tst_qqmllanguage.cpp')
-rw-r--r-- | tests/auto/qml/qqmllanguage/tst_qqmllanguage.cpp | 86 |
1 files changed, 86 insertions, 0 deletions
diff --git a/tests/auto/qml/qqmllanguage/tst_qqmllanguage.cpp b/tests/auto/qml/qqmllanguage/tst_qqmllanguage.cpp index efe89f61ac..fee65fcb17 100644 --- a/tests/auto/qml/qqmllanguage/tst_qqmllanguage.cpp +++ b/tests/auto/qml/qqmllanguage/tst_qqmllanguage.cpp @@ -403,6 +403,9 @@ private slots: void nullIsNull(); void multiRequired(); + void objectAndGadgetMethodCallsRejectThisObject(); + void objectAndGadgetMethodCallsAcceptThisObject(); + private: QQmlEngine engine; QStringList defaultImportPathList; @@ -7763,6 +7766,89 @@ void tst_qqmllanguage::multiRequired() qPrintable(url.toString() + ":5 Required property description was not initialized\n")); } +void tst_qqmllanguage::objectAndGadgetMethodCallsRejectThisObject() +{ + QQmlEngine engine; + QQmlComponent c(&engine, testFileUrl("objectAndGadgetMethodCallsRejectThisObject.qml")); + QVERIFY2(c.isReady(), qPrintable(c.errorString())); + + const QList<int> lines = { 15, 19, 21, 22, 24, 25, 28, 31 }; + for (int line : lines) { + const QString message + = ".*:%1: Calling C.. methods with 'this' objects different from the one " + "they were retrieved from is broken, due to historical reasons. The " + "original object is used as 'this' object. You can allow the given " + "'this' object to be used by setting " + "'pragma NativeMethodBehavior: AcceptThisObject'"_L1.arg(QString::number(line)); + QTest::ignoreMessage(QtWarningMsg, QRegularExpression(message)); + } + + QScopedPointer<QObject> o(c.create()); + QVERIFY(!o.isNull()); + + QCOMPARE(o->property("badRect"), QRectF(1, 2, 3, 4)); + QCOMPARE(o->property("goodRect1"), QRectF(1, 2, 3, 4)); + QCOMPARE(o->property("goodRect2"), QRectF(1, 2, 3, 4)); + + QCOMPARE(o->property("badString"), QStringLiteral("27")); + QCOMPARE(o->property("goodString1"), QStringLiteral("27")); + QCOMPARE(o->property("goodString2"), QStringLiteral("27")); + QCOMPARE(o->property("goodString3"), QStringLiteral("27")); + + QVERIFY(o->property("goodString4").value<QString>().startsWith("QObject_QML_"_L1)); + QVERIFY(o->property("badString2").value<QString>().startsWith("QObject_QML_"_L1)); + + QCOMPARE(o->property("badInt"), 5); + QCOMPARE(o->property("goodInt1"), 5); + QCOMPARE(o->property("goodInt2"), 5); + QCOMPARE(o->property("goodInt3"), 5); +} + +void tst_qqmllanguage::objectAndGadgetMethodCallsAcceptThisObject() +{ + QQmlEngine engine; + QQmlComponent c(&engine, testFileUrl("objectAndGadgetMethodCallsAcceptThisObject.qml")); + QVERIFY2(c.isReady(), qPrintable(c.errorString())); + + QTest::ignoreMessage( + QtWarningMsg, QRegularExpression( + "objectAndGadgetMethodCallsAcceptThisObject.qml:16: Error: " + "Cannot call method QtObject::rect on QObject_QML_")); + QTest::ignoreMessage( + QtWarningMsg, QRegularExpression( + "objectAndGadgetMethodCallsAcceptThisObject.qml:20: Error: " + "Cannot call method BaseValueType::report on QObject_QML_")); + QTest::ignoreMessage( + QtWarningMsg, QRegularExpression( + "objectAndGadgetMethodCallsAcceptThisObject.qml:26: Error: " + "Cannot call method toString on QRectF")); + QTest::ignoreMessage( + QtWarningMsg, QRegularExpression( + "objectAndGadgetMethodCallsAcceptThisObject.qml:29: Error: " + "Cannot call method OriginalSingleton::mm on QObject_QML_")); + + + QScopedPointer<QObject> o(c.create()); + QVERIFY(!o.isNull()); + + QCOMPARE(o->property("badRect"), QRectF()); + QCOMPARE(o->property("goodRect1"), QRectF(1, 2, 3, 4)); + QCOMPARE(o->property("goodRect2"), QRectF(1, 2, 3, 4)); + + QCOMPARE(o->property("badString"), QString()); + QCOMPARE(o->property("goodString1"), QStringLiteral("27")); + QCOMPARE(o->property("goodString2"), QStringLiteral("27")); + QCOMPARE(o->property("goodString3"), QStringLiteral("28")); + + QVERIFY(o->property("goodString4").value<QString>().startsWith("QtObject"_L1)); + QCOMPARE(o->property("badString2"), QString()); + + QCOMPARE(o->property("badInt"), 0); + QCOMPARE(o->property("goodInt1"), 5); + QCOMPARE(o->property("goodInt2"), 5); + QCOMPARE(o->property("goodInt3"), 5); +} + QTEST_MAIN(tst_qqmllanguage) #include "tst_qqmllanguage.moc" |