+void tst_qdeclarativeecmascript::scarceResources_data()
+{
+ QTest::addColumn<QUrl>("qmlFile");
+ QTest::addColumn<bool>("readDetachStatus");
+ QTest::addColumn<bool>("expectedDetachStatus");
+ QTest::addColumn<QStringList>("propertyNames");
+ QTest::addColumn<QVariantList>("expectedValidity");
+ QTest::addColumn<QVariantList>("expectedValues");
+ QTest::addColumn<QStringList>("expectedErrors");
+
+ QPixmap origPixmap(100, 100);
+ origPixmap.fill(Qt::blue);
+
+ /* property var semantics */
+
+ // in the following three cases, the instance created from the component
+ // has a property which is a copy of the scarce resource; hence, the
+ // resource should NOT be detached prior to deletion of the object instance,
+ // unless the resource is destroyed explicitly.
+ QTest::newRow("var: import scarce resource copy directly")
+ << testFileUrl("scarceResourceCopy.var.qml")
+ << true
+ << false // won't be detached, because assigned to property and not explicitly released
+ << (QStringList() << QLatin1String("scarceResourceCopy"))
+ << (QList<QVariant>() << true)
+ << (QList<QVariant>() << origPixmap)
+ << QStringList();
+
+ QTest::newRow("var: import scarce resource copy from JS")
+ << testFileUrl("scarceResourceCopyFromJs.var.qml")
+ << true
+ << false // won't be detached, because assigned to property and not explicitly released
+ << (QStringList() << QLatin1String("scarceResourceCopy"))
+ << (QList<QVariant>() << true)
+ << (QList<QVariant>() << origPixmap)
+ << QStringList();
+
+ QTest::newRow("var: import released scarce resource copy from JS")
+ << testFileUrl("scarceResourceDestroyedCopy.var.qml")
+ << true
+ << true // explicitly released, so it will be detached
+ << (QStringList() << QLatin1String("scarceResourceCopy"))
+ << (QList<QVariant>() << false)
+ << (QList<QVariant>() << QVariant())
+ << QStringList();
+
+ // in the following three cases, no other copy should exist in memory,
+ // and so it should be detached (unless explicitly preserved).
+ QTest::newRow("var: import auto-release SR from JS in binding side-effect")
+ << testFileUrl("scarceResourceTest.var.qml")
+ << true
+ << true // auto released, so it will be detached
+ << (QStringList() << QLatin1String("scarceResourceTest"))
+ << (QList<QVariant>() << true)
+ << (QList<QVariant>() << QVariant(100))
+ << QStringList();
+ QTest::newRow("var: import explicit-preserve SR from JS in binding side-effect")
+ << testFileUrl("scarceResourceTestPreserve.var.qml")
+ << true
+ << false // won't be detached because we explicitly preserve it
+ << (QStringList() << QLatin1String("scarceResourceTest"))
+ << (QList<QVariant>() << true)
+ << (QList<QVariant>() << QVariant(100))
+ << QStringList();
+ QTest::newRow("var: import explicit-preserve SR from JS in binding side-effect")
+ << testFileUrl("scarceResourceTestMultiple.var.qml")
+ << true
+ << true // will be detached because all resources were released manually or automatically.
+ << (QStringList() << QLatin1String("scarceResourceTest"))
+ << (QList<QVariant>() << true)
+ << (QList<QVariant>() << QVariant(100))
+ << QStringList();
+
+ // In the following three cases, test that scarce resources are handled
+ // correctly for imports.
+ QTest::newRow("var: import with no binding")
+ << testFileUrl("scarceResourceCopyImportNoBinding.var.qml")
+ << false // cannot check detach status.
+ << false
+ << QStringList()
+ << QList<QVariant>()
+ << QList<QVariant>()
+ << QStringList();
+ QTest::newRow("var: import with binding without explicit preserve")
+ << testFileUrl("scarceResourceCopyImportNoBinding.var.qml")
+ << false
+ << false
+ << (QStringList() << QLatin1String("scarceResourceCopy"))
+ << (QList<QVariant>() << false) // will have been released prior to evaluation of binding.
+ << (QList<QVariant>() << QVariant())
+ << QStringList();
+ QTest::newRow("var: import with explicit release after binding evaluation")
+ << testFileUrl("scarceResourceCopyImport.var.qml")
+ << false
+ << false
+ << (QStringList() << QLatin1String("scarceResourceImportedCopy") << QLatin1String("scarceResourceAssignedCopyOne") << QLatin1String("scarceResourceAssignedCopyTwo") << QLatin1String("arePropertiesEqual"))
+ << (QList<QVariant>() << false << false << false << true) // since property var = JS object reference, by releasing the provider's resource, all handles are invalidated.
+ << (QList<QVariant>() << QVariant() << QVariant() << QVariant() << QVariant(true))
+ << QStringList();
+ QTest::newRow("var: import with different js objects")
+ << testFileUrl("scarceResourceCopyImportDifferent.var.qml")
+ << false
+ << false
+ << (QStringList() << QLatin1String("scarceResourceAssignedCopyOne") << QLatin1String("scarceResourceAssignedCopyTwo") << QLatin1String("arePropertiesEqual"))
+ << (QList<QVariant>() << false << true << true) // invalidating one shouldn't invalidate the other, because they're not references to the same JS object.
+ << (QList<QVariant>() << QVariant() << QVariant(origPixmap) << QVariant(false))
+ << QStringList();
+ QTest::newRow("var: import with different js objects and explicit release")
+ << testFileUrl("scarceResourceMultipleDifferentNoBinding.var.qml")
+ << false
+ << false
+ << (QStringList() << QLatin1String("resourceOne") << QLatin1String("resourceTwo"))
+ << (QList<QVariant>() << true << false) // invalidating one shouldn't invalidate the other, because they're not references to the same JS object.
+ << (QList<QVariant>() << QVariant(origPixmap) << QVariant())
+ << QStringList();
+ QTest::newRow("var: import with same js objects and explicit release")
+ << testFileUrl("scarceResourceMultipleSameNoBinding.var.qml")
+ << false
+ << false
+ << (QStringList() << QLatin1String("resourceOne") << QLatin1String("resourceTwo"))
+ << (QList<QVariant>() << false << false) // invalidating one should invalidate the other, because they're references to the same JS object.
+ << (QList<QVariant>() << QVariant() << QVariant())
+ << QStringList();
+ QTest::newRow("var: binding with same js objects and explicit release")
+ << testFileUrl("scarceResourceMultipleSameWithBinding.var.qml")
+ << false
+ << false
+ << (QStringList() << QLatin1String("resourceOne") << QLatin1String("resourceTwo"))
+ << (QList<QVariant>() << false << false) // invalidating one should invalidate the other, because they're references to the same JS object.
+ << (QList<QVariant>() << QVariant() << QVariant())
+ << QStringList();
+
+
+ /* property variant semantics */
+
+ // in the following three cases, the instance created from the component
+ // has a property which is a copy of the scarce resource; hence, the
+ // resource should NOT be detached prior to deletion of the object instance,
+ // unless the resource is destroyed explicitly.
+ QTest::newRow("variant: import scarce resource copy directly")
+ << testFileUrl("scarceResourceCopy.variant.qml")
+ << true
+ << false // won't be detached, because assigned to property and not explicitly released
+ << (QStringList() << QLatin1String("scarceResourceCopy"))
+ << (QList<QVariant>() << true)
+ << (QList<QVariant>() << origPixmap)
+ << QStringList();
+
+ QTest::newRow("variant: import scarce resource copy from JS")
+ << testFileUrl("scarceResourceCopyFromJs.variant.qml")
+ << true
+ << false // won't be detached, because assigned to property and not explicitly released
+ << (QStringList() << QLatin1String("scarceResourceCopy"))
+ << (QList<QVariant>() << true)
+ << (QList<QVariant>() << origPixmap)
+ << QStringList();
+
+ QTest::newRow("variant: import released scarce resource copy from JS")
+ << testFileUrl("scarceResourceDestroyedCopy.variant.qml")
+ << true
+ << true // explicitly released, so it will be detached
+ << (QStringList() << QLatin1String("scarceResourceCopy"))
+ << (QList<QVariant>() << false)
+ << (QList<QVariant>() << QVariant())
+ << QStringList();
+
+ // in the following three cases, no other copy should exist in memory,
+ // and so it should be detached (unless explicitly preserved).
+ QTest::newRow("variant: import auto-release SR from JS in binding side-effect")
+ << testFileUrl("scarceResourceTest.variant.qml")
+ << true
+ << true // auto released, so it will be detached
+ << (QStringList() << QLatin1String("scarceResourceTest"))
+ << (QList<QVariant>() << true)
+ << (QList<QVariant>() << QVariant(100))
+ << QStringList();
+ QTest::newRow("variant: import explicit-preserve SR from JS in binding side-effect")
+ << testFileUrl("scarceResourceTestPreserve.variant.qml")
+ << true
+ << false // won't be detached because we explicitly preserve it
+ << (QStringList() << QLatin1String("scarceResourceTest"))
+ << (QList<QVariant>() << true)
+ << (QList<QVariant>() << QVariant(100))
+ << QStringList();
+ QTest::newRow("variant: import multiple scarce resources")
+ << testFileUrl("scarceResourceTestMultiple.variant.qml")
+ << true
+ << true // will be detached because all resources were released manually or automatically.
+ << (QStringList() << QLatin1String("scarceResourceTest"))
+ << (QList<QVariant>() << true)
+ << (QList<QVariant>() << QVariant(100))
+ << QStringList();
+
+ // In the following three cases, test that scarce resources are handled
+ // correctly for imports.
+ QTest::newRow("variant: import with no binding")
+ << testFileUrl("scarceResourceCopyImportNoBinding.variant.qml")
+ << false // cannot check detach status.
+ << false
+ << QStringList()
+ << QList<QVariant>()
+ << QList<QVariant>()
+ << QStringList();
+ QTest::newRow("variant: import with binding without explicit preserve")
+ << testFileUrl("scarceResourceCopyImportNoBinding.variant.qml")
+ << false
+ << false
+ << (QStringList() << QLatin1String("scarceResourceCopy"))
+ << (QList<QVariant>() << false) // will have been released prior to evaluation of binding.
+ << (QList<QVariant>() << QVariant())
+ << QStringList();
+ QTest::newRow("variant: import with explicit release after binding evaluation")
+ << testFileUrl("scarceResourceCopyImport.variant.qml")
+ << false
+ << false
+ << (QStringList() << QLatin1String("scarceResourceImportedCopy") << QLatin1String("scarceResourceAssignedCopyOne") << QLatin1String("scarceResourceAssignedCopyTwo"))
+ << (QList<QVariant>() << true << true << false) // since property variant = variant copy, releasing the provider's resource does not invalidate previously assigned copies.
+ << (QList<QVariant>() << origPixmap << origPixmap << QVariant())
+ << QStringList();
+}
+
+void tst_qdeclarativeecmascript::scarceResources()
+{
+ QFETCH(QUrl, qmlFile);
+ QFETCH(bool, readDetachStatus);
+ QFETCH(bool, expectedDetachStatus);
+ QFETCH(QStringList, propertyNames);
+ QFETCH(QVariantList, expectedValidity);
+ QFETCH(QVariantList, expectedValues);
+ QFETCH(QStringList, expectedErrors);
+
+ QDeclarativeEnginePrivate *ep = QDeclarativeEnginePrivate::get(&engine);
+ ScarceResourceObject *eo = 0;
+ QObject *object = 0;
+
+ QDeclarativeComponent c(&engine, qmlFile);
+ object = c.create();
+ QVERIFY(object != 0);
+ for (int i = 0; i < propertyNames.size(); ++i) {
+ QString prop = propertyNames.at(i);
+ bool validity = expectedValidity.at(i).toBool();
+ QVariant value = expectedValues.at(i);
+
+ QCOMPARE(object->property(prop.toLatin1().constData()).isValid(), validity);
+ if (value.type() == QVariant::Int) {
+ QCOMPARE(object->property(prop.toLatin1().constData()).toInt(), value.toInt());
+ } else if (value.type() == QVariant::Pixmap) {
+ QCOMPARE(object->property(prop.toLatin1().constData()).value<QPixmap>(), value.value<QPixmap>());
+ }
+ }
+
+ if (readDetachStatus) {
+ eo = qobject_cast<ScarceResourceObject*>(QDeclarativeProperty::read(object, "a").value<QObject*>());
+ QCOMPARE(eo->scarceResourceIsDetached(), expectedDetachStatus);
+ }
+
+ QVERIFY(ep->scarceResources.isEmpty());
+ delete object;
+}
+