Ensure that scarce resources work with var properties
[profile/ivi/qtdeclarative.git] / tests / auto / declarative / qdeclarativeecmascript / tst_qdeclarativeecmascript.cpp
index c92dc80..5e62ec6 100644 (file)
 #include <private/qdeclarativeengine_p.h>
 #include <private/qv8gccallback_p.h>
 #include <private/qdeclarativevmemetaobject_p.h>
+#include <private/qv4compiler_p.h>
 #include "testtypes.h"
 #include "testhttpserver.h"
-#include "../shared/util.h"
+#include "../../shared/util.h"
 
 /*
 This test covers evaluation of ECMAScript expressions and bindings from within
@@ -151,6 +152,8 @@ private slots:
     void importScripts_data();
     void importScripts();
     void scarceResources();
+    void scarceResources_data();
+    void scarceResources_other();
     void propertyChangeSlots();
     void propertyVar_data();
     void propertyVar();
@@ -170,6 +173,16 @@ private slots:
     void handleReferenceManagement();
     void stringArg();
     void readonlyDeclaration();
+    void sequenceConversionRead();
+    void sequenceConversionWrite();
+    void sequenceConversionArray();
+    void sequenceConversionThreads();
+    void sequenceConversionBindings();
+    void sequenceConversionCopy();
+    void assignSequenceTypes();
+    void qtbug_22464();
+    void qtbug_21580();
+
     void bug1();
     void bug2();
     void dynamicCreationCrash();
@@ -192,6 +205,7 @@ private slots:
     void qtbug_10696();
     void qtbug_11606();
     void qtbug_11600();
+    void qtbug_21864();
     void nonscriptable();
     void deleteLater();
     void in();
@@ -209,15 +223,23 @@ private slots:
     void signalHandlers();
     void doubleEvaluate();
     void forInLoop();
-
+    void nonNotifyable();
+    void deleteWhileBindingRunning();
     void callQtInvokables();
     void invokableObjectArg();
     void invokableObjectRet();
-
+    void qtbug_20344();
+    void qtbug_22679();
+    void qtbug_22843_data();
+    void qtbug_22843();
     void revisionErrors();
     void revision();
 
     void automaticSemicolon();
+    void unaryExpression();
+    void switchStatement();
+    void withStatement();
+    void tryStatement();
 
 private:
     static void propertyVarWeakRefCallback(v8::Persistent<v8::Value> object, void* parameter);
@@ -1349,11 +1371,11 @@ void tst_qdeclarativeecmascript::scriptErrors()
     QString warning1 = url.left(url.length() - 3) + "js:2: Error: Invalid write to global property \"a\"";
     QString warning2 = url + ":5: ReferenceError: Can't find variable: a";
     QString warning3 = url.left(url.length() - 3) + "js:4: Error: Invalid write to global property \"a\"";
-    QString warning4 = url + ":10: ReferenceError: Can't find variable: a";
-    QString warning5 = url + ":8: ReferenceError: Can't find variable: a";
-    QString warning6 = url + ":7: Unable to assign [undefined] to int";
-    QString warning7 = url + ":12: Error: Cannot assign to read-only property \"trueProperty\"";
-    QString warning8 = url + ":13: Error: Cannot assign to non-existent property \"fakeProperty\"";
+    QString warning4 = url + ":13: ReferenceError: Can't find variable: a";
+    QString warning5 = url + ":11: ReferenceError: Can't find variable: a";
+    QString warning6 = url + ":10: Unable to assign [undefined] to int";
+    QString warning7 = url + ":15: Error: Cannot assign to read-only property \"trueProperty\"";
+    QString warning8 = url + ":16: Error: Cannot assign to non-existent property \"fakeProperty\"";
 
     QTest::ignoreMessage(QtWarningMsg, warning1.toLatin1().constData());
     QTest::ignoreMessage(QtWarningMsg, warning2.toLatin1().constData());
@@ -1392,15 +1414,15 @@ void tst_qdeclarativeecmascript::functionErrors()
     delete object;
 
     // test that if an exception occurs while invoking js function from cpp, it is reported as expected.
-    QDeclarativeComponent componentTwo(&engine, TEST_FILE("scarceresources/scarceResourceFunctionFail.qml"));
+    QDeclarativeComponent componentTwo(&engine, TEST_FILE("scarceResourceFunctionFail.var.qml"));
     url = componentTwo.url().toString();
     object = componentTwo.create();
     QVERIFY(object != 0);
 
     QString srpname = object->property("srp_name").toString();
     
-    warning = url + QLatin1String(":17: TypeError: Property 'scarceResource' of object ") + srpname + 
-              QLatin1String(" is not a function");
+    warning = url + QLatin1String(":16: TypeError: Property 'scarceResource' of object ") + srpname
+                  + QLatin1String(" is not a function");
     QTest::ignoreMessage(QtWarningMsg, warning.toLatin1().constData()); // we expect a meaningful warning to be printed.
     QMetaObject::invokeMethod(object, "retrieveScarceResource");
     delete object;
@@ -1581,6 +1603,7 @@ void tst_qdeclarativeecmascript::shutdownErrors()
 void tst_qdeclarativeecmascript::compositePropertyType()
 {
     QDeclarativeComponent component(&engine, TEST_FILE("compositePropertyType.qml"));
+
     QTest::ignoreMessage(QtDebugMsg, "hello world");
     QObject *object = qobject_cast<QObject *>(component.create());
     delete object;
@@ -1632,6 +1655,30 @@ void tst_qdeclarativeecmascript::undefinedResetsProperty()
     }
 }
 
+// Aliases to variant properties should work
+void tst_qdeclarativeecmascript::qtbug_22464()
+{
+    QDeclarativeComponent component(&engine, TEST_FILE("qtbug_22464.qml"));
+    QObject *object = component.create();
+    QVERIFY(object != 0);
+
+    QCOMPARE(object->property("test").toBool(), true);
+
+    delete object;
+}
+
+void tst_qdeclarativeecmascript::qtbug_21580()
+{
+    QDeclarativeComponent component(&engine, TEST_FILE("qtbug_21580.qml"));
+
+    QObject *object = component.create();
+    QVERIFY(object != 0);
+
+    QCOMPARE(object->property("test").toBool(), true);
+
+    delete object;
+}
+
 // QTBUG-6781
 void tst_qdeclarativeecmascript::bug1()
 {
@@ -3152,110 +3199,98 @@ void tst_qdeclarativeecmascript::importScripts()
     }
 }
 
-void tst_qdeclarativeecmascript::scarceResources()
+void tst_qdeclarativeecmascript::scarceResources_other()
 {
+    /* These tests require knowledge of state, since we test values after
+       performing signal or function invocation. */
+
     QPixmap origPixmap(100, 100);
     origPixmap.fill(Qt::blue);
