Implement script module api property get and set
authorChris Adams <christopher.adams@nokia.com>
Wed, 3 Aug 2011 01:04:01 +0000 (11:04 +1000)
committerQt by Nokia <qt-info@nokia.com>
Tue, 30 Aug 2011 05:15:51 +0000 (07:15 +0200)
This commit adds code for property get and set for script module
APIs, and also splits up the module API unit tests into QObject and
Script (QJSValue) parts.
Related to commit: 3ee8a19f5b7142b96e2df649ea0dac444b5622a2

Task-number: QMLNG-33
Task-number: QTBUG-17318
Change-Id: I4aaf5d1cc1d4774dd0f0999f0985439e4d76f0ca
Reviewed-on: http://codereview.qt.nokia.com/1472
Reviewed-by: Qt Sanity Bot <qt_sanity_bot@ovi.com>
Reviewed-by: Aaron Kennedy <aaron.kennedy@nokia.com>

13 files changed:
src/declarative/qml/qdeclarative.h
src/declarative/qml/v8/qv8typewrapper.cpp
tests/auto/declarative/qdeclarativeecmascript/data/moduleapi/moduleApiMajorVersionFail.qml [moved from tests/auto/declarative/qdeclarativeecmascript/data/moduleApiMajorVersionFail.qml with 100% similarity]
tests/auto/declarative/qdeclarativeecmascript/data/moduleapi/moduleApiMinorVersionFail.qml [moved from tests/auto/declarative/qdeclarativeecmascript/data/moduleApiMinorVersionFail.qml with 100% similarity]
tests/auto/declarative/qdeclarativeecmascript/data/moduleapi/qobjectModuleApi.qml [moved from tests/auto/declarative/qdeclarativeecmascript/data/moduleApi.qml with 87% similarity]
tests/auto/declarative/qdeclarativeecmascript/data/moduleapi/qobjectModuleApiCaching.qml [moved from tests/auto/declarative/qdeclarativeecmascript/data/moduleApiCaching.qml with 70% similarity]
tests/auto/declarative/qdeclarativeecmascript/data/moduleapi/qobjectModuleApiWriting.qml [moved from tests/auto/declarative/qdeclarativeecmascript/data/moduleApiWriting.qml with 91% similarity]
tests/auto/declarative/qdeclarativeecmascript/data/moduleapi/scriptModuleApi.qml [new file with mode: 0644]
tests/auto/declarative/qdeclarativeecmascript/data/moduleapi/scriptModuleApiCaching.qml [new file with mode: 0644]
tests/auto/declarative/qdeclarativeecmascript/data/moduleapi/scriptModuleApiWriting.qml [new file with mode: 0644]
tests/auto/declarative/qdeclarativeecmascript/testtypes.cpp
tests/auto/declarative/qdeclarativeecmascript/testtypes.h
tests/auto/declarative/qdeclarativeecmascript/tst_qdeclarativeecmascript.cpp

