aboutsummaryrefslogtreecommitdiffstats
path: root/tests/auto/qml/qqmlcontext/tst_qqmlcontext.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'tests/auto/qml/qqmlcontext/tst_qqmlcontext.cpp')
-rw-r--r--tests/auto/qml/qqmlcontext/tst_qqmlcontext.cpp229
1 files changed, 128 insertions, 101 deletions
diff --git a/tests/auto/qml/qqmlcontext/tst_qqmlcontext.cpp b/tests/auto/qml/qqmlcontext/tst_qqmlcontext.cpp
index 8398f8b9d7..8e726857cc 100644
--- a/tests/auto/qml/qqmlcontext/tst_qqmlcontext.cpp
+++ b/tests/auto/qml/qqmlcontext/tst_qqmlcontext.cpp
@@ -1,5 +1,5 @@
// 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.h>
#include <QDebug>
@@ -49,6 +49,10 @@ private slots:
void outerContextObject();
void contextObjectHierarchy();
void destroyContextProperty();
+ void destroyContextObject();
+
+ void numericContextProperty();
+ void gcDeletesContextObject();
private:
QQmlEngine engine;
@@ -92,13 +96,13 @@ void tst_qqmlcontext::resolvedUrl()
// Relative to a deleted parent
{
- QQmlContext *ctxt = new QQmlContext(&engine);
+ std::unique_ptr<QQmlContext> ctxt = std::make_unique<QQmlContext>(&engine);
ctxt->setBaseUrl(QUrl("http://www.qt-project.org/"));
- QQmlContext ctxt2(ctxt);
+ QQmlContext ctxt2(ctxt.get());
QCOMPARE(ctxt2.resolvedUrl(QUrl("main2.qml")), QUrl("http://www.qt-project.org/main2.qml"));
- delete ctxt; ctxt = nullptr;
+ ctxt.reset();
QCOMPARE(ctxt2.resolvedUrl(QUrl("main2.qml")), QUrl());
}
@@ -114,58 +118,58 @@ void tst_qqmlcontext::resolvedUrl()
void tst_qqmlcontext::engineMethod()
{
- QQmlEngine *engine = new QQmlEngine;
+ std::unique_ptr<QQmlEngine> engine = std::make_unique<QQmlEngine>();
- QQmlContext ctxt(engine);
+ QQmlContext ctxt(engine.get());
QQmlContext ctxt2(&ctxt);
QQmlContext ctxt3(&ctxt2);
QQmlContext ctxt4(&ctxt2);
- QCOMPARE(ctxt.engine(), engine);
- QCOMPARE(ctxt2.engine(), engine);
- QCOMPARE(ctxt3.engine(), engine);
- QCOMPARE(ctxt4.engine(), engine);
+ QCOMPARE(ctxt.engine(), engine.get());
+ QCOMPARE(ctxt2.engine(), engine.get());
+ QCOMPARE(ctxt3.engine(), engine.get());
+ QCOMPARE(ctxt4.engine(), engine.get());
- delete engine; engine = nullptr;
+ engine.reset();
- QCOMPARE(ctxt.engine(), engine);
- QCOMPARE(ctxt2.engine(), engine);
- QCOMPARE(ctxt3.engine(), engine);
- QCOMPARE(ctxt4.engine(), engine);
+ QCOMPARE(ctxt.engine(), engine.get());
+ QCOMPARE(ctxt2.engine(), engine.get());
+ QCOMPARE(ctxt3.engine(), engine.get());
+ QCOMPARE(ctxt4.engine(), engine.get());
}
void tst_qqmlcontext::parentContext()
{
- QQmlEngine *engine = new QQmlEngine;
+ std::unique_ptr<QQmlEngine> engine = std::make_unique<QQmlEngine>();
QCOMPARE(engine->rootContext()->parentContext(), (QQmlContext *)nullptr);
- QQmlContext *ctxt = new QQmlContext(engine);
- QQmlContext *ctxt2 = new QQmlContext(ctxt);
- QQmlContext *ctxt3 = new QQmlContext(ctxt2);
- QQmlContext *ctxt4 = new QQmlContext(ctxt2);
- QQmlContext *ctxt5 = new QQmlContext(ctxt);
- QQmlContext *ctxt6 = new QQmlContext(engine);
- QQmlContext *ctxt7 = new QQmlContext(engine->rootContext());
+ std::unique_ptr<QQmlContext> ctxt = std::make_unique<QQmlContext>(engine.get());
+ std::unique_ptr<QQmlContext> ctxt2 = std::make_unique<QQmlContext>(ctxt.get());
+ std::unique_ptr<QQmlContext> ctxt3 = std::make_unique<QQmlContext>(ctxt2.get());
+ std::unique_ptr<QQmlContext> ctxt4 = std::make_unique<QQmlContext>(ctxt2.get());
+ std::unique_ptr<QQmlContext> ctxt5 = std::make_unique<QQmlContext>(ctxt.get());
+ std::unique_ptr<QQmlContext> ctxt6 = std::make_unique<QQmlContext>(engine.get());
+ std::unique_ptr<QQmlContext> ctxt7 = std::make_unique<QQmlContext>(engine->rootContext());
QCOMPARE(ctxt->parentContext(), engine->rootContext());
- QCOMPARE(ctxt2->parentContext(), ctxt);
- QCOMPARE(ctxt3->parentContext(), ctxt2);
- QCOMPARE(ctxt4->parentContext(), ctxt2);
- QCOMPARE(ctxt5->parentContext(), ctxt);
+ QCOMPARE(ctxt2->parentContext(), ctxt.get());
+ QCOMPARE(ctxt3->parentContext(), ctxt2.get());
+ QCOMPARE(ctxt4->parentContext(), ctxt2.get());
+ QCOMPARE(ctxt5->parentContext(), ctxt.get());
QCOMPARE(ctxt6->parentContext(), engine->rootContext());
QCOMPARE(ctxt7->parentContext(), engine->rootContext());
- delete ctxt2; ctxt2 = nullptr;
+ ctxt2.reset();
QCOMPARE(ctxt->parentContext(), engine->rootContext());
QCOMPARE(ctxt3->parentContext(), (QQmlContext *)nullptr);
QCOMPARE(ctxt4->parentContext(), (QQmlContext *)nullptr);
- QCOMPARE(ctxt5->parentContext(), ctxt);
+ QCOMPARE(ctxt5->parentContext(), ctxt.get());
QCOMPARE(ctxt6->parentContext(), engine->rootContext());
QCOMPARE(ctxt7->parentContext(), engine->rootContext());
- delete engine; engine = nullptr;
+ engine.reset();
QCOMPARE(ctxt->parentContext(), (QQmlContext *)nullptr);
QCOMPARE(ctxt3->parentContext(), (QQmlContext *)nullptr);
@@ -173,13 +177,6 @@ void tst_qqmlcontext::parentContext()
QCOMPARE(ctxt5->parentContext(), (QQmlContext *)nullptr);
QCOMPARE(ctxt6->parentContext(), (QQmlContext *)nullptr);
QCOMPARE(ctxt7->parentContext(), (QQmlContext *)nullptr);
-
- delete ctxt7;
- delete ctxt6;
- delete ctxt5;
- delete ctxt4;
- delete ctxt3;
- delete ctxt;
}
class TestObject : public QObject
@@ -229,11 +226,9 @@ private:
QQmlComponent component(&engine); \
component.setData("import QtQuick 2.0; QtObject { property variant test: " #name " }", QUrl()); \
\
- QObject *obj = component.create(ctxt); \
+ std::unique_ptr<QObject> obj { component.create(ctxt) }; \
\
QCOMPARE(obj->property("test"), value); \
-\
- delete obj; \
}
void tst_qqmlcontext::setContextProperty()
@@ -279,39 +274,33 @@ void tst_qqmlcontext::setContextProperty()
QQmlComponent component(&engine);
component.setData("import QtQuick 2.0; QtObject { property variant test: a }", QUrl());
- QObject *obj = component.create(&ctxt2);
+ std::unique_ptr<QObject> obj { component.create(&ctxt2) };
QCOMPARE(obj->property("test"), QVariant(13));
ctxt.setContextProperty("a", QVariant(19));
QCOMPARE(obj->property("test"), QVariant(19));
-
- delete obj;
}
{
QQmlComponent component(&engine);
component.setData("import QtQuick 2.0; QtObject { property variant test: b }", QUrl());
- QObject *obj = component.create(&ctxt2);
+ std::unique_ptr<QObject> obj { component.create(&ctxt2) };
QCOMPARE(obj->property("test"), QVariant(8));
ctxt.setContextProperty("b", QVariant(5));
QCOMPARE(obj->property("test"), QVariant(8));
ctxt2.setContextProperty("b", QVariant(1912));
QCOMPARE(obj->property("test"), QVariant(1912));
-
- delete obj;
}
{
QQmlComponent component(&engine);
component.setData("import QtQuick 2.0; QtObject { property variant test: e.a }", QUrl());
- QObject *obj = component.create(&ctxt2);
+ std::unique_ptr<QObject> obj { component.create(&ctxt2) };
QCOMPARE(obj->property("test"), QVariant(12));
obj1.setA(13);
QCOMPARE(obj->property("test"), QVariant(13));
-
- delete obj;
}
// New context properties
@@ -319,13 +308,11 @@ void tst_qqmlcontext::setContextProperty()
QQmlComponent component(&engine);
component.setData("import QtQuick 2.0; QtObject { property variant test: a }", QUrl());
- QObject *obj = component.create(&ctxt2);
+ std::unique_ptr<QObject> obj { component.create(&ctxt2) };
QCOMPARE(obj->property("test"), QVariant(19));
ctxt2.setContextProperty("a", QVariant(1945));
QCOMPARE(obj->property("test"), QVariant(1945));
-
- delete obj;
}
// Setting an object-variant context property
@@ -337,15 +324,13 @@ void tst_qqmlcontext::setContextProperty()
ctxt.setContextProperty("ctxtProp", QVariant());
QTest::ignoreMessage(QtWarningMsg, "<Unknown File>:1: TypeError: Cannot read property 'a' of undefined");
- QObject *obj = component.create(&ctxt);
+ std::unique_ptr<QObject> obj { component.create(&ctxt) };
QVariant v = obj->property("obj");
ctxt.setContextProperty("ctxtProp", v);
QCOMPARE(obj->property("test"), QVariant(10));
-
- delete obj;
}
}
@@ -407,13 +392,11 @@ void tst_qqmlcontext::setContextObject()
QQmlComponent component(&engine);
component.setData("import QtQuick 2.0; QtObject { property variant test: a }", QUrl());
- QObject *obj = component.create(&ctxt);
+ std::unique_ptr<QObject> obj { component.create(&ctxt) };
QCOMPARE(obj->property("test"), QVariant(12));
to.setA(14);
QCOMPARE(obj->property("test"), QVariant(14));
-
- delete obj;
}
// Change of context object
@@ -431,19 +414,19 @@ void tst_qqmlcontext::setContextObject()
void tst_qqmlcontext::destruction()
{
- QQmlContext *ctxt = new QQmlContext(&engine);
+ std::unique_ptr<QQmlContext> ctxt = std::make_unique<QQmlContext>(&engine);
QObject obj;
- QQmlEngine::setContextForObject(&obj, ctxt);
- QQmlExpression expr(ctxt, nullptr, "a");
+ QQmlEngine::setContextForObject(&obj, ctxt.get());
+ QQmlExpression expr(ctxt.get(), nullptr, "a");
- QCOMPARE(ctxt, QQmlEngine::contextForObject(&obj));
- QCOMPARE(ctxt, expr.context());
+ QCOMPARE(ctxt.get(), QQmlEngine::contextForObject(&obj));
+ QCOMPARE(ctxt.get(), expr.context());
- delete ctxt; ctxt = nullptr;
+ ctxt.reset();
- QCOMPARE(ctxt, QQmlEngine::contextForObject(&obj));
- QCOMPARE(ctxt, expr.context());
+ QCOMPARE(ctxt.get(), QQmlEngine::contextForObject(&obj));
+ QCOMPARE(ctxt.get(), expr.context());
}
void tst_qqmlcontext::idAsContextProperty()
@@ -451,18 +434,16 @@ void tst_qqmlcontext::idAsContextProperty()
QQmlComponent component(&engine);
component.setData("import QtQuick 2.0; QtObject { property variant a; a: QtObject { id: myObject } }", QUrl());
- QObject *obj = component.create();
- QVERIFY(obj);
+ std::unique_ptr<QObject> obj { component.create() };
+ QVERIFY(obj.get());
QVariant a = obj->property("a");
QCOMPARE(a.userType(), int(QMetaType::QObjectStar));
- QVariant ctxt = qmlContext(obj)->contextProperty("myObject");
+ QVariant ctxt = qmlContext(obj.get())->contextProperty("myObject");
QCOMPARE(ctxt.userType(), int(QMetaType::QObjectStar));
QCOMPARE(a, ctxt);
-
- delete obj;
}
// Internal contexts should be read-only
@@ -471,28 +452,26 @@ void tst_qqmlcontext::readOnlyContexts()
QQmlComponent component(&engine);
component.setData("import QtQuick 2.0; QtObject { id: me }", QUrl());
- QObject *obj = component.create();
- QVERIFY(obj);
+ std::unique_ptr<QObject> obj { component.create() };
+ QVERIFY(obj.get());
- QQmlContext *context = qmlContext(obj);
+ QQmlContext *context = qmlContext(obj.get());
QVERIFY(context);
- QCOMPARE(qvariant_cast<QObject*>(context->contextProperty("me")), obj);
- QCOMPARE(context->contextObject(), obj);
+ QCOMPARE(qvariant_cast<QObject*>(context->contextProperty("me")), obj.get());
+ QCOMPARE(context->contextObject(), obj.get());
QTest::ignoreMessage(QtWarningMsg, "QQmlContext: Cannot set property on internal context.");
context->setContextProperty("hello", 12);
QCOMPARE(context->contextProperty("hello"), QVariant());
QTest::ignoreMessage(QtWarningMsg, "QQmlContext: Cannot set property on internal context.");
- context->setContextProperty("hello", obj);
+ context->setContextProperty("hello", obj.get());
QCOMPARE(context->contextProperty("hello"), QVariant());
QTest::ignoreMessage(QtWarningMsg, "QQmlContext: Cannot set context object for internal context.");
context->setContextObject(nullptr);
- QCOMPARE(context->contextObject(), obj);
-
- delete obj;
+ QCOMPARE(context->contextObject(), obj.get());
}
void tst_qqmlcontext::objectsAndNames()
@@ -624,14 +603,12 @@ void tst_qqmlcontext::refreshExpressionsCrash()
component.setData("import QtQuick 2.0; QtObject { property var binding: deleteCommand.doCommand() }", QUrl());
QVERIFY(component.isReady());
- QObject *o1 = component.create(&ctxt);
+ std::unique_ptr<QObject> o1 { component.create(&ctxt) };
QObject *o2 = component.create(&ctxt);
command.object = o2;
QQmlContextData::get(&ctxt)->refreshExpressions();
-
- delete o1;
}
{
QQmlEngine engine;
@@ -647,13 +624,11 @@ void tst_qqmlcontext::refreshExpressionsCrash()
QVERIFY(component.isReady());
QObject *o1 = component.create(&ctxt);
- QObject *o2 = component.create(&ctxt);
+ std::unique_ptr<QObject> o2 { component.create(&ctxt) };
command.object = o1;
QQmlContextData::get(&ctxt)->refreshExpressions();
-
- delete o2;
}
}
@@ -685,19 +660,15 @@ void tst_qqmlcontext::refreshExpressions()
QQmlContext context(engine.rootContext());
QQmlContext context2(&context);
- QObject *o1 = component.create(&context);
- QObject *o2 = component.create(&context2);
- QObject *o3 = component2.create(&context);
+ std::unique_ptr<QObject> o1 { component.create(&context) };
+ std::unique_ptr<QObject> o2 { component.create(&context2) };
+ std::unique_ptr<QObject> o3 { component2.create(&context) };
QCOMPARE(command.count, 5);
QQmlContextData::get(&context)->refreshExpressions();
QCOMPARE(command.count, 10);
-
- delete o3;
- delete o2;
- delete o1;
}
// Test that updating the root context, only causes expressions in contexts with an
@@ -717,10 +688,10 @@ void tst_qqmlcontext::refreshExpressionsRootContext()
QString warning = component2.url().toString() + QLatin1String(":4: ReferenceError: unresolvedName is not defined");
- QObject *o1 = component.create(&context);
+ std::unique_ptr<QObject> o1 { component.create(&context) };
QTest::ignoreMessage(QtWarningMsg, qPrintable(warning));
- QObject *o2 = component2.create(&context2);
+ std::unique_ptr<QObject> o2 { component2.create(&context2) };
QCOMPARE(command.count, 3);
@@ -728,9 +699,6 @@ void tst_qqmlcontext::refreshExpressionsRootContext()
QQmlContextData::get(engine.rootContext())->refreshExpressions();
QCOMPARE(command.count, 4);
-
- delete o2;
- delete o1;
}
void tst_qqmlcontext::skipExpressionRefresh_qtbug_53431()
@@ -752,10 +720,9 @@ void tst_qqmlcontext::qtbug_22535()
QQmlComponent component(&engine, testFileUrl("qtbug_22535.qml"));
QQmlContext context(engine.rootContext());
- QObject *o = component.create(&context);
+ std::unique_ptr<QObject> o { component.create(&context) };
// Don't crash!
- delete o;
}
void tst_qqmlcontext::evalAfterInvalidate()
@@ -858,7 +825,7 @@ void tst_qqmlcontext::contextLeak()
scriptContext = scriptContextWrapper->as<QV4::QQmlContextWrapper>()->getContext();
}
- engine.collectGarbage();
+ gc(engine);
// Each time a JS file (non-pragma-shared) is imported, we create a QQmlContext(Data) for it.
// Make sure that context does not leak.
@@ -979,6 +946,66 @@ void tst_qqmlcontext::destroyContextProperty()
// TODO: Or are we?
}
+void tst_qqmlcontext::destroyContextObject()
+{
+ QQmlEngine engine;
+ QList<QQmlRefPointer<QQmlContextData>> contexts;
+ QQmlComponent component(&engine, testFileUrl("destroyContextObject.qml"));
+ QScopedPointer<QObject> root(component.create());
+
+ QPointer<QObject> a = root->property("a").value<QObject *>();
+ QVERIFY(a);
+
+ for (QQmlRefPointer<QQmlContextData> context = QQmlData::get(a)->ownContext;
+ context; context = context->parent()) {
+ contexts.append(context);
+ }
+
+ QObject *deleted = a.data();
+ root.reset();
+
+ QVERIFY(a.isNull());
+
+ for (const auto &context : contexts)
+ QVERIFY(context->contextObject() != deleted);
+}
+
+void tst_qqmlcontext::numericContextProperty()
+{
+ QQmlEngine engine;
+ auto context = engine.rootContext();
+ QTest::ignoreMessage(QtWarningMsg, "QQmlContext: Using numbers as context properties will be disallowed in a future Qt version.");
+ context->setContextProperty(QLatin1String("11"), 42);
+ QCOMPARE(context->contextProperty(QLatin1String("11")).toInt(), 42);
+}
+
+void tst_qqmlcontext::gcDeletesContextObject()
+{
+ QQmlEngine engine;
+ QQmlComponent c(&engine, testFileUrl("gcDeletesContextObject.qml"));
+
+ QVERIFY2(c.isReady(), qPrintable(c.errorString()));
+ QScopedPointer<QObject> o(c.create());
+
+ QVERIFY(!o.isNull());
+
+ QPointer<QObject> contextObject = o->property("o").value<QObject *>();
+ QVERIFY(contextObject != nullptr);
+
+ QQmlData *data = QQmlData::get(contextObject);
+ QVERIFY(data);
+ QQmlRefPointer<QQmlContextData> context = data->ownContext;
+ QVERIFY(context);
+ QCOMPARE(context->contextObject(), contextObject);
+
+ o->setProperty("o", QVariant::fromValue<QObject *>(nullptr));
+ QCOMPARE(o->property("o").value<QObject *>(), nullptr);
+ engine.collectGarbage();
+
+ QTRY_VERIFY(contextObject.isNull());
+ QCOMPARE(context->contextObject(), nullptr);
+}
+
QTEST_MAIN(tst_qqmlcontext)
#include "tst_qqmlcontext.moc"