-
+    QString srp_name, expectedWarning;
     QDeclarativeEnginePrivate *ep = QDeclarativeEnginePrivate::get(&engine);
     ScarceResourceObject *eo = 0;
+    QObject *srsc = 0;
     QObject *object = 0;
 
-    // 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.
-    QDeclarativeComponent component(&engine, TEST_FILE("scarceresources/scarceResourceCopy.qml"));
-    object = component.create();
-    QVERIFY(object != 0);
-    QVERIFY(object->property("scarceResourceCopy").isValid());
-    QCOMPARE(object->property("scarceResourceCopy").value<QPixmap>(), origPixmap);
-    QVERIFY(ep->scarceResources.isEmpty()); // should have been released by this point.
+    /* property var semantics */
+
+    // test that scarce resources are handled properly in signal invocation
+    QDeclarativeComponent varComponentTen(&engine, TEST_FILE("scarceResourceSignal.var.qml"));
+    object = varComponentTen.create();
+    srsc = object->findChild<QObject*>("srsc");
+    QVERIFY(srsc);
+    QVERIFY(!srsc->property("scarceResourceCopy").isValid()); // hasn't been instantiated yet.
+    QCOMPARE(srsc->property("width"), QVariant(5)); // default value is 5.
     eo = qobject_cast<ScarceResourceObject*>(QDeclarativeProperty::read(object, "a").value<QObject*>());
-    QVERIFY(!eo->scarceResourceIsDetached()); // there are two copies of it in existence: the property of object, and the property of eo.
+    QVERIFY(eo->scarceResourceIsDetached()); // should be no other copies of it at this stage.
+    QMetaObject::invokeMethod(srsc, "testSignal");
+    QVERIFY(!srsc->property("scarceResourceCopy").isValid()); // still hasn't been instantiated
+    QCOMPARE(srsc->property("width"), QVariant(10)); // but width was assigned to 10.
+    eo = qobject_cast<ScarceResourceObject*>(QDeclarativeProperty::read(object, "a").value<QObject*>());
+    QVERIFY(eo->scarceResourceIsDetached()); // should still be no other copies of it at this stage.
+    QMetaObject::invokeMethod(srsc, "testSignal2"); // assigns scarceResourceCopy to the scarce pixmap.
+    QVERIFY(srsc->property("scarceResourceCopy").isValid());
+    QCOMPARE(srsc->property("scarceResourceCopy").value<QPixmap>(), origPixmap);
+    eo = qobject_cast<ScarceResourceObject*>(QDeclarativeProperty::read(object, "a").value<QObject*>());
+    QVERIFY(!(eo->scarceResourceIsDetached())); // should be another copy of the resource now.
+    QVERIFY(ep->scarceResources.isEmpty()); // should have been released by this point.
     delete object;
 
-    QDeclarativeComponent componentTwo(&engine, TEST_FILE("scarceresources/scarceResourceCopyFromJs.qml"));
-    object = componentTwo.create();
+    // test that scarce resources are handled properly from js functions in qml files
+    QDeclarativeComponent varComponentEleven(&engine, TEST_FILE("scarceResourceFunction.var.qml"));
+    object = varComponentEleven.create();
     QVERIFY(object != 0);
-    QVERIFY(object->property("scarceResourceCopy").isValid());
+    QVERIFY(!object->property("scarceResourceCopy").isValid()); // not yet assigned, so should not be valid
+    eo = qobject_cast<ScarceResourceObject*>(QDeclarativeProperty::read(object, "a").value<QObject*>());
+    QVERIFY(eo->scarceResourceIsDetached()); // should be no other copies of it at this stage.
+    QMetaObject::invokeMethod(object, "retrieveScarceResource");
+    QVERIFY(object->property("scarceResourceCopy").isValid()); // assigned, so should be valid.
     QCOMPARE(object->property("scarceResourceCopy").value<QPixmap>(), origPixmap);
-    QVERIFY(ep->scarceResources.isEmpty()); // should have been released by this point.
     eo = qobject_cast<ScarceResourceObject*>(QDeclarativeProperty::read(object, "a").value<QObject*>());
-    QVERIFY(!eo->scarceResourceIsDetached()); // there are two copies of it in existence: the property of object, and the property of eo.
-    delete object;
-
-    QDeclarativeComponent componentThree(&engine, TEST_FILE("scarceresources/scarceResourceDestroyedCopy.qml"));
-    object = componentThree.create();
-    QVERIFY(object != 0);
-    QVERIFY(!(object->property("scarceResourceCopy").isValid())); // was manually released prior to being returned.
-    QVERIFY(ep->scarceResources.isEmpty()); // should have been released by this point.
+    QVERIFY(!eo->scarceResourceIsDetached()); // should be a copy of the resource at this stage.
+    QMetaObject::invokeMethod(object, "releaseScarceResource");
+    QVERIFY(!object->property("scarceResourceCopy").isValid()); // just released, so should not be valid
     eo = qobject_cast<ScarceResourceObject*>(QDeclarativeProperty::read(object, "a").value<QObject*>());
-    QVERIFY(eo->scarceResourceIsDetached()); // should have explicitly been released during the evaluation of the binding.
-    delete object;
-
-    // in the following three cases, no other copy should exist in memory,
-    // and so it should be detached (unless explicitly preserved).
-    QDeclarativeComponent componentFour(&engine, TEST_FILE("scarceresources/scarceResourceTest.qml"));
-    object = componentFour.create();
-    QVERIFY(object != 0);
-    QVERIFY(object->property("scarceResourceTest").isValid());
-    QCOMPARE(object->property("scarceResourceTest").toInt(), 100);
+    QVERIFY(eo->scarceResourceIsDetached()); // should be no other copies of it at this stage.
     QVERIFY(ep->scarceResources.isEmpty()); // should have been released by this point.
-    eo = qobject_cast<ScarceResourceObject*>(QDeclarativeProperty::read(object, "a").value<QObject*>());
-    QVERIFY(eo->scarceResourceIsDetached()); // the resource should have been released after the binding was evaluated.
     delete object;
 
-    QDeclarativeComponent componentFive(&engine, TEST_FILE("scarceresources/scarceResourceTestPreserve.qml"));
-    object = componentFive.create();
+    // test that if an exception occurs while invoking js function from cpp, that the resources are released.
+    QDeclarativeComponent varComponentTwelve(&engine, TEST_FILE("scarceResourceFunctionFail.var.qml"));
+    object = varComponentTwelve.create();
     QVERIFY(object != 0);
-    QVERIFY(object->property("scarceResourceTest").isValid());
-    QCOMPARE(object->property("scarceResourceTest").toInt(), 100);
-    QVERIFY(ep->scarceResources.isEmpty()); // should have been released by this point.
+    QVERIFY(!object->property("scarceResourceCopy").isValid()); // not yet assigned, so should not be valid
     eo = qobject_cast<ScarceResourceObject*>(QDeclarativeProperty::read(object, "a").value<QObject*>());
