Add support for more sequence types
[profile/ivi/qtdeclarative.git] / tests / auto / declarative / qdeclarativeecmascript / tst_qdeclarativeecmascript.cpp
index c92dc80..ee228ec 100644 (file)
@@ -170,6 +170,13 @@ private slots:
     void handleReferenceManagement();
     void stringArg();
     void readonlyDeclaration();
+    void sequenceConversionRead();
+    void sequenceConversionWrite();
+    void sequenceConversionArray();
+    void sequenceConversionThreads();
+    void sequenceConversionBindings();
+    void sequenceConversionCopy();
+
     void bug1();
     void bug2();
     void dynamicCreationCrash();
@@ -4048,6 +4055,232 @@ 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());
+
+    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;
+}
+
 // Test that assigning a null object works 
 // Regressed with: df1788b4dbbb2826ae63f26bdf166342595343f4
 void tst_qdeclarativeecmascript::nullObjectBinding()