aboutsummaryrefslogtreecommitdiffstats
path: root/tests/auto/qml/qqmllanguage
diff options
context:
space:
mode:
authorLiang Qi <liang.qi@qt.io>2017-12-12 10:35:21 +0100
committerShawn Rutledge <shawn.rutledge@qt.io>2018-01-04 14:41:16 +0100
commit2bee46e3f10e2c44d185d7a51a06830b68529676 (patch)
treeb65ac19203edfc2972b6020dd040e46c43b5d1fb /tests/auto/qml/qqmllanguage
parent52f7ab28172cea3710a16775b7a512fce821fc77 (diff)
parent41293196b4db1aa7a0c616af312875c484639644 (diff)
Merge remote-tracking branch 'origin/5.9' into 5.10
Conflicts: src/qml/memory/qv4mm.cpp src/qml/memory/qv4mmdefs_p.h src/quick/items/qquickwindow.cpp src/quick/items/qquickwindow_p.h tests/auto/qml/debugger/qqmlprofilerservice/qqmlprofilerservice.pro tests/auto/qml/debugger/qqmlprofilerservice/tst_qqmlprofilerservice.cpp Change-Id: I7021fa1edf076627a67048f41f7b201220262b09
Diffstat (limited to 'tests/auto/qml/qqmllanguage')
-rw-r--r--tests/auto/qml/qqmllanguage/tst_qqmllanguage.cpp152
1 files changed, 152 insertions, 0 deletions
diff --git a/tests/auto/qml/qqmllanguage/tst_qqmllanguage.cpp b/tests/auto/qml/qqmllanguage/tst_qqmllanguage.cpp
index 7fb4c809f7..a56318f80c 100644
--- a/tests/auto/qml/qqmllanguage/tst_qqmllanguage.cpp
+++ b/tests/auto/qml/qqmllanguage/tst_qqmllanguage.cpp
@@ -44,6 +44,7 @@
#include <private/qqmlglobal_p.h>
#include <private/qqmlscriptstring_p.h>
#include <private/qqmlvmemetaobject_p.h>
+#include <private/qqmlcomponent_p.h>
#include "testtypes.h"
#include "testhttpserver.h"
@@ -254,6 +255,7 @@ private slots:
void rootObjectInCreationNotForSubObjects();
void lazyDeferredSubObject();
void deferredProperties();
+ void executeDeferredPropertiesOnce();
void noChildEvents();
@@ -4392,8 +4394,17 @@ void tst_qqmllanguage::deferredProperties()
QQmlListProperty<QObject> listProperty = object->property("listProperty").value<QQmlListProperty<QObject>>();
QCOMPARE(listProperty.count(&listProperty), 0);
+ QQmlData *qmlData = QQmlData::get(object.data());
+ QVERIFY(qmlData);
+
+ QCOMPARE(qmlData->deferredData.count(), 2); // MyDeferredListProperty.qml + deferredListProperty.qml
+ QCOMPARE(qmlData->deferredData.first()->bindings.count(), 3); // "innerobj", "innerlist1", "innerlist2"
+ QCOMPARE(qmlData->deferredData.last()->bindings.count(), 3); // "outerobj", "outerlist1", "outerlist2"
+
qmlExecuteDeferred(object.data());
+ QCOMPARE(qmlData->deferredData.count(), 0);
+
innerObj = object->findChild<QObject *>(QStringLiteral("innerobj")); // MyDeferredListProperty.qml
QVERIFY(innerObj);
QCOMPARE(innerObj->property("wasCompleted"), QVariant(true));
@@ -4419,6 +4430,147 @@ void tst_qqmllanguage::deferredProperties()
QCOMPARE(listProperty.at(&listProperty, 3)->property("wasCompleted"), QVariant(true));
}
+static void beginDeferredOnce(QQmlEnginePrivate *enginePriv,
+ const QQmlProperty &property, QQmlComponentPrivate::DeferredState *deferredState)
+{
+ QObject *object = property.object();
+ QQmlData *ddata = QQmlData::get(object);
+ Q_ASSERT(!ddata->deferredData.isEmpty());
+
+ int propertyIndex = property.index();
+
+ for (auto dit = ddata->deferredData.rbegin(); dit != ddata->deferredData.rend(); ++dit) {
+ QQmlData::DeferredData *deferData = *dit;
+
+ auto range = deferData->bindings.equal_range(propertyIndex);
+ if (range.first == deferData->bindings.end())
+ continue;
+
+ QQmlComponentPrivate::ConstructionState *state = new QQmlComponentPrivate::ConstructionState;
+ state->completePending = true;
+
+ QQmlContextData *creationContext = nullptr;
+ state->creator.reset(new QQmlObjectCreator(deferData->context->parent, deferData->compilationUnit, creationContext));
+
+ enginePriv->inProgressCreations++;
+
+ typedef QMultiHash<int, const QV4::CompiledData::Binding *> QV4PropertyBindingHash;
+ auto it = std::reverse_iterator<QV4PropertyBindingHash::iterator>(range.second);
+ auto last = std::reverse_iterator<QV4PropertyBindingHash::iterator>(range.first);
+ while (it != last) {
+ if (!state->creator->populateDeferredBinding(property, deferData, *it))
+ state->errors << state->creator->errors;
+ ++it;
+ }
+
+ deferredState->constructionStates += state;
+
+ // Cleanup any remaining deferred bindings for this property, also in inner contexts,
+ // to avoid executing them later and overriding the property that was just populated.
+ while (dit != ddata->deferredData.rend()) {
+ (*dit)->bindings.remove(propertyIndex);
+ ++dit;
+ }
+ break;
+ }
+}
+
+static void testExecuteDeferredOnce(const QQmlProperty &property)
+{
+ QObject *object = property.object();
+ QQmlData *data = QQmlData::get(object);
+ if (data && !data->deferredData.isEmpty() && !data->wasDeleted(object)) {
+ QQmlEnginePrivate *ep = QQmlEnginePrivate::get(data->context->engine);
+
+ QQmlComponentPrivate::DeferredState state;
+ beginDeferredOnce(ep, property, &state);
+
+ // Release deferred data for those compilation units that no longer have deferred bindings
+ data->releaseDeferredData();
+
+ QQmlComponentPrivate::completeDeferred(ep, &state);
+ }
+}
+
+void tst_qqmllanguage::executeDeferredPropertiesOnce()
+{
+ QQmlComponent component(&engine, testFile("deferredProperties.qml"));
+ VERIFY_ERRORS(0);
+ QScopedPointer<QObject> object(component.create());
+ QVERIFY(!object.isNull());
+
+ QObjectList innerObjsAtCreation = object->findChildren<QObject *>(QStringLiteral("innerobj"));
+ QVERIFY(innerObjsAtCreation.isEmpty());
+
+ QObjectList outerObjsAtCreation = object->findChildren<QObject *>(QStringLiteral("outerobj"));
+ QVERIFY(outerObjsAtCreation.isEmpty());
+
+ QObject *groupProperty = object->property("groupProperty").value<QObject *>();
+ QVERIFY(!groupProperty);
+
+ QQmlListProperty<QObject> listProperty = object->property("listProperty").value<QQmlListProperty<QObject>>();
+ QCOMPARE(listProperty.count(&listProperty), 0);
+
+ QQmlData *qmlData = QQmlData::get(object.data());
+ QVERIFY(qmlData);
+
+ QCOMPARE(qmlData->deferredData.count(), 2); // MyDeferredListProperty.qml + deferredListProperty.qml
+ QCOMPARE(qmlData->deferredData.first()->bindings.count(), 3); // "innerobj", "innerlist1", "innerlist2"
+ QCOMPARE(qmlData->deferredData.last()->bindings.count(), 3); // "outerobj", "outerlist1", "outerlist2"
+
+ // first execution creates the outer object
+ testExecuteDeferredOnce(QQmlProperty(object.data(), "groupProperty"));
+
+ QCOMPARE(qmlData->deferredData.count(), 2); // MyDeferredListProperty.qml + deferredListProperty.qml
+ QCOMPARE(qmlData->deferredData.first()->bindings.count(), 2); // "innerlist1", "innerlist2"
+ QCOMPARE(qmlData->deferredData.last()->bindings.count(), 2); // "outerlist1", "outerlist2"
+
+ QObjectList innerObjsAfterFirstExecute = object->findChildren<QObject *>(QStringLiteral("innerobj")); // MyDeferredListProperty.qml
+ QVERIFY(innerObjsAfterFirstExecute.isEmpty());
+
+ QObjectList outerObjsAfterFirstExecute = object->findChildren<QObject *>(QStringLiteral("outerobj")); // deferredListProperty.qml
+ QCOMPARE(outerObjsAfterFirstExecute.count(), 1);
+ QCOMPARE(outerObjsAfterFirstExecute.first()->property("wasCompleted"), QVariant(true));
+
+ groupProperty = object->property("groupProperty").value<QObject *>();
+ QCOMPARE(groupProperty, outerObjsAfterFirstExecute.first());
+
+ listProperty = object->property("listProperty").value<QQmlListProperty<QObject>>();
+ QCOMPARE(listProperty.count(&listProperty), 0);
+
+ // re-execution does nothing (to avoid overriding the property)
+ testExecuteDeferredOnce(QQmlProperty(object.data(), "groupProperty"));
+
+ QCOMPARE(qmlData->deferredData.count(), 2); // MyDeferredListProperty.qml + deferredListProperty.qml
+ QCOMPARE(qmlData->deferredData.first()->bindings.count(), 2); // "innerlist1", "innerlist2"
+ QCOMPARE(qmlData->deferredData.last()->bindings.count(), 2); // "outerlist1", "outerlist2"
+
+ QObjectList innerObjsAfterSecondExecute = object->findChildren<QObject *>(QStringLiteral("innerobj")); // MyDeferredListProperty.qml
+ QVERIFY(innerObjsAfterSecondExecute.isEmpty());
+
+ QObjectList outerObjsAfterSecondExecute = object->findChildren<QObject *>(QStringLiteral("outerobj")); // deferredListProperty.qml
+ QCOMPARE(outerObjsAfterFirstExecute, outerObjsAfterSecondExecute);
+
+ groupProperty = object->property("groupProperty").value<QObject *>();
+ QCOMPARE(groupProperty, outerObjsAfterFirstExecute.first());
+
+ listProperty = object->property("listProperty").value<QQmlListProperty<QObject>>();
+ QCOMPARE(listProperty.count(&listProperty), 0);
+
+ // execution of a list property should execute all outer list bindings
+ testExecuteDeferredOnce(QQmlProperty(object.data(), "listProperty"));
+
+ QCOMPARE(qmlData->deferredData.count(), 0);
+
+ listProperty = object->property("listProperty").value<QQmlListProperty<QObject>>();
+ QCOMPARE(listProperty.count(&listProperty), 2);
+
+ QCOMPARE(listProperty.at(&listProperty, 0)->objectName(), QStringLiteral("outerlist1")); // deferredListProperty.qml
+ QCOMPARE(listProperty.at(&listProperty, 0)->property("wasCompleted"), QVariant(true));
+ QCOMPARE(listProperty.at(&listProperty, 1)->objectName(), QStringLiteral("outerlist2")); // deferredListProperty.qml
+ QCOMPARE(listProperty.at(&listProperty, 1)->property("wasCompleted"), QVariant(true));
+}
+
void tst_qqmllanguage::noChildEvents()
{
QQmlComponent component(&engine);