-    QVERIFY(!eo->scarceResourceIsDetached()); // this won't be detached since we explicitly preserved it.
-    delete object;
-
-    QDeclarativeComponent componentSix(&engine, TEST_FILE("scarceresources/scarceResourceTestMultiple.qml"));
-    object = componentSix.create();
-    QVERIFY(object != 0);
-    QVERIFY(object->property("scarceResourceTest").isValid());
-    QCOMPARE(object->property("scarceResourceTest").toInt(), 100);
-    QVERIFY(ep->scarceResources.isEmpty()); // should have been released by this point.
+    QVERIFY(eo->scarceResourceIsDetached()); // should be no other copies of it at this stage.
+    srp_name = object->property("srp_name").toString();
+    expectedWarning = varComponentTwelve.url().toString() + QLatin1String(":16: TypeError: Property 'scarceResource' of object ") + srp_name + QLatin1String(" is not a function");
+    QTest::ignoreMessage(QtWarningMsg, qPrintable(expectedWarning)); // we expect a meaningful warning to be printed.
+    QMetaObject::invokeMethod(object, "retrieveScarceResource");
+    QVERIFY(!object->property("scarceResourceCopy").isValid()); // due to exception, assignment will NOT have occurred.
     eo = qobject_cast<ScarceResourceObject*>(QDeclarativeProperty::read(object, "a").value<QObject*>());
-    QVERIFY(eo->scarceResourceIsDetached()); // all resources were released manually or automatically released.
-    delete object;
-
-    // test that scarce resources are handled correctly for imports
-    QDeclarativeComponent componentSeven(&engine, TEST_FILE("scarceresources/scarceResourceCopyImportNoBinding.qml"));
-    object = componentSeven.create();
-    QVERIFY(object != 0); // the import should have caused the addition of a resource to the ScarceResources list
-    QVERIFY(ep->scarceResources.isEmpty()); // but they should have been released by this point.
-    delete object;
-
-    QDeclarativeComponent componentEight(&engine, TEST_FILE("scarceresources/scarceResourceCopyImportFail.qml"));
-    object = componentEight.create();
-    QVERIFY(object != 0);
-    QVERIFY(!object->property("scarceResourceCopy").isValid()); // wasn't preserved, so shouldn't be valid.
+    QVERIFY(eo->scarceResourceIsDetached()); // should be no other copies of it at this stage.
     QVERIFY(ep->scarceResources.isEmpty()); // should have been released by this point.
     delete object;
 
-    QDeclarativeComponent componentNine(&engine, TEST_FILE("scarceresources/scarceResourceCopyImport.qml"));
-    object = componentNine.create();
+    // test that if an Item which has JS ownership but has a scarce resource property is garbage collected,
+    // that the scarce resource is removed from the engine's list of scarce resources to clean up.
+    QDeclarativeComponent varComponentThirteen(&engine, TEST_FILE("scarceResourceObjectGc.var.qml"));
+    object = varComponentThirteen.create();
     QVERIFY(object != 0);
-    QVERIFY(object->property("scarceResourceCopy").isValid()); // preserved, so should be valid.
-    QCOMPARE(object->property("scarceResourceCopy").value<QPixmap>(), origPixmap);
-    QVERIFY(object->property("scarceResourceAssignedCopyOne").isValid()); // assigned before destroy(), so should be valid.
-    QCOMPARE(object->property("scarceResourceAssignedCopyOne").value<QPixmap>(), origPixmap);
-    QVERIFY(!object->property("scarceResourceAssignedCopyTwo").isValid()); // assigned after destroy(), so should be invalid.
-    QVERIFY(ep->scarceResources.isEmpty()); // this will still be zero, because "preserve()" REMOVES it from this list.
+    QVERIFY(!object->property("varProperty").isValid()); // not assigned yet
+    QMetaObject::invokeMethod(object, "assignVarProperty");
+    QVERIFY(ep->scarceResources.isEmpty());             // the scarce resource is a VME property.
+    QMetaObject::invokeMethod(object, "deassignVarProperty");
+    QVERIFY(ep->scarceResources.isEmpty());             // should still be empty; the resource should have been released on gc.
     delete object;
 
+    /* property variant semantics */
+
     // test that scarce resources are handled properly in signal invocation
-    QDeclarativeComponent componentTen(&engine, TEST_FILE("scarceresources/scarceResourceSignal.qml"));
-    object = componentTen.create();
+    QDeclarativeComponent variantComponentTen(&engine, TEST_FILE("scarceResourceSignal.variant.qml"));
+    object = variantComponentTen.create();
     QVERIFY(object != 0);
-    QObject *srsc = object->findChild<QObject*>("srsc");
+    srsc = object->findChild<QObject*>("srsc");
     QVERIFY(srsc);
     QVERIFY(!srsc->property("scarceResourceCopy").isValid()); // hasn't been instantiated yet.
     QCOMPARE(srsc->property("width"), QVariant(5)); // default value is 5.
@@ -3275,8 +3310,8 @@ void tst_qdeclarativeecmascript::scarceResources()
     delete object;
 
     // test that scarce resources are handled properly from js functions in qml files
-    QDeclarativeComponent componentEleven(&engine, TEST_FILE("scarceresources/scarceResourceFunction.qml"));
-    object = componentEleven.create();
+    QDeclarativeComponent variantComponentEleven(&engine, TEST_FILE("scarceResourceFunction.variant.qml"));
+    object = variantComponentEleven.create();
     QVERIFY(object != 0);
     QVERIFY(!object->property("scarceResourceCopy").isValid()); // not yet assigned, so should not be valid
     eo = qobject_cast<ScarceResourceObject*>(QDeclarativeProperty::read(object, "a").value<QObject*>());
@@ -3294,14 +3329,14 @@ void tst_qdeclarativeecmascript::scarceResources()
     delete object;
 
     // test that if an exception occurs while invoking js function from cpp, that the resources are released.
-    QDeclarativeComponent componentTwelve(&engine, TEST_FILE("scarceresources/scarceResourceFunctionFail.qml"));
-    object = componentTwelve.create();
+    QDeclarativeComponent variantComponentTwelve(&engine, TEST_FILE("scarceResourceFunctionFail.variant.qml"));
+    object = variantComponentTwelve.create();
     QVERIFY(object != 0);
     QVERIFY(!object->property("scarceResourceCopy").isValid()); // not yet assigned, so should not be valid
     eo = qobject_cast<ScarceResourceObject*>(QDeclarativeProperty::read(object, "a").value<QObject*>());
     QVERIFY(eo->scarceResourceIsDetached()); // should be no other copies of it at this stage.