index 311ecd3..a0eb98d 100644 (file)
@@ -420,33 +420,35 @@ Q_DECLARATIVE_EXPORT void qmlRegisterBaseTypes(const char *uri, int versionMajor
    Installing a module API into a uri allows developers to provide arbitrary functionality
    (methods and properties) in a namespace that doesn't necessarily contain elements.
 
-   A module API may be either a QObject or a QScriptValue.  Only one module API provider
+   A module API may be either a QObject or a QJSValue.  Only one module API provider
    may be registered into any given namespace (combination of \a uri, \a majorVersion and \a minorVersion).
-   This function should be used to register a module API provider function which returns a QScriptValue as a module API.
+   This function should be used to register a module API provider function which returns a QJSValue as a module API.
+
+   \e NOTE: QJSValue module API properties will \e not trigger binding re-evaluation if changed.
 
    Usage:
    \code
    // first, define the module API provider function (callback).
-   static QScriptValue *example_qscriptvalue_module_api_provider(QDeclarativeEngine *engine, QScriptEngine *scriptEngine)
+   static QJSValue *example_qjsvalue_module_api_provider(QDeclarativeEngine *engine, QJSEngine *scriptEngine)
    {
        Q_UNUSED(engine)
 
        static int seedValue = 5;
-       QScriptValue example = scriptEngine->newObject();
+       QJSValue example = scriptEngine->newObject();
        example.setProperty("someProperty", seedValue++);
        return example;
    }
 
    // second, register the module API provider with QML by calling this function in an initialization function.
    ...
-   qmlRegisterModuleApi("Qt.example.qscriptvalueApi", 1, 0, example_qscriptvalue_module_api_provider);
+   qmlRegisterModuleApi("Qt.example.qjsvalueApi", 1, 0, example_qjsvalue_module_api_provider);
    ...
    \endcode
 
    In order to use the registered module API in QML, you must import the module API.
    \qml
    import QtQuick 2.0
-   import Qt.example.qscriptvalueApi 1.0 as ExampleApi
+   import Qt.example.qjsvalueApi 1.0 as ExampleApi
    Item {
        id: root
        property int someValue: ExampleApi.someProperty
@@ -474,7 +476,7 @@ inline int qmlRegisterModuleApi(const char *uri, int versionMajor, int versionMi
    Installing a module API into a uri allows developers to provide arbitrary functionality
    (methods and properties) in a namespace that doesn't necessarily contain elements.
 
-   A module API may be either a QObject or a QScriptValue.  Only one module API provider
+   A module API may be either a QObject or a QJSValue.  Only one module API provider
    may be registered into any given namespace (combination of \a uri, \a majorVersion and \a minorVersion).
    This function should be used to register a module API provider function which returns a QObject as a module API.
 
@@ -507,7 +509,7 @@ inline int qmlRegisterModuleApi(const char *uri, int versionMajor, int versionMi
    };
 
    // second, define the module API provider function (callback).
-   static QObject *example_qobject_module_api_provider(QDeclarativeEngine *engine, QScriptEngine *scriptEngine)
+   static QObject *example_qobject_module_api_provider(QDeclarativeEngine *engine, QJSEngine *scriptEngine)
    {
        Q_UNUSED(engine)
        Q_UNUSED(scriptEngine)
index c51a2ee..98ed1d5 100644 (file)
@@ -45,6 +45,9 @@
 #include <private/qdeclarativeengine_p.h>
 #include <private/qdeclarativecontext_p.h>
 
+#include <private/qjsvalue_p.h>
+#include <private/qscript_impl_p.h>
+
 QT_BEGIN_NAMESPACE
 
 class QV8TypeResource : public QV8ObjectResource
@@ -186,6 +189,11 @@ v8::Handle<v8::Value> QV8TypeWrapper::Getter(v8::Local<v8::String> property,
             if (moduleApi->qobjectApi) {
                 v8::Handle<v8::Value> rv = v8engine->qobjectWrapper()->getProperty(moduleApi->qobjectApi, propertystring, QV8QObjectWrapper::IgnoreRevision);
                 return rv;
+            } else if (moduleApi->scriptApi.isValid()) {
+                // NOTE: if used in a binding, changes will not trigger re-evaluation since non-NOTIFYable.
+                QJSValuePrivate *apiprivate = QJSValuePrivate::get(moduleApi->scriptApi);
+                QScopedPointer<QJSValuePrivate> propertyValue(apiprivate->property(property).give());
+                return propertyValue->asV8Value(v8engine);
             } else {
                 return v8::Handle<v8::Value>();
             }
@@ -212,8 +220,6 @@ v8::Handle<v8::Value> QV8TypeWrapper::Setter(v8::Local<v8::String> property,
 
     QV8Engine *v8engine = resource->engine;
 
-    // XXX TODO: Implement writes to module API objects
-
     QHashedV8String propertystring(property);
 
     if (resource->type && resource->object) {
@@ -235,9 +241,20 @@ v8::Handle<v8::Value> QV8TypeWrapper::Setter(v8::Local<v8::String> property,
                 moduleApi->qobjectCallback = 0;
             }
 
-            if (moduleApi->qobjectApi) 
+            if (moduleApi->qobjectApi) {
                 v8engine->qobjectWrapper()->setProperty(moduleApi->qobjectApi, propertystring, value, 
                                                         QV8QObjectWrapper::IgnoreRevision);
+            } else if (moduleApi->scriptApi.isValid()) {
+                QScopedPointer<QJSValuePrivate> setvalp(new QJSValuePrivate(v8engine, value));
+                QJSValuePrivate *apiprivate = QJSValuePrivate::get(moduleApi->scriptApi);
+                if (apiprivate->propertyFlags(property) & QJSValue::ReadOnly) {
+                    QString error = QLatin1String("Cannot assign to read-only property \"") +
+                                    v8engine->toString(property) + QLatin1Char('\"');
+                    v8::ThrowException(v8::Exception::Error(v8engine->toString(error)));
+                } else {
+                    apiprivate->setProperty(property, setvalp.data());
+                }
+            }
         }
     }
 
@@ -1,7 +1,6 @@
 import QtQuick 2.0
 
 import Qt.test 1.0 as QtTest                                    // module API installed into existing uri
-import Qt.test.scriptApi 1.0 as QtTestScriptApi                 // script module API installed into new uri
 import Qt.test.qobjectApi 1.0 as QtTestQObjectApi               // qobject module API installed into new uri
 import Qt.test.qobjectApi 1.3 as QtTestMinorVersionQObjectApi   // qobject module API installed into existing uri with new minor version
 import Qt.test.qobjectApi 2.0 as QtTestMajorVersionQObjectApi   // qobject module API installed into existing uri with new major version
@@ -9,7 +8,6 @@ import Qt.test.qobjectApiParented 1.0 as QtTestParentedQObjectApi // qobject (wi
 
 QtObject {
     property int existingUriTest: QtTest.qobjectTestProperty
-    property int scriptTest: QtTestScriptApi.scriptTestProperty
     property int qobjectTest: QtTestQObjectApi.qobjectTestProperty
     property int qobjectMethodTest: 2
     property int qobjectMinorVersionTest: QtTestMinorVersionQObjectApi.qobjectTestProperty
@@ -1,12 +1,10 @@
 import QtQuick 2.0
 
 import Qt.test 1.0 as QtTest                                      // module API installed into existing uri
-import Qt.test.scriptApi 1.0 as QtTestScriptApi                   // script module API installed into new uri
 import Qt.test.qobjectApiParented 1.0 as QtTestParentedQObjectApi // qobject (with parent) module API installed into a new uri
 
 QtObject {
     property int existingUriTest: QtTest.qobjectTestProperty
-    property int scriptTest: QtTestScriptApi.scriptTestProperty
     property int qobjectParentedTest: QtTestParentedQObjectApi.qobjectTestProperty
 }
 
@@ -1,6 +1,5 @@
 import QtQuick 2.0
-
-import Qt.test 1.0 as QtTest     // module API installed into existing uri
+import Qt.test 1.0 as QtTest     // qobject module API installed into existing uri
 
 QtObject {
     property int firstProperty: 1
diff --git a/tests/auto/declarative/qdeclarativeecmascript/data/moduleapi/scriptModuleApi.qml b/tests/auto/declarative/qdeclarativeecmascript/data/moduleapi/scriptModuleApi.qml
new file mode 100644 (file)
index 0000000..7c4e204
--- /dev/null
@@ -0,0 +1,6 @@
+import QtQuick 2.0
+import Qt.test.scriptApi 1.0 as QtTestScriptApi                 // script module API installed into new uri
+
+QtObject {
+    property int scriptTest: QtTestScriptApi.scriptTestProperty // script module api's only provide properties.
+}
diff --git a/tests/auto/declarative/qdeclarativeecmascript/data/moduleapi/scriptModuleApiCaching.qml b/tests/auto/declarative/qdeclarativeecmascript/data/moduleapi/scriptModuleApiCaching.qml
new file mode 100644 (file)
index 0000000..90974b5
--- /dev/null
@@ -0,0 +1,6 @@
+import QtQuick 2.0
+import Qt.test.scriptApi 1.0 as QtTestScriptApi                   // script module API installed into new uri
+
+QtObject {
+    property int scriptTest: QtTestScriptApi.scriptTestProperty
+}
diff --git a/tests/auto/declarative/qdeclarativeecmascript/data/moduleapi/scriptModuleApiWriting.qml b/tests/auto/declarative/qdeclarativeecmascript/data/moduleapi/scriptModuleApiWriting.qml
new file mode 100644 (file)
index 0000000..02461d5
--- /dev/null
@@ -0,0 +1,32 @@
+import QtQuick 2.0
+import Qt.test.scriptApi 1.0 as QtTestScriptApi
+import Qt.test.scriptApi 2.0 as QtTestScriptApi2
+
+QtObject {
+    property int firstProperty
+    property int readBack
+
+    property int secondProperty
+    property int unchanged
+
+    onFirstPropertyChanged: {
+        if (QtTestScriptApi.scriptTestProperty != firstProperty) {
+            QtTestScriptApi.scriptTestProperty = firstProperty;
+            readBack = QtTestScriptApi.scriptTestProperty;
+        }
+    }
+
+    onSecondPropertyChanged: {
+        if (QtTestScriptApi2.scriptTestProperty != secondProperty) {
+            QtTestScriptApi2.scriptTestProperty = secondProperty;
+            unchanged = QtTestScriptApi2.scriptTestProperty;
+        }
+    }
+
+    Component.onCompleted: {
+        firstProperty = QtTestScriptApi.scriptTestProperty;
+        readBack = QtTestScriptApi.scriptTestProperty;
+        secondProperty = QtTestScriptApi2.scriptTestProperty;
+        unchanged = QtTestScriptApi2.scriptTestProperty;
+    }
+}
index 160a572..05d5510 100644 (file)
@@ -111,6 +111,21 @@ static QJSValue script_api(QDeclarativeEngine *engine, QJSEngine *scriptEngine)
     return v;
 }
 
+static QJSValue readonly_script_api(QDeclarativeEngine *engine, QJSEngine *scriptEngine)
+{
+    Q_UNUSED(engine)
+
+    static int testProperty = 42;
+    QJSValue v = scriptEngine->newObject();
+    v.setProperty("scriptTestProperty", testProperty++);
+
+    // now freeze it so that it's read-only
+    QJSValue freezeFunction = scriptEngine->evaluate("(function(obj) { return Object.freeze(obj); })");
+    v = freezeFunction.call(QJSValue(), (QJSValueList() << v));
+
+    return v;
+}
+
 static QObject *qobject_api(QDeclarativeEngine *engine, QJSEngine *scriptEngine)
 {
     Q_UNUSED(engine)
@@ -166,6 +181,7 @@ void registerTypes()
     qmlRegisterModuleApi("Qt.test",1,0,script_api);             // register (script) module API for an existing uri which contains elements
     qmlRegisterModuleApi("Qt.test",1,0,qobject_api);            // register (qobject) for an existing uri for which another module API was previously regd.  Should replace!
     qmlRegisterModuleApi("Qt.test.scriptApi",1,0,script_api);   // register (script) module API for a uri which doesn't contain elements
+    qmlRegisterModuleApi("Qt.test.scriptApi",2,0,readonly_script_api); // register (script) module API for a uri which doesn't contain elements - will be made read-only
     qmlRegisterModuleApi("Qt.test.qobjectApi",1,0,qobject_api); // register (qobject) module API for a uri which doesn't contain elements
     qmlRegisterModuleApi("Qt.test.qobjectApi",1,3,qobject_api); // register (qobject) module API for a uri which doesn't contain elements, minor version set
     qmlRegisterModuleApi("Qt.test.qobjectApi",2,0,qobject_api); // register (qobject) module API for a uri which doesn't contain elements, major version set
index afb361e..d88fcd0 100644 (file)
@@ -945,7 +945,7 @@ public:
 
     ~testQObjectApi() {}
 
-    Q_INVOKABLE int qobjectTestMethod() { m_methodCallCount += 1; return m_methodCallCount; }
+    Q_INVOKABLE int qobjectTestMethod(int increment = 1) { m_methodCallCount += increment; return m_methodCallCount; }
 
     int qobjectTestProperty() const { return m_testProperty; }
     void setQObjectTestProperty(int tp) { m_testProperty = tp; emit qobjectTestPropertyChanged(tp); }
index 3efe189..111c04d 100644 (file)
@@ -145,6 +145,7 @@ private slots:
     void numberAssignment();
     void propertySplicing();
     void signalWithUnknownTypes();
+    void moduleApi_data();
     void moduleApi();
     void importScripts();
     void scarceResources();
@@ -2735,55 +2736,142 @@ void tst_qdeclarativeecmascript::signalWithUnknownTypes()
     delete object;
 }
 
+void tst_qdeclarativeecmascript::moduleApi_data()
+{
+    QTest::addColumn<QUrl>("testfile");
+    QTest::addColumn<QString>("errorMessage");
+    QTest::addColumn<QStringList>("warningMessages");
+    QTest::addColumn<QStringList>("readProperties");
+    QTest::addColumn<QVariantList>("readExpectedValues");
+    QTest::addColumn<QStringList>("writeProperties");
+    QTest::addColumn<QVariantList>("writeValues");
+    QTest::addColumn<QStringList>("readBackProperties");
+    QTest::addColumn<QVariantList>("readBackExpectedValues");
+
+    QTest::newRow("qobject, register + read + method")
+            << TEST_FILE("moduleapi/qobjectModuleApi.qml")
+            << QString()
+            << QStringList()
+            << (QStringList() << "existingUriTest" << "qobjectTest" << "qobjectMethodTest"
+                   << "qobjectMinorVersionTest" << "qobjectMajorVersionTest" << "qobjectParentedTest")
+            << (QVariantList() << 20 << 20 << 1 << 20 << 20 << 26)
+            << QStringList()
+            << QVariantList()
+            << QStringList()
+            << QVariantList();
+
+    QTest::newRow("script, register + read")
+            << TEST_FILE("moduleapi/scriptModuleApi.qml")
+            << QString()
+            << QStringList()
+            << (QStringList() << "scriptTest")
+            << (QVariantList() << 13)
+            << QStringList()
+            << QVariantList()
+            << QStringList()
+            << QVariantList();
+
+    QTest::newRow("qobject, caching + read")
+            << TEST_FILE("moduleapi/qobjectModuleApiCaching.qml")
+            << QString()
+            << QStringList()
+            << (QStringList() << "existingUriTest" << "qobjectParentedTest")
+            << (QVariantList() << 20 << 26) // 26, shouldn't have incremented to 27.
+            << QStringList()
+            << QVariantList()
+            << QStringList()
+            << QVariantList();
+
+    QTest::newRow("script, caching + read")
+            << TEST_FILE("moduleapi/scriptModuleApiCaching.qml")
+            << QString()
+            << QStringList()
+            << (QStringList() << "scriptTest")
+            << (QVariantList() << 13) // 13, shouldn't have incremented to 14.
+            << QStringList()
+            << QVariantList()
+            << QStringList()
+            << QVariantList();
+
+    QTest::newRow("qobject, writing + readonly constraints")
+            << TEST_FILE("moduleapi/qobjectModuleApiWriting.qml")
+            << QString()
+            << (QStringList() << QString(QLatin1String("file://") + TEST_FILE("moduleapi/qobjectModuleApiWriting.qml").toLocalFile() + QLatin1String(":14: Error: Cannot assign to read-only property \"qobjectTestProperty\"")))
+            << (QStringList() << "readOnlyProperty" << "writableProperty")
+            << (QVariantList() << 20 << 50)
+            << (QStringList() << "firstProperty" << "writableProperty")
+            << (QVariantList() << 30 << 30)
+            << (QStringList() << "readOnlyProperty" << "writableProperty")
+            << (QVariantList() << 20 << 30);
+
+    QTest::newRow("script, writing + readonly constraints")
+            << TEST_FILE("moduleapi/scriptModuleApiWriting.qml")
+            << QString()
+            << (QStringList() << QString(QLatin1String("file://") + TEST_FILE("moduleapi/scriptModuleApiWriting.qml").toLocalFile() + QLatin1String(":21: Error: Cannot assign to read-only property \"scriptTestProperty\"")))
+            << (QStringList() << "readBack" << "unchanged")
+            << (QVariantList() << 13 << 42)
+            << (QStringList() << "firstProperty" << "secondProperty")
+            << (QVariantList() << 30 << 30)
+            << (QStringList() << "readBack" << "unchanged")
+            << (QVariantList() << 30 << 42);
+
+    QTest::newRow("qobject, invalid major version fail")
+            << TEST_FILE("moduleapi/moduleApiMajorVersionFail.qml")
+            << QString("QDeclarativeComponent: Component is not ready")
+            << QStringList()
+            << QStringList()
+            << QVariantList()
+            << QStringList()
+            << QVariantList()
+            << QStringList()
+            << QVariantList();
+
+    QTest::newRow("qobject, invalid minor version fail")
+            << TEST_FILE("moduleapi/moduleApiMinorVersionFail.qml")
+            << QString("QDeclarativeComponent: Component is not ready")
+            << QStringList()
+            << QStringList()
+            << QVariantList()
+            << QStringList()
+            << QVariantList()
+            << QStringList()
+            << QVariantList();
+}
+
 void tst_qdeclarativeecmascript::moduleApi()
 {
-    QDeclarativeComponent component(&engine, TEST_FILE("moduleApi.qml"));
-    QObject *object = component.create();
-    QVERIFY(object != 0);
-    QCOMPARE(object->property("existingUriTest").toInt(), 20);
+    QFETCH(QUrl, testfile);
+    QFETCH(QString, errorMessage);
+    QFETCH(QStringList, warningMessages);
+    QFETCH(QStringList, readProperties);
+    QFETCH(QVariantList, readExpectedValues);
+    QFETCH(QStringList, writeProperties);
+    QFETCH(QVariantList, writeValues);
+    QFETCH(QStringList, readBackProperties);
+    QFETCH(QVariantList, readBackExpectedValues);
 
-    QEXPECT_FAIL("", "QTBUG-17318", Continue);
-    QCOMPARE(object->property("scriptTest").toInt(), 13);
-    QCOMPARE(object->property("qobjectTest").toInt(), 20);
-    QCOMPARE(object->property("qobjectMethodTest").toInt(), 1); // first call of method, so count = 1.
-    QCOMPARE(object->property("qobjectMinorVersionTest").toInt(), 20);
-    QCOMPARE(object->property("qobjectMajorVersionTest").toInt(), 20);
-    QCOMPARE(object->property("qobjectParentedTest").toInt(), 26);
-    delete object;
+    QDeclarativeComponent component(&engine, testfile);
 
-    // test that caching of module apis works correctly.
-    QDeclarativeComponent componentTwo(&engine, TEST_FILE("moduleApiCaching.qml"));
-    object = componentTwo.create();
-    QVERIFY(object != 0);
-    QCOMPARE(object->property("existingUriTest").toInt(), 20);
-    QEXPECT_FAIL("", "QTBUG-17318", Continue);
-    QCOMPARE(object->property("scriptTest").toInt(), 13);            // shouldn't have incremented.
-    QCOMPARE(object->property("qobjectParentedTest").toInt(), 26);   // shouldn't have incremented.
-    delete object;
+    if (!errorMessage.isEmpty())
+        QTest::ignoreMessage(QtWarningMsg, errorMessage.toAscii().constData());
 
-    // test that writing to a property of module apis works correctly.
-    QDeclarativeComponent componentThree(&engine, TEST_FILE("moduleApiWriting.qml"));
-    QString expectedWarning = QLatin1String("file://") + TEST_FILE("moduleApiWriting.qml").toLocalFile() + QLatin1String(":15: Error: Cannot assign to read-only property \"qobjectTestProperty\"");
-    QTest::ignoreMessage(QtWarningMsg, expectedWarning.toAscii().constData());
-    object = componentThree.create();
-    QVERIFY(object != 0);
-    QCOMPARE(object->property("readOnlyProperty").toInt(), 20);
-    QCOMPARE(object->property("writableProperty").toInt(), 50);
-    QVERIFY(object->setProperty("firstProperty", QVariant(30))); // shouldn't affect value of readOnlyProperty
-    QVERIFY(object->setProperty("writableProperty", QVariant(30))); // SHOULD affect value of writableProperty
-    QCOMPARE(object->property("readOnlyProperty").toInt(), 20);
-    QCOMPARE(object->property("writableProperty").toInt(), 30);
-    delete object;
+    if (warningMessages.size())
+        foreach (const QString &warning, warningMessages)
+            QTest::ignoreMessage(QtWarningMsg, warning.toAscii().constData());
 
-    QDeclarativeComponent failOne(&engine, TEST_FILE("moduleApiMajorVersionFail.qml"));
-    QTest::ignoreMessage(QtWarningMsg, "QDeclarativeComponent: Component is not ready");
-    object = failOne.create();
-    QVERIFY(object == 0); // should have failed: invalid major version
-
-    QDeclarativeComponent failTwo(&engine, TEST_FILE("moduleApiMinorVersionFail.qml"));
-    QTest::ignoreMessage(QtWarningMsg, "QDeclarativeComponent: Component is not ready");
-    object = failTwo.create();
-    QVERIFY(object == 0); // should have failed: invalid minor version
+    QObject *object = component.create();
+    if (!errorMessage.isEmpty()) {
+        QVERIFY(object == 0);
+    } else {
+        QVERIFY(object != 0);
+        for (int i = 0; i < readProperties.size(); ++i)
+            QCOMPARE(object->property(readProperties.at(i).toAscii().constData()), readExpectedValues.at(i));
+        for (int i = 0; i < writeProperties.size(); ++i)
+            QVERIFY(object->setProperty(writeProperties.at(i).toAscii().constData(), writeValues.at(i)));
+        for (int i = 0; i < readBackProperties.size(); ++i)
+            QCOMPARE(object->property(readBackProperties.at(i).toAscii().constData()), readBackExpectedValues.at(i));
+        delete object;
+    }
 }
 
 void tst_qdeclarativeecmascript::importScripts()