-    QString srp_name = object->property("srp_name").toString();
-    QString expectedWarning = componentTwelve.url().toString() + QLatin1String(":17: TypeError: Property 'scarceResource' of object ") + srp_name + QLatin1String(" is not a function");
+    srp_name = object->property("srp_name").toString();
+    expectedWarning = variantComponentTwelve.url().toString() + QLatin1String(":16: TypeError: Property 'scarceResource' of object ") + srp_name + QLatin1String(" is not a function");
     QTest::ignoreMessage(QtWarningMsg, qPrintable(expectedWarning)); // we expect a meaningful warning to be printed.
     QMetaObject::invokeMethod(object, "retrieveScarceResource");
     QVERIFY(!object->property("scarceResourceCopy").isValid()); // due to exception, assignment will NOT have occurred.
@@ -3311,6 +3346,266 @@ void tst_qdeclarativeecmascript::scarceResources()
     delete object;
 }
 
+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")
+        << TEST_FILE("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")
+        << TEST_FILE("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")
+        << TEST_FILE("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")
+        << TEST_FILE("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")
+        << TEST_FILE("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")
+        << TEST_FILE("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")
+        << TEST_FILE("scarceResourceCopyImportNoBinding.var.qml")
+        << false // cannot check detach status.
+        << false
+        << QStringList()
+        << QList<QVariant>()
+        << QList<QVariant>()
+        << QStringList();
+    QTest::newRow("var: import with binding without explicit preserve")
+        << TEST_FILE("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")
+        << TEST_FILE("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")
+        << TEST_FILE("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")
+        << TEST_FILE("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")
+        << TEST_FILE("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")
+        << TEST_FILE("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")
+        << TEST_FILE("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")
+        << TEST_FILE("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")
+        << TEST_FILE("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")
+        << TEST_FILE("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")
+        << TEST_FILE("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")
+        << TEST_FILE("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")
+        << TEST_FILE("scarceResourceCopyImportNoBinding.variant.qml")
+        << false // cannot check detach status.
+        << false
+        << QStringList()
+        << QList<QVariant>()
+        << QList<QVariant>()
+        << QStringList();
+    QTest::newRow("variant: import with binding without explicit preserve")
+        << TEST_FILE("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")
+        << TEST_FILE("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;
+}
+
 void tst_qdeclarativeecmascript::propertyChangeSlots()
 {
     // ensure that allowable property names are allowed and onPropertyNameChanged slots are generated correctly.
@@ -4048,6 +4343,319 @@ void tst_qdeclarativeecmascript::readonlyDeclaration()
     delete object;
 }
 
+Q_DECLARE_METATYPE(QList<int>)
+Q_DECLARE_METATYPE(QList<qreal>)
+Q_DECLARE_METATYPE(QList<bool>)
+Q_DECLARE_METATYPE(QList<QString>)
+Q_DECLARE_METATYPE(QList<QUrl>)
+void tst_qdeclarativeecmascript::sequenceConversionRead()
+{
+    {
+        QUrl qmlFile = TEST_FILE("sequenceConversion.read.qml");
+        QDeclarativeComponent component(&engine, qmlFile);
+        QObject *object = component.create();
+        QVERIFY(object != 0);
+        MySequenceConversionObject *seq = object->findChild<MySequenceConversionObject*>("msco");
+        QVERIFY(seq != 0);
+
+        QMetaObject::invokeMethod(object, "readSequences");
+        QList<int> intList; intList << 1 << 2 << 3 << 4;
+        QCOMPARE(object->property("intListLength").toInt(), intList.length());
+        QCOMPARE(object->property("intList").value<QList<int> >(), intList);
+        QList<qreal> qrealList; qrealList << 1.1 << 2.2 << 3.3 << 4.4;
+        QCOMPARE(object->property("qrealListLength").toInt(), qrealList.length());
+        QCOMPARE(object->property("qrealList").value<QList<qreal> >(), qrealList);
+        QList<bool> boolList; boolList << true << false << true << false;
+        QCOMPARE(object->property("boolListLength").toInt(), boolList.length());
+        QCOMPARE(object->property("boolList").value<QList<bool> >(), boolList);
+        QList<QString> stringList; stringList << QLatin1String("first") << QLatin1String("second") << QLatin1String("third") << QLatin1String("fourth");
+        QCOMPARE(object->property("stringListLength").toInt(), stringList.length());
+        QCOMPARE(object->property("stringList").value<QList<QString> >(), stringList);
+        QList<QUrl> urlList; urlList << QUrl("http://www.example1.com") << QUrl("http://www.example2.com") << QUrl("http://www.example3.com");
+        QCOMPARE(object->property("urlListLength").toInt(), urlList.length());
+        QCOMPARE(object->property("urlList").value<QList<QUrl> >(), urlList);
+        QStringList qstringList; qstringList << QLatin1String("first") << QLatin1String("second") << QLatin1String("third") << QLatin1String("fourth");
+        QCOMPARE(object->property("qstringListLength").toInt(), qstringList.length());
+        QCOMPARE(object->property("qstringList").value<QStringList>(), qstringList);
+
+        QMetaObject::invokeMethod(object, "readSequenceElements");
+        QCOMPARE(object->property("intVal").toInt(), 2);
+        QCOMPARE(object->property("qrealVal").toReal(), 2.2);
+        QCOMPARE(object->property("boolVal").toBool(), false);
+        QCOMPARE(object->property("stringVal").toString(), QString(QLatin1String("second")));
+        QCOMPARE(object->property("urlVal").toUrl(), QUrl("http://www.example2.com"));
+        QCOMPARE(object->property("qstringVal").toString(), QString(QLatin1String("second")));
+
+        QMetaObject::invokeMethod(object, "enumerateSequenceElements");
+        QCOMPARE(object->property("enumerationMatches").toBool(), true);
+
+        intList.clear(); intList << 1 << 2 << 3 << 4 << 5; // set by the enumerateSequenceElements test.
+        QDeclarativeProperty seqProp(seq, "intListProperty");
+        QCOMPARE(seqProp.read().value<QList<int> >(), intList);
+        QDeclarativeProperty seqProp2(seq, "intListProperty", &engine);
+        QCOMPARE(seqProp2.read().value<QList<int> >(), intList);
+
+        QMetaObject::invokeMethod(object, "testReferenceDeletion");
+        QCOMPARE(object->property("referenceDeletion").toBool(), true);
+
+        delete object;
+    }
+
+    {
+        QUrl qmlFile = TEST_FILE("sequenceConversion.read.error.qml");
+        QDeclarativeComponent component(&engine, qmlFile);
+        QObject *object = component.create();
+        QVERIFY(object != 0);
+        MySequenceConversionObject *seq = object->findChild<MySequenceConversionObject*>("msco");
+        QVERIFY(seq != 0);
+
+        // we haven't registered QList<QPoint> as a sequence type.
+        QString warningOne = QLatin1String("QMetaProperty::read: Unable to handle unregistered datatype 'QList<QPoint>' for property 'MySequenceConversionObject::pointListProperty'");
+        QString warningTwo = qmlFile.toString() + QLatin1String(":18: TypeError: Cannot read property 'length' of undefined");
+        QTest::ignoreMessage(QtWarningMsg, warningOne.toAscii().constData());
+        QTest::ignoreMessage(QtWarningMsg, warningTwo.toAscii().constData());
+
+        QMetaObject::invokeMethod(object, "performTest");
+
+        // QList<QPoint> has not been registered as a sequence type.
+        QCOMPARE(object->property("pointListLength").toInt(), 0);
+        QVERIFY(!object->property("pointList").isValid());
+        QTest::ignoreMessage(QtWarningMsg, "QMetaProperty::read: Unable to handle unregistered datatype 'QList<QPoint>' for property 'MySequenceConversionObject::pointListProperty'");
+        QDeclarativeProperty seqProp(seq, "pointListProperty", &engine);
+        QVERIFY(!seqProp.read().isValid()); // not a valid/known sequence type
+
+        delete object;
+    }
+}
+
+void tst_qdeclarativeecmascript::sequenceConversionWrite()
+{
+    {
+        QUrl qmlFile = TEST_FILE("sequenceConversion.write.qml");
+        QDeclarativeComponent component(&engine, qmlFile);
+        QObject *object = component.create();
+        QVERIFY(object != 0);
+        MySequenceConversionObject *seq = object->findChild<MySequenceConversionObject*>("msco");
+        QVERIFY(seq != 0);
+
+        QMetaObject::invokeMethod(object, "writeSequences");
+        QCOMPARE(object->property("success").toBool(), true);
+
+        QMetaObject::invokeMethod(object, "writeSequenceElements");
+        QCOMPARE(object->property("success").toBool(), true);
+
+        QMetaObject::invokeMethod(object, "writeOtherElements");
+        QCOMPARE(object->property("success").toBool(), true);
+
+        QMetaObject::invokeMethod(object, "testReferenceDeletion");
+        QCOMPARE(object->property("referenceDeletion").toBool(), true);
+
+        delete object;
+    }
+
+    {
+        QUrl qmlFile = TEST_FILE("sequenceConversion.write.error.qml");
+        QDeclarativeComponent component(&engine, qmlFile);
+        QObject *object = component.create();
+        QVERIFY(object != 0);
+        MySequenceConversionObject *seq = object->findChild<MySequenceConversionObject*>("msco");
+        QVERIFY(seq != 0);
+
+        // we haven't registered QList<QPoint> as a sequence type, so writing shouldn't work.
+        QString warningOne = qmlFile.toString() + QLatin1String(":16: Error: Cannot assign QVariantList to void");
+        QTest::ignoreMessage(QtWarningMsg, warningOne.toAscii().constData());
+
+        QMetaObject::invokeMethod(object, "performTest");
+
+        QList<QPoint> pointList; pointList << QPoint(1, 2) << QPoint(3, 4) << QPoint(5, 6); // original values, shouldn't have changed
+        QCOMPARE(seq->pointListProperty(), pointList);
+
+        delete object;
+    }
+}
+
+void tst_qdeclarativeecmascript::sequenceConversionArray()
+{
+    // ensure that in JS the returned sequences act just like normal JS Arrays.
+    QUrl qmlFile = TEST_FILE("sequenceConversion.array.qml");
+    QDeclarativeComponent component(&engine, qmlFile);
+    QObject *object = component.create();
+    QVERIFY(object != 0);
+    QMetaObject::invokeMethod(object, "indexedAccess");
+    QVERIFY(object->property("success").toBool());
+    QMetaObject::invokeMethod(object, "arrayOperations");
+    QVERIFY(object->property("success").toBool());
+    QMetaObject::invokeMethod(object, "testEqualitySemantics");
+    QVERIFY(object->property("success").toBool());
+    QMetaObject::invokeMethod(object, "testReferenceDeletion");
+    QCOMPARE(object->property("referenceDeletion").toBool(), true);
+    delete object;
+}
+
+void tst_qdeclarativeecmascript::sequenceConversionThreads()
+{
+    // ensure that sequence conversion operations work correctly in a worker thread
+    // and that serialisation between the main and worker thread succeeds.
+    QUrl qmlFile = TEST_FILE("sequenceConversion.threads.qml");
+    QDeclarativeComponent component(&engine, qmlFile);
+    QObject *object = component.create();
+    QVERIFY(object != 0);
+
+    QMetaObject::invokeMethod(object, "testIntSequence");
+    QTRY_VERIFY(object->property("finished").toBool());
+    QVERIFY(object->property("success").toBool());
+
+    QMetaObject::invokeMethod(object, "testQrealSequence");
+    QTRY_VERIFY(object->property("finished").toBool());
+    QVERIFY(object->property("success").toBool());
+
+    QMetaObject::invokeMethod(object, "testBoolSequence");
+    QTRY_VERIFY(object->property("finished").toBool());
+    QVERIFY(object->property("success").toBool());
+
+    QMetaObject::invokeMethod(object, "testStringSequence");
+    QTRY_VERIFY(object->property("finished").toBool());
+    QVERIFY(object->property("success").toBool());
+
+    QMetaObject::invokeMethod(object, "testQStringSequence");
+    QTRY_VERIFY(object->property("finished").toBool());
+    QVERIFY(object->property("success").toBool());
+
+    QMetaObject::invokeMethod(object, "testUrlSequence");
+    QTRY_VERIFY(object->property("finished").toBool());
+    QVERIFY(object->property("success").toBool());
+
+    QMetaObject::invokeMethod(object, "testVariantSequence");
+    QTRY_VERIFY(object->property("finished").toBool());
+    QVERIFY(object->property("success").toBool());
+
+    delete object;
+}
+
+void tst_qdeclarativeecmascript::sequenceConversionBindings()
+{
+    {
+        QUrl qmlFile = TEST_FILE("sequenceConversion.bindings.qml");
+        QDeclarativeComponent component(&engine, qmlFile);
+        QObject *object = component.create();
+        QVERIFY(object != 0);
+        QList<int> intList; intList << 1 << 2 << 3 << 12 << 7;
+        QCOMPARE(object->property("boundSequence").value<QList<int> >(), intList);
+        QCOMPARE(object->property("boundElement").toInt(), intList.at(3));
+        QList<int> intListTwo; intListTwo << 1 << 2 << 3 << 12 << 14;
+        QCOMPARE(object->property("boundSequenceTwo").value<QList<int> >(), intListTwo);
+        delete object;
+    }
+
+    {
+        QUrl qmlFile = TEST_FILE("sequenceConversion.bindings.error.qml");
+        QString warning = QString(QLatin1String("%1:17: Unable to assign QList<int> to QList<bool>")).arg(qmlFile.toString());
+        QTest::ignoreMessage(QtWarningMsg, warning.toAscii().constData());
+        QDeclarativeComponent component(&engine, qmlFile);
+        QObject *object = component.create();
+        QVERIFY(object != 0);
+        delete object;
+    }
+}
+
+void tst_qdeclarativeecmascript::sequenceConversionCopy()
+{
+    QUrl qmlFile = TEST_FILE("sequenceConversion.copy.qml");
+    QDeclarativeComponent component(&engine, qmlFile);
+    QObject *object = component.create();
+    QVERIFY(object != 0);
+    QMetaObject::invokeMethod(object, "testCopySequences");
+    QCOMPARE(object->property("success").toBool(), true);
+    QMetaObject::invokeMethod(object, "readSequenceCopyElements");
+    QCOMPARE(object->property("success").toBool(), true);
+    QMetaObject::invokeMethod(object, "testEqualitySemantics");
+    QCOMPARE(object->property("success").toBool(), true);
+    delete object;
+}
+
+void tst_qdeclarativeecmascript::assignSequenceTypes()
+{
+    // test binding array to sequence type property
+    {
+    QDeclarativeComponent component(&engine, TEST_FILE("assignSequenceTypes.1.qml"));
+    MySequenceConversionObject *object = qobject_cast<MySequenceConversionObject *>(component.create());
+    QVERIFY(object != 0);
+    QCOMPARE(object->intListProperty(), (QList<int>() << 1 << 2));
+    QCOMPARE(object->qrealListProperty(), (QList<qreal>() << 1.1 << 2.2));
+    QCOMPARE(object->boolListProperty(), (QList<bool>() << false << true));
+    QCOMPARE(object->urlListProperty(), (QList<QUrl>() << QUrl("http://www.example1.com") << QUrl("http://www.example2.com")));
+    QCOMPARE(object->stringListProperty(), (QList<QString>() << QLatin1String("one") << QLatin1String("two")));
+    QCOMPARE(object->qstringListProperty(), (QStringList() << QLatin1String("one") << QLatin1String("two")));
+    delete object;
+    }
+
+    // test binding literal to sequence type property
+    {
+    QDeclarativeComponent component(&engine, TEST_FILE("assignSequenceTypes.2.qml"));
+    MySequenceConversionObject *object = qobject_cast<MySequenceConversionObject *>(component.create());
+    QVERIFY(object != 0);
+    QCOMPARE(object->intListProperty(), (QList<int>() << 1));
+    QCOMPARE(object->qrealListProperty(), (QList<qreal>() << 1.1));
+    QCOMPARE(object->boolListProperty(), (QList<bool>() << false));
+    QCOMPARE(object->urlListProperty(), (QList<QUrl>() << QUrl("http://www.example1.com")));
+    QCOMPARE(object->stringListProperty(), (QList<QString>() << QLatin1String("one")));
+    QCOMPARE(object->qstringListProperty(), (QStringList() << QLatin1String("two")));
+    delete object;
+    }
+
+    // test binding single value to sequence type property
+    {
+    QDeclarativeComponent component(&engine, TEST_FILE("assignSequenceTypes.3.qml"));
+    MySequenceConversionObject *object = qobject_cast<MySequenceConversionObject *>(component.create());
+    QVERIFY(object != 0);
+    QCOMPARE(object->intListProperty(), (QList<int>() << 1));
+    QCOMPARE(object->qrealListProperty(), (QList<qreal>() << 1.1));
+    QCOMPARE(object->boolListProperty(), (QList<bool>() << false));
+    QCOMPARE(object->urlListProperty(), (QList<QUrl>() << QUrl(TEST_FILE("example.html"))));
+    delete object;
+    }
+
+    // test assigning array to sequence type property in js function
+    {
+    QDeclarativeComponent component(&engine, TEST_FILE("assignSequenceTypes.4.qml"));
+    MySequenceConversionObject *object = qobject_cast<MySequenceConversionObject *>(component.create());
+    QVERIFY(object != 0);
+    QCOMPARE(object->intListProperty(), (QList<int>() << 1 << 2));
+    QCOMPARE(object->qrealListProperty(), (QList<qreal>() << 1.1 << 2.2));
+    QCOMPARE(object->boolListProperty(), (QList<bool>() << false << true));
+    QCOMPARE(object->urlListProperty(), (QList<QUrl>() << QUrl("http://www.example1.com") << QUrl("http://www.example2.com")));
+    QCOMPARE(object->stringListProperty(), (QList<QString>() << QLatin1String("one") << QLatin1String("two")));
+    QCOMPARE(object->qstringListProperty(), (QStringList() << QLatin1String("one") << QLatin1String("two")));
+    delete object;
+    }
+
+    // test assigning literal to sequence type property in js function
+    {
+    QDeclarativeComponent component(&engine, TEST_FILE("assignSequenceTypes.5.qml"));
+    MySequenceConversionObject *object = qobject_cast<MySequenceConversionObject *>(component.create());
+    QVERIFY(object != 0);
+    QCOMPARE(object->intListProperty(), (QList<int>() << 1));
+    QCOMPARE(object->qrealListProperty(), (QList<qreal>() << 1.1));
+    QCOMPARE(object->boolListProperty(), (QList<bool>() << false));
+    QCOMPARE(object->urlListProperty(), (QList<QUrl>() << QUrl("http://www.example1.com")));
+    QCOMPARE(object->stringListProperty(), (QList<QString>() << QLatin1String("one")));
+    QCOMPARE(object->qstringListProperty(), (QStringList() << QLatin1String("two")));
+    delete object;
+    }
+
+    // test assigning single value to sequence type property in js function
+    {
+    QDeclarativeComponent component(&engine, TEST_FILE("assignSequenceTypes.6.qml"));
+    MySequenceConversionObject *object = qobject_cast<MySequenceConversionObject *>(component.create());
+    QVERIFY(object != 0);
+    QCOMPARE(object->intListProperty(), (QList<int>() << 1));
+    QCOMPARE(object->qrealListProperty(), (QList<qreal>() << 1.1));
+    QCOMPARE(object->boolListProperty(), (QList<bool>() << false));
+    QCOMPARE(object->urlListProperty(), (QList<QUrl>() << QUrl(TEST_FILE("example.html"))));
+    delete object;
+    }
+}
+
 // Test that assigning a null object works 
 // Regressed with: df1788b4dbbb2826ae63f26bdf166342595343f4
 void tst_qdeclarativeecmascript::nullObjectBinding()
@@ -4494,6 +5102,15 @@ void tst_qdeclarativeecmascript::qtbug_11600()
     delete o;
 }
 
+void tst_qdeclarativeecmascript::qtbug_21864()
+{
+    QDeclarativeComponent component(&engine, TEST_FILE("qtbug_21864.qml"));
+    QObject *o = component.create();
+    QVERIFY(o != 0);
+    QCOMPARE(o->property("test").toBool(), true);
+    delete o;
+}
+
 // Reading and writing non-scriptable properties should fail
 void tst_qdeclarativeecmascript::nonscriptable()
 {
@@ -4528,10 +5145,19 @@ void tst_qdeclarativeecmascript::in()
 void tst_qdeclarativeecmascript::typeOf()
 {
     QDeclarativeComponent component(&engine, TEST_FILE("typeOf.qml"));
+
+    // These warnings should not happen once QTBUG-21864 is fixed
+    QString warning1 = component.url().toString() + QLatin1String(":16: Error: Cannot assign [undefined] to QString");
+    QString warning2 = component.url().resolved(QUrl("typeOf.js")).toString() + QLatin1String(":1: ReferenceError: Can't find variable: a");
+
+    QTest::ignoreMessage(QtWarningMsg, qPrintable(warning1));
+    QTest::ignoreMessage(QtWarningMsg, qPrintable(warning2));
+
     QObject *o = component.create();
     QVERIFY(o != 0);
-    QCOMPARE(o->property("test1").toString(), QLatin1String("undefined"));
+
     QEXPECT_FAIL("", "QTBUG-21864", Abort);
+    QCOMPARE(o->property("test1").toString(), QLatin1String("undefined"));
     QCOMPARE(o->property("test2").toString(), QLatin1String("object"));
     QCOMPARE(o->property("test3").toString(), QLatin1String("number"));
     QCOMPARE(o->property("test4").toString(), QLatin1String("string"));
@@ -4675,6 +5301,19 @@ void tst_qdeclarativeecmascript::aliasToCompositeElement()
     delete object;
 }
 
+void tst_qdeclarativeecmascript::qtbug_20344()
+{
+    QDeclarativeComponent component(&engine, TEST_FILE("qtbug_20344.qml"));
+
+    QString warning = component.url().toString() + ":5: Error: Exception thrown from within QObject slot";
+    QTest::ignoreMessage(QtWarningMsg, qPrintable(warning));
+
+    QObject *object = component.create();
+    QVERIFY(object != 0);
+
+    delete object;
+}
+
 void tst_qdeclarativeecmascript::revisionErrors()
 {
     {
@@ -4796,6 +5435,13 @@ void tst_qdeclarativeecmascript::automaticSemicolon()
     QVERIFY(object != 0);
 }
 
+void tst_qdeclarativeecmascript::unaryExpression()
+{
+    QDeclarativeComponent component(&engine, TEST_FILE("unaryExpression.qml"));
+    QObject *object = component.create();
+    QVERIFY(object != 0);
+}
+
 // Makes sure that a binding isn't double re-evaluated when it depends on the same variable twice
 void tst_qdeclarativeecmascript::doubleEvaluate()
 {
@@ -4813,6 +5459,39 @@ void tst_qdeclarativeecmascript::doubleEvaluate()
     delete object;
 }
 
+static QStringList messages;
+static void captureMsgHandler(QtMsgType, const char *msg)
+{
+    messages.append(QLatin1String(msg));
+}
+
+void tst_qdeclarativeecmascript::nonNotifyable()
+{
+    QV4Compiler::enableV4(false);
+    QDeclarativeComponent component(&engine, TEST_FILE("nonNotifyable.qml"));
+    QV4Compiler::enableV4(true);
+
+    QtMsgHandler old = qInstallMsgHandler(captureMsgHandler);
+    messages.clear();
+    QObject *object = component.create();
+    qInstallMsgHandler(old);
+
+    QVERIFY(object != 0);
+
+    QString expected1 = QLatin1String("QDeclarativeExpression: Expression ") +
+                        component.url().toString() +
+                        QLatin1String(":5 depends on non-NOTIFYable properties:");
+    QString expected2 = QLatin1String("    ") +
+                        QLatin1String(object->metaObject()->className()) +
+                        QLatin1String("::value");
+
+    QCOMPARE(messages.length(), 2);
+    QCOMPARE(messages.at(0), expected1);
+    QCOMPARE(messages.at(1), expected2);
+
+    delete object;
+}
+
 void tst_qdeclarativeecmascript::forInLoop()
 {
     QDeclarativeComponent component(&engine, TEST_FILE("forInLoop.qml"));
@@ -4832,6 +5511,264 @@ void tst_qdeclarativeecmascript::forInLoop()
     delete object;
 }
 
+// An object the binding depends on is deleted while the binding is still running
+void tst_qdeclarativeecmascript::deleteWhileBindingRunning()
+{
+    QDeclarativeComponent component(&engine, TEST_FILE("deleteWhileBindingRunning.qml"));
+    QObject *object = component.create();
+    QVERIFY(object != 0);
+    delete object;
+}
+
+void tst_qdeclarativeecmascript::qtbug_22679()
+{
+    MyQmlObject object;
+    object.setStringProperty(QLatin1String("Please work correctly"));
+    engine.rootContext()->setContextProperty("contextProp", &object);
+
+    QDeclarativeComponent component(&engine, TEST_FILE("qtbug_22679.qml"));
+    qRegisterMetaType<QList<QDeclarativeError> >("QList<QDeclarativeError>");
+    QSignalSpy warningsSpy(&engine, SIGNAL(warnings(QList<QDeclarativeError>)));
+
+    QObject *o = component.create();
+    QVERIFY(o != 0);
+    QCOMPARE(warningsSpy.count(), 0);
+    delete o;
+}
+
+void tst_qdeclarativeecmascript::qtbug_22843_data()
+{
+    QTest::addColumn<bool>("library");
+
+    QTest::newRow("without .pragma library") << false;
+    QTest::newRow("with .pragma library") << true;
+}
+
+void tst_qdeclarativeecmascript::qtbug_22843()
+{
+    QFETCH(bool, library);
+
+    QString fileName("qtbug_22843");
+    if (library)
+        fileName += QLatin1String(".library");
+    fileName += QLatin1String(".qml");
+
+    QDeclarativeComponent component(&engine, TEST_FILE(fileName));
+    QString url = component.url().toString();
+    QString warning1 = url.left(url.length()-3) + QLatin1String("js:4: SyntaxError: Unexpected token )");
+    QString warning2 = url + QLatin1String(":5: TypeError: Object [object Object] has no method 'func'");
+
+    qRegisterMetaType<QList<QDeclarativeError> >("QList<QDeclarativeError>");
+    QSignalSpy warningsSpy(&engine, SIGNAL(warnings(QList<QDeclarativeError>)));
+    for (int x = 0; x < 3; ++x) {
+        warningsSpy.clear();
+        // For libraries, only the first import attempt should produce a
+        // SyntaxError warning; subsequent component creation should not
+        // attempt to reload the script.
+        bool expectSyntaxError = !library || (x == 0);
+        if (expectSyntaxError)
+            QTest::ignoreMessage(QtWarningMsg, qPrintable(warning1));
+        QTest::ignoreMessage(QtWarningMsg, qPrintable(warning2));
+        QObject *object = component.create();
+        QVERIFY(object != 0);
+        QCOMPARE(warningsSpy.count(), 1 + (expectSyntaxError?1:0));
+        delete object;
+    }
+}
+
+
+void tst_qdeclarativeecmascript::switchStatement()
+{
+    {
+        QDeclarativeComponent component(&engine, TEST_FILE("switchStatement.1.qml"));
+        MyQmlObject *object = qobject_cast<MyQmlObject *>(component.create());
+        QVERIFY(object != 0);
+
+        // `object->value()' is the number of executed statements
+
+        object->setStringProperty("A");
+        QCOMPARE(object->value(), 5);
+
+        object->setStringProperty("S");
+        QCOMPARE(object->value(), 3);
+
+        object->setStringProperty("D");
+        QCOMPARE(object->value(), 3);
+
+        object->setStringProperty("F");
+        QCOMPARE(object->value(), 4);
+
+        object->setStringProperty("something else");
+        QCOMPARE(object->value(), 1);
+    }
+
+    {
+        QDeclarativeComponent component(&engine, TEST_FILE("switchStatement.2.qml"));
+        MyQmlObject *object = qobject_cast<MyQmlObject *>(component.create());
+        QVERIFY(object != 0);
+
+        // `object->value()' is the number of executed statements
+
+        object->setStringProperty("A");
+        QCOMPARE(object->value(), 5);
+
+        object->setStringProperty("S");
+        QCOMPARE(object->value(), 3);
+
+        object->setStringProperty("D");
+        QCOMPARE(object->value(), 3);
+
+        object->setStringProperty("F");
+        QCOMPARE(object->value(), 3);
+
+        object->setStringProperty("something else");
+        QCOMPARE(object->value(), 4);
+    }
+
+    {
+        QDeclarativeComponent component(&engine, TEST_FILE("switchStatement.3.qml"));
+        MyQmlObject *object = qobject_cast<MyQmlObject *>(component.create());
+        QVERIFY(object != 0);
+
+        // `object->value()' is the number of executed statements
+
+        object->setStringProperty("A");
+        QCOMPARE(object->value(), 5);
+
+        object->setStringProperty("S");
+        QCOMPARE(object->value(), 3);
+
+        object->setStringProperty("D");
+        QCOMPARE(object->value(), 3);
+
+        object->setStringProperty("F");
+        QCOMPARE(object->value(), 3);
+
+        object->setStringProperty("something else");
+        QCOMPARE(object->value(), 6);
+    }
+
+    {
+        QDeclarativeComponent component(&engine, TEST_FILE("switchStatement.4.qml"));
+
+        QString warning = component.url().toString() + ":4: Unable to assign [undefined] to int";
+        QTest::ignoreMessage(QtWarningMsg, qPrintable(warning));
+
+        MyQmlObject *object = qobject_cast<MyQmlObject *>(component.create());
+        QVERIFY(object != 0);
+
+        // `object->value()' is the number of executed statements
+
+        object->setStringProperty("A");
+        QCOMPARE(object->value(), 5);
+
+        object->setStringProperty("S");
+        QCOMPARE(object->value(), 3);
+
+        object->setStringProperty("D");
+        QCOMPARE(object->value(), 3);
+
+        object->setStringProperty("F");
+        QCOMPARE(object->value(), 3);
+
+        QTest::ignoreMessage(QtWarningMsg, qPrintable(warning));
+
+        object->setStringProperty("something else");
+    }
+
+    {
+        QDeclarativeComponent component(&engine, TEST_FILE("switchStatement.5.qml"));
+        MyQmlObject *object = qobject_cast<MyQmlObject *>(component.create());
+        QVERIFY(object != 0);
+
+        // `object->value()' is the number of executed statements
+
+        object->setStringProperty("A");
+        QCOMPARE(object->value(), 1);
+
+        object->setStringProperty("S");
+        QCOMPARE(object->value(), 1);
+
+        object->setStringProperty("D");
+        QCOMPARE(object->value(), 1);
+
+        object->setStringProperty("F");
+        QCOMPARE(object->value(), 1);
+
+        object->setStringProperty("something else");
+        QCOMPARE(object->value(), 1);
+    }
+
+    {
+        QDeclarativeComponent component(&engine, TEST_FILE("switchStatement.6.qml"));
+        MyQmlObject *object = qobject_cast<MyQmlObject *>(component.create());
+        QVERIFY(object != 0);
+
+        // `object->value()' is the number of executed statements
+
+        object->setStringProperty("A");
+        QCOMPARE(object->value(), 123);
+
+        object->setStringProperty("S");
+        QCOMPARE(object->value(), 123);
+
+        object->setStringProperty("D");
+        QCOMPARE(object->value(), 321);
+
+        object->setStringProperty("F");
+        QCOMPARE(object->value(), 321);
+
+        object->setStringProperty("something else");
+        QCOMPARE(object->value(), 0);
+    }
+}
+
+void tst_qdeclarativeecmascript::withStatement()
+{
+    {
+        QDeclarativeComponent component(&engine, TEST_FILE("withStatement.1.qml"));
+        MyQmlObject *object = qobject_cast<MyQmlObject *>(component.create());
+        QVERIFY(object != 0);
+
+        QCOMPARE(object->value(), 123);
+    }
+}
+
+void tst_qdeclarativeecmascript::tryStatement()
+{
+    {
+        QDeclarativeComponent component(&engine, TEST_FILE("tryStatement.1.qml"));
+        MyQmlObject *object = qobject_cast<MyQmlObject *>(component.create());
+        QVERIFY(object != 0);
+
+        QCOMPARE(object->value(), 123);
+    }
+
+    {
+        QDeclarativeComponent component(&engine, TEST_FILE("tryStatement.2.qml"));
+        MyQmlObject *object = qobject_cast<MyQmlObject *>(component.create());
+        QVERIFY(object != 0);
+
+        QCOMPARE(object->value(), 321);
+    }
+
+    {
+        QDeclarativeComponent component(&engine, TEST_FILE("tryStatement.3.qml"));
+        MyQmlObject *object = qobject_cast<MyQmlObject *>(component.create());
+        QVERIFY(object != 0);
+
+        QCOMPARE(object->value(), 1);
+    }
+
+    {
+        QDeclarativeComponent component(&engine, TEST_FILE("tryStatement.4.qml"));
+        MyQmlObject *object = qobject_cast<MyQmlObject *>(component.create());
+        QVERIFY(object != 0);
+
+        QCOMPARE(object->value(), 1);
+    }
+}
+
 QTEST_MAIN(tst_qdeclarativeecmascript)
 
 #include "tst_qdeclarativeecmascript.moc"