#include #include #include #include #include #include #include #include "testtypes.h" /* This test case covers QML language issues. This covers everything that does involve evaluating ECMAScript expressions and bindings. Evaluation of expressions and bindings is covered in qmlecmascript */ class tst_qmllanguage : public QObject { Q_OBJECT public: tst_qmllanguage() { QmlMetaType::registerCustomStringConverter(qMetaTypeId(), myCustomVariantTypeConverter); QFileInfo fileInfo(__FILE__); engine.addImportPath(fileInfo.absoluteDir().filePath(QLatin1String("data/lib"))); } private slots: void errors_data(); void errors(); void simpleObject(); void simpleContainer(); void interfaceProperty(); void interfaceQmlList(); void interfaceQList(); void assignObjectToSignal(); void assignObjectToVariant(); void assignLiteralSignalProperty(); void assignQmlComponent(); void assignBasicTypes(); void assignTypeExtremes(); void assignCompositeToType(); void customParserTypes(); void rootAsQmlComponent(); void inlineQmlComponents(); void idProperty(); void assignSignal(); void dynamicProperties(); void dynamicObjectProperties(); void dynamicSignalsAndSlots(); void simpleBindings(); void autoComponentCreation(); void propertyValueSource(); void attachedProperties(); void dynamicObjects(); void customVariantTypes(); void valueTypes(); void cppnamespace(); void aliasProperties(); void componentCompositeType(); void i18n(); void i18n_data(); void onCompleted(); void importsBuiltin_data(); void importsBuiltin(); void importsLocal_data(); void importsLocal(); void importsInstalled_data(); void importsInstalled(); void importsOrder_data(); void importsOrder(); // regression tests for crashes void crash1(); private: QmlEngine engine; void testType(const QString& qml, const QString& type); }; #define VERIFY_ERRORS(errorfile) \ if (!errorfile) { \ if (qgetenv("DEBUG") != "" && !component.errors().isEmpty()) \ qWarning() << "Unexpected Errors:" << component.errors(); \ QVERIFY(!component.isError()); \ QVERIFY(component.errors().isEmpty()); \ } else { \ QFile file(QLatin1String("data/") + QLatin1String(errorfile)); \ QVERIFY(file.open(QIODevice::ReadOnly)); \ QByteArray data = file.readAll(); \ QList expected = data.split('\n'); \ expected.removeAll(QByteArray("")); \ QList errors = component.errors(); \ QList actual; \ for (int ii = 0; ii < errors.count(); ++ii) { \ const QmlError &error = errors.at(ii); \ QByteArray errorStr = QByteArray::number(error.line()) + ":" + \ QByteArray::number(error.column()) + ":" + \ error.description().toUtf8(); \ actual << errorStr; \ } \ if (qgetenv("DEBUG") != "" && expected != actual) \ qWarning() << "Expected:" << expected << "Actual:" << actual; \ QCOMPARE(expected, actual); \ } inline QUrl TEST_FILE(const QString &filename) { QFileInfo fileInfo(__FILE__); return QUrl::fromLocalFile(fileInfo.absoluteDir().filePath(QLatin1String("data/") + filename)); } inline QUrl TEST_FILE(const char *filename) { return TEST_FILE(QLatin1String(filename)); } void tst_qmllanguage::errors_data() { QTest::addColumn("file"); QTest::addColumn("errorFile"); QTest::addColumn("create"); QTest::newRow("nonexistantProperty.1") << "nonexistantProperty.1.qml" << "nonexistantProperty.1.errors.txt" << false; QTest::newRow("nonexistantProperty.2") << "nonexistantProperty.2.qml" << "nonexistantProperty.2.errors.txt" << false; QTest::newRow("nonexistantProperty.3") << "nonexistantProperty.3.qml" << "nonexistantProperty.3.errors.txt" << false; QTest::newRow("nonexistantProperty.4") << "nonexistantProperty.4.qml" << "nonexistantProperty.4.errors.txt" << false; QTest::newRow("nonexistantProperty.5") << "nonexistantProperty.5.qml" << "nonexistantProperty.5.errors.txt" << false; QTest::newRow("nonexistantProperty.6") << "nonexistantProperty.6.qml" << "nonexistantProperty.6.errors.txt" << false; QTest::newRow("wrongType (string for int)") << "wrongType.1.qml" << "wrongType.1.errors.txt" << false; QTest::newRow("wrongType (int for bool)") << "wrongType.2.qml" << "wrongType.2.errors.txt" << false; QTest::newRow("wrongType (bad rect)") << "wrongType.3.qml" << "wrongType.3.errors.txt" << false; QTest::newRow("wrongType (invalid enum)") << "wrongType.4.qml" << "wrongType.4.errors.txt" << false; QTest::newRow("wrongType (int for uint)") << "wrongType.5.qml" << "wrongType.5.errors.txt" << false; QTest::newRow("wrongType (string for real)") << "wrongType.6.qml" << "wrongType.6.errors.txt" << false; QTest::newRow("wrongType (int for color)") << "wrongType.7.qml" << "wrongType.7.errors.txt" << false; QTest::newRow("wrongType (int for date)") << "wrongType.8.qml" << "wrongType.8.errors.txt" << false; QTest::newRow("wrongType (int for time)") << "wrongType.9.qml" << "wrongType.9.errors.txt" << false; QTest::newRow("wrongType (int for datetime)") << "wrongType.10.qml" << "wrongType.10.errors.txt" << false; QTest::newRow("wrongType (string for point)") << "wrongType.11.qml" << "wrongType.11.errors.txt" << false; QTest::newRow("wrongType (color for size)") << "wrongType.12.qml" << "wrongType.12.errors.txt" << false; QTest::newRow("wrongType (number string for int)") << "wrongType.13.qml" << "wrongType.13.errors.txt" << false; QTest::newRow("wrongType (int for string)") << "wrongType.14.qml" << "wrongType.14.errors.txt" << false; QTest::newRow("readOnly.1") << "readOnly.1.qml" << "readOnly.1.errors.txt" << false; QTest::newRow("readOnly.2") << "readOnly.2.qml" << "readOnly.2.errors.txt" << false; QTest::newRow("listAssignment.1") << "listAssignment.1.qml" << "listAssignment.1.errors.txt" << false; QTest::newRow("listAssignment.2") << "listAssignment.2.qml" << "listAssignment.2.errors.txt" << false; QTest::newRow("listAssignment.3") << "listAssignment.3.qml" << "listAssignment.3.errors.txt" << false; QTest::newRow("invalidID.1") << "invalidID.qml" << "invalidID.errors.txt" << false; QTest::newRow("invalidID.2") << "invalidID.2.qml" << "invalidID.2.errors.txt" << false; QTest::newRow("invalidID.3") << "invalidID.3.qml" << "invalidID.3.errors.txt" << false; QTest::newRow("invalidID.4") << "invalidID.4.qml" << "invalidID.4.errors.txt" << false; QTest::newRow("invalidID.5") << "invalidID.5.qml" << "invalidID.5.errors.txt" << false; QTest::newRow("invalidID.6") << "invalidID.6.qml" << "invalidID.6.errors.txt" << false; QTest::newRow("unsupportedProperty") << "unsupportedProperty.qml" << "unsupportedProperty.errors.txt" << false; QTest::newRow("nullDotProperty") << "nullDotProperty.qml" << "nullDotProperty.errors.txt" << true; QTest::newRow("fakeDotProperty") << "fakeDotProperty.qml" << "fakeDotProperty.errors.txt" << false; QTest::newRow("duplicateIDs") << "duplicateIDs.qml" << "duplicateIDs.errors.txt" << false; QTest::newRow("unregisteredObject") << "unregisteredObject.qml" << "unregisteredObject.errors.txt" << false; QTest::newRow("empty") << "empty.qml" << "empty.errors.txt" << false; QTest::newRow("missingObject") << "missingObject.qml" << "missingObject.errors.txt" << false; QTest::newRow("failingComponent") << "failingComponentTest.qml" << "failingComponent.errors.txt" << false; QTest::newRow("missingSignal") << "missingSignal.qml" << "missingSignal.errors.txt" << false; QTest::newRow("finalOverride") << "finalOverride.qml" << "finalOverride.errors.txt" << false; QTest::newRow("importNamespaceConflict") << "importNamespaceConflict.qml" << "importNamespaceConflict.errors.txt" << false; QTest::newRow("importVersionMissing (builtin)") << "importVersionMissingBuiltIn.qml" << "importVersionMissingBuiltIn.errors.txt" << false; QTest::newRow("importVersionMissing (installed)") << "importVersionMissingInstalled.qml" << "importVersionMissingInstalled.errors.txt" << false; QTest::newRow("customParserIdNotAllowed") << "customParserIdNotAllowed.qml" << "customParserIdNotAllowed.errors.txt" << false; } void tst_qmllanguage::errors() { QFETCH(QString, file); QFETCH(QString, errorFile); QFETCH(bool, create); QmlComponent component(&engine, TEST_FILE(file)); if(create) { QObject *object = component.create(); QVERIFY(object == 0); } VERIFY_ERRORS(errorFile.toLatin1().constData()); } void tst_qmllanguage::simpleObject() { QmlComponent component(&engine, TEST_FILE("simpleObject.qml")); VERIFY_ERRORS(0); QObject *object = component.create(); QVERIFY(object != 0); } void tst_qmllanguage::simpleContainer() { QmlComponent component(&engine, TEST_FILE("simpleContainer.qml")); VERIFY_ERRORS(0); MyContainer *container= qobject_cast(component.create()); QVERIFY(container != 0); QCOMPARE(container->children()->count(),2); } void tst_qmllanguage::interfaceProperty() { QmlComponent component(&engine, TEST_FILE("interfaceProperty.qml")); VERIFY_ERRORS(0); MyQmlObject *object = qobject_cast(component.create()); QVERIFY(object != 0); QVERIFY(object->interface()); QVERIFY(object->interface()->id == 913); } void tst_qmllanguage::interfaceQmlList() { QmlComponent component(&engine, TEST_FILE("interfaceQmlList.qml")); VERIFY_ERRORS(0); MyContainer *container= qobject_cast(component.create()); QVERIFY(container != 0); QVERIFY(container->qmllistAccessor().count() == 2); for(int ii = 0; ii < 2; ++ii) QVERIFY(container->qmllistAccessor().at(ii)->id == 913); } void tst_qmllanguage::interfaceQList() { QmlComponent component(&engine, TEST_FILE("interfaceQList.qml")); VERIFY_ERRORS(0); MyContainer *container= qobject_cast(component.create()); QVERIFY(container != 0); QVERIFY(container->qlistInterfaces()->count() == 2); for(int ii = 0; ii < 2; ++ii) QVERIFY(container->qlistInterfaces()->at(ii)->id == 913); } void tst_qmllanguage::assignObjectToSignal() { QmlComponent component(&engine, TEST_FILE("assignObjectToSignal.qml")); VERIFY_ERRORS(0); MyQmlObject *object = qobject_cast(component.create()); QVERIFY(object != 0); QTest::ignoreMessage(QtWarningMsg, "MyQmlObject::basicSlot"); emit object->basicSignal(); } void tst_qmllanguage::assignObjectToVariant() { QmlComponent component(&engine, TEST_FILE("assignObjectToVariant.qml")); VERIFY_ERRORS(0); QObject *object = component.create(); QVERIFY(object != 0); QVariant v = object->property("a"); QVERIFY(v.userType() == qMetaTypeId()); } void tst_qmllanguage::assignLiteralSignalProperty() { QmlComponent component(&engine, TEST_FILE("assignLiteralSignalProperty.qml")); VERIFY_ERRORS(0); MyQmlObject *object = qobject_cast(component.create()); QVERIFY(object != 0); QCOMPARE(object->onLiteralSignal(), 10); } // Test is an external component can be loaded and assigned (to a qlist) void tst_qmllanguage::assignQmlComponent() { QmlComponent component(&engine, TEST_FILE("assignQmlComponent.qml")); VERIFY_ERRORS(0); MyContainer *object = qobject_cast(component.create()); QVERIFY(object != 0); QVERIFY(object->children()->count() == 1); QObject *child = object->children()->at(0); QCOMPARE(child->property("x"), QVariant(10)); QCOMPARE(child->property("y"), QVariant(11)); } // Test literal assignment to all the basic types void tst_qmllanguage::assignBasicTypes() { QmlComponent component(&engine, TEST_FILE("assignBasicTypes.qml")); VERIFY_ERRORS(0); MyTypeObject *object = qobject_cast(component.create()); QVERIFY(object != 0); QCOMPARE(object->flagProperty(), MyTypeObject::FlagVal1 | MyTypeObject::FlagVal3); QCOMPARE(object->enumProperty(), MyTypeObject::EnumVal2); QCOMPARE(object->stringProperty(), QString("Hello World!")); QCOMPARE(object->uintProperty(), uint(10)); QCOMPARE(object->intProperty(), -19); QCOMPARE((float)object->realProperty(), float(23.2)); QCOMPARE((float)object->doubleProperty(), float(-19.7)); QCOMPARE(object->colorProperty(), QColor("red")); QCOMPARE(object->dateProperty(), QDate(1982, 11, 25)); QCOMPARE(object->timeProperty(), QTime(11, 11, 32)); QCOMPARE(object->dateTimeProperty(), QDateTime(QDate(2009, 5, 12), QTime(13, 22, 1))); QCOMPARE(object->pointProperty(), QPoint(99,13)); QCOMPARE(object->pointFProperty(), QPointF((float)-10.1, (float)12.3)); QCOMPARE(object->sizeProperty(), QSize(99, 13)); QCOMPARE(object->sizeFProperty(), QSizeF((float)0.1, (float)0.2)); QCOMPARE(object->rectProperty(), QRect(9, 7, 100, 200)); QCOMPARE(object->rectFProperty(), QRectF((float)1000.1, (float)-10.9, (float)400, (float)90.99)); QCOMPARE(object->boolProperty(), true); QCOMPARE(object->variantProperty(), QVariant("Hello World!")); QVERIFY(object->objectProperty() != 0); MyTypeObject *child = qobject_cast(object->objectProperty()); QVERIFY(child != 0); QCOMPARE(child->intProperty(), 8); } // Test edge case type assignments void tst_qmllanguage::assignTypeExtremes() { QmlComponent component(&engine, TEST_FILE("assignTypeExtremes.qml")); VERIFY_ERRORS(0); MyTypeObject *object = qobject_cast(component.create()); QVERIFY(object != 0); QCOMPARE(object->uintProperty(), 0xEE6B2800); QCOMPARE(object->intProperty(), -0x77359400); } // Test that a composite type can assign to a property of its base type void tst_qmllanguage::assignCompositeToType() { QmlComponent component(&engine, TEST_FILE("assignCompositeToType.qml")); VERIFY_ERRORS(0); QObject *object = component.create(); QVERIFY(object != 0); } // Tests that custom parser types can be instantiated void tst_qmllanguage::customParserTypes() { QmlComponent component(&engine, TEST_FILE("customParserTypes.qml")); VERIFY_ERRORS(0); QObject *object = component.create(); QVERIFY(object != 0); QVERIFY(object->property("count") == QVariant(2)); } // Tests that the root item can be a custom component void tst_qmllanguage::rootAsQmlComponent() { QmlComponent component(&engine, TEST_FILE("rootAsQmlComponent.qml")); VERIFY_ERRORS(0); MyContainer *object = qobject_cast(component.create()); QVERIFY(object != 0); QCOMPARE(object->property("x"), QVariant(11)); QCOMPARE(object->children()->count(), 2); } // Tests that components can be specified inline void tst_qmllanguage::inlineQmlComponents() { QmlComponent component(&engine, TEST_FILE("inlineQmlComponents.qml")); VERIFY_ERRORS(0); MyContainer *object = qobject_cast(component.create()); QVERIFY(object != 0); QCOMPARE(object->children()->count(), 1); QmlComponent *comp = qobject_cast(object->children()->at(0)); QVERIFY(comp != 0); MyQmlObject *compObject = qobject_cast(comp->create()); QVERIFY(compObject != 0); QCOMPARE(compObject->value(), 11); } // Tests that types that have an id property have it set void tst_qmllanguage::idProperty() { QmlComponent component(&engine, TEST_FILE("idProperty.qml")); VERIFY_ERRORS(0); MyContainer *object = qobject_cast(component.create()); QVERIFY(object != 0); QCOMPARE(object->children()->count(), 1); MyTypeObject *child = qobject_cast(object->children()->at(0)); QVERIFY(child != 0); QCOMPARE(child->id(), QString("MyObjectId")); QCOMPARE(object->property("object"), QVariant::fromValue((QObject *)child)); } // Tests that signals can be assigned to void tst_qmllanguage::assignSignal() { QmlComponent component(&engine, TEST_FILE("assignSignal.qml")); VERIFY_ERRORS(0); MyQmlObject *object = qobject_cast(component.create()); QVERIFY(object != 0); QTest::ignoreMessage(QtWarningMsg, "MyQmlObject::basicSlot"); emit object->basicSignal(); QTest::ignoreMessage(QtWarningMsg, "MyQmlObject::basicSlot(9)"); emit object->basicParameterizedSignal(9); } // Tests the creation and assignment of dynamic properties void tst_qmllanguage::dynamicProperties() { QmlComponent component(&engine, TEST_FILE("dynamicProperties.qml")); VERIFY_ERRORS(0); QObject *object = component.create(); QVERIFY(object != 0); QCOMPARE(object->property("intProperty"), QVariant(10)); QCOMPARE(object->property("boolProperty"), QVariant(false)); QCOMPARE(object->property("doubleProperty"), QVariant(-10.1)); QCOMPARE(object->property("realProperty"), QVariant((qreal)-19.9)); QCOMPARE(object->property("stringProperty"), QVariant("Hello World!")); QCOMPARE(object->property("colorProperty"), QVariant(QColor("red"))); QCOMPARE(object->property("dateProperty"), QVariant(QDate(1945, 9, 2))); QCOMPARE(object->property("varProperty"), QVariant("Hello World!")); QCOMPARE(object->property("variantProperty"), QVariant(12)); } // Tests the creation and assignment of dynamic object properties // ### Not complete void tst_qmllanguage::dynamicObjectProperties() { QmlComponent component(&engine, TEST_FILE("dynamicObjectProperties.qml")); VERIFY_ERRORS(0); QObject *object = component.create(); QVERIFY(object != 0); QVERIFY(object->property("objectProperty") == qVariantFromValue((QObject*)0)); QVERIFY(object->property("objectProperty2") != qVariantFromValue((QObject*)0)); } // Tests the declaration of dynamic signals and slots void tst_qmllanguage::dynamicSignalsAndSlots() { QmlComponent component(&engine, TEST_FILE("dynamicSignalsAndSlots.qml")); VERIFY_ERRORS(0); QObject *object = component.create(); QVERIFY(object != 0); QVERIFY(object->metaObject()->indexOfMethod("signal1()") != -1); QVERIFY(object->metaObject()->indexOfMethod("signal2()") != -1); QVERIFY(object->metaObject()->indexOfMethod("slot1()") != -1); QVERIFY(object->metaObject()->indexOfMethod("slot2()") != -1); } void tst_qmllanguage::simpleBindings() { QmlComponent component(&engine, TEST_FILE("simpleBindings.qml")); VERIFY_ERRORS(0); QObject *object = component.create(); QVERIFY(object != 0); QCOMPARE(object->property("value1"), QVariant(10)); QCOMPARE(object->property("value2"), QVariant(10)); QCOMPARE(object->property("value3"), QVariant(21)); QCOMPARE(object->property("value4"), QVariant(10)); QCOMPARE(object->property("objectProperty"), QVariant::fromValue(object)); } void tst_qmllanguage::autoComponentCreation() { QmlComponent component(&engine, TEST_FILE("autoComponentCreation.qml")); VERIFY_ERRORS(0); MyTypeObject *object = qobject_cast(component.create()); QVERIFY(object != 0); QVERIFY(object->componentProperty() != 0); MyTypeObject *child = qobject_cast(object->componentProperty()->create()); QVERIFY(child != 0); QCOMPARE(child->realProperty(), qreal(9)); } void tst_qmllanguage::propertyValueSource() { QmlComponent component(&engine, TEST_FILE("propertyValueSource.qml")); VERIFY_ERRORS(0); MyTypeObject *object = qobject_cast(component.create()); QVERIFY(object != 0); QList valueSources; QObjectList allChildren = object->findChildren(); foreach (QObject *child, allChildren) { QmlType *type = QmlMetaType::qmlType(child->metaObject()); if (type && type->propertyValueSourceCast() != -1) valueSources.append(child); } QCOMPARE(valueSources.count(), 1); MyPropertyValueSource *valueSource = qobject_cast(valueSources.at(0)); QVERIFY(valueSource != 0); QCOMPARE(valueSource->prop.object(), object); QCOMPARE(valueSource->prop.name(), QString(QLatin1String("intProperty"))); } void tst_qmllanguage::attachedProperties() { QmlComponent component(&engine, TEST_FILE("attachedProperties.qml")); VERIFY_ERRORS(0); QObject *object = component.create(); QVERIFY(object != 0); QObject *attached = qmlAttachedPropertiesObject(object); QVERIFY(attached != 0); QCOMPARE(attached->property("value"), QVariant(10)); } // Tests non-static object properties void tst_qmllanguage::dynamicObjects() { QmlComponent component(&engine, TEST_FILE("dynamicObject.1.qml")); VERIFY_ERRORS(0); QObject *object = component.create(); QVERIFY(object != 0); } // Tests the registration of custom variant string converters void tst_qmllanguage::customVariantTypes() { QmlComponent component(&engine, TEST_FILE("customVariantTypes.qml")); VERIFY_ERRORS(0); MyQmlObject *object = qobject_cast(component.create()); QVERIFY(object != 0); QCOMPARE(object->customType().a, 10); } void tst_qmllanguage::valueTypes() { QmlComponent component(&engine, TEST_FILE("valueTypes.qml")); VERIFY_ERRORS(0); MyTypeObject *object = qobject_cast(component.create()); QVERIFY(object != 0); QCOMPARE(object->rectProperty(), QRect(10, 11, 12, 13)); QCOMPARE(object->rectProperty2(), QRect(10, 11, 12, 13)); QCOMPARE(object->intProperty(), 10); object->doAction(); QCOMPARE(object->rectProperty(), QRect(12, 11, 14, 13)); QCOMPARE(object->rectProperty2(), QRect(12, 11, 14, 13)); QCOMPARE(object->intProperty(), 12); QmlMetaProperty p = QmlMetaProperty::createProperty(object, "rectProperty.x"); QCOMPARE(p.read(), QVariant(12)); p.write(13); QCOMPARE(p.read(), QVariant(13)); quint32 r = p.save(); QmlMetaProperty p2; p2.restore(r, object); QCOMPARE(p2.read(), QVariant(13)); } void tst_qmllanguage::cppnamespace() { QmlComponent component(&engine, TEST_FILE("cppnamespace.qml")); VERIFY_ERRORS(0); QObject *object = component.create(); QVERIFY(object != 0); delete object; } void tst_qmllanguage::aliasProperties() { // Simple "int" alias { QmlComponent component(&engine, TEST_FILE("alias.1.qml")); VERIFY_ERRORS(0); QObject *object = component.create(); QVERIFY(object != 0); // Read through alias QCOMPARE(object->property("valueAlias").toInt(), 10); object->setProperty("value", QVariant(13)); QCOMPARE(object->property("valueAlias").toInt(), 13); // Write throught alias object->setProperty("valueAlias", QVariant(19)); QCOMPARE(object->property("valueAlias").toInt(), 19); QCOMPARE(object->property("value").toInt(), 19); delete object; } // Complex object alias { QmlComponent component(&engine, TEST_FILE("alias.2.qml")); VERIFY_ERRORS(0); QObject *object = component.create(); QVERIFY(object != 0); // Read through alias MyQmlObject *v = qvariant_cast(object->property("aliasObject")); QVERIFY(v != 0); QCOMPARE(v->value(), 10); // Write through alias MyQmlObject *v2 = new MyQmlObject(); v2->setParent(object); object->setProperty("aliasObject", qVariantFromValue(v2)); MyQmlObject *v3 = qvariant_cast(object->property("aliasObject")); QVERIFY(v3 != 0); QCOMPARE(v3, v2); delete object; } // Nested aliases { QmlComponent component(&engine, TEST_FILE("alias.3.qml")); VERIFY_ERRORS(0); QObject *object = component.create(); QVERIFY(object != 0); QCOMPARE(object->property("value").toInt(), 1892); QCOMPARE(object->property("value2").toInt(), 1892); object->setProperty("value", QVariant(1313)); QCOMPARE(object->property("value").toInt(), 1313); QCOMPARE(object->property("value2").toInt(), 1313); object->setProperty("value2", QVariant(8080)); QCOMPARE(object->property("value").toInt(), 8080); QCOMPARE(object->property("value2").toInt(), 8080); delete object; } // Enum aliases { QmlComponent component(&engine, TEST_FILE("alias.4.qml")); VERIFY_ERRORS(0); QObject *object = component.create(); QVERIFY(object != 0); QCOMPARE(object->property("enumAlias").toInt(), 1); delete object; } // Id aliases { QmlComponent component(&engine, TEST_FILE("alias.5.qml")); VERIFY_ERRORS(0); QObject *object = component.create(); QVERIFY(object != 0); QVariant v = object->property("otherAlias"); QCOMPARE(v.userType(), qMetaTypeId()); MyQmlObject *o = qvariant_cast(v); QCOMPARE(o->value(), 10); delete o; v = object->property("otherAlias"); QCOMPARE(v.userType(), qMetaTypeId()); o = qvariant_cast(v); QVERIFY(o == 0); delete object; } } // Test that the root element in a composite type can be a Component void tst_qmllanguage::componentCompositeType() { QmlComponent component(&engine, TEST_FILE("componentCompositeType.qml")); VERIFY_ERRORS(0); QObject *object = component.create(); QVERIFY(object != 0); } class TestType : public QObject { Q_OBJECT public: TestType(QObject *p=0) : QObject(p) {} }; class TestType2 : public QObject { Q_OBJECT public: TestType2(QObject *p=0) : QObject(p) {} }; void tst_qmllanguage::i18n_data() { QTest::addColumn("file"); QTest::addColumn("stringProperty"); QTest::newRow("i18nStrings") << "i18nStrings.qml" << QString::fromUtf8("Test áâãäå (5 accented 'a' letters)"); QTest::newRow("i18nDeclaredPropertyNames") << "i18nDeclaredPropertyNames.qml" << QString::fromUtf8("Test áâãäå: 10"); QTest::newRow("i18nDeclaredPropertyUse") << "i18nDeclaredPropertyUse.qml" << QString::fromUtf8("Test áâãäå: 15"); QTest::newRow("i18nScript") << "i18nScript.qml" << QString::fromUtf8("Test áâãäå: 20"); QTest::newRow("i18nType") << "i18nType.qml" << QString::fromUtf8("Test áâãäå: 30"); } void tst_qmllanguage::i18n() { QFETCH(QString, file); QFETCH(QString, stringProperty); QmlComponent component(&engine, TEST_FILE(file)); VERIFY_ERRORS(0); MyTypeObject *object = qobject_cast(component.create()); QVERIFY(object != 0); QCOMPARE(object->stringProperty(), stringProperty); delete object; } // Check that the Component::onCompleted attached property works void tst_qmllanguage::onCompleted() { QmlComponent component(&engine, TEST_FILE("onCompleted.qml")); VERIFY_ERRORS(0); QTest::ignoreMessage(QtDebugMsg, "Completed 6 10"); QTest::ignoreMessage(QtDebugMsg, "Completed 6 10"); QTest::ignoreMessage(QtDebugMsg, "Completed 10 11"); QObject *object = component.create(); QVERIFY(object != 0); } // Check that first child of qml is of given type. Empty type insists on error. void tst_qmllanguage::testType(const QString& qml, const QString& type) { QmlComponent component(&engine, qml.toUtf8(), TEST_FILE("empty.qml")); // just a file for relative local imports if (type.isEmpty()) { QVERIFY(component.isError()); } else { VERIFY_ERRORS(0); QObject *object = component.create(); QVERIFY(object != 0); QCOMPARE(QString(object->metaObject()->className()), type); } } QML_DECLARE_TYPE(TestType) QML_DECLARE_TYPE(TestType2) QML_DEFINE_TYPE(com.nokia.Test, 1, 0, 3, Test, TestType) QML_DEFINE_TYPE(com.nokia.Test, 1, 5, 7, Test, TestType) QML_DEFINE_TYPE(com.nokia.Test, 1, 8, 9, Test, TestType2) QML_DEFINE_TYPE(com.nokia.Test, 1, 12, 13, Test, TestType2) QML_DEFINE_TYPE(com.nokia.Test, 1, 9, 11, OldTest, TestType) void tst_qmllanguage::importsBuiltin_data() { QTest::addColumn("qml"); QTest::addColumn("type"); // import built-ins QTest::newRow("missing import") << "Test {}" << ""; QTest::newRow("not in version 0.0") << "import com.nokia.Test 0.0\n" "Test {}" << ""; QTest::newRow("in version 1.0") << "import com.nokia.Test 1.0\n" "Test {}" << "TestType"; QTest::newRow("qualified wrong") << "import com.nokia.Test 1.0 as T\n" "Test {}" << ""; QTest::newRow("qualified right") << "import com.nokia.Test 1.0 as T\n" "T.Test {}" << "TestType"; QTest::newRow("qualified right but not in version 0.0") << "import com.nokia.Test 0.0 as T\n" "T.Test {}" << ""; QTest::newRow("in version 1.1") << "import com.nokia.Test 1.1\n" "Test {}" << "TestType"; QTest::newRow("in version 1.3") << "import com.nokia.Test 1.3\n" "Test {}" << "TestType"; QTest::newRow("not in version 1.4") << "import com.nokia.Test 1.4\n" "Test {}" << ""; QTest::newRow("in version 1.5") << "import com.nokia.Test 1.5\n" "Test {}" << "TestType"; QTest::newRow("changed in version 1.8") << "import com.nokia.Test 1.8\n" "Test {}" << "TestType2"; QTest::newRow("not in version 1.10") << "import com.nokia.Test 1.10\n" "Test {}" << ""; QTest::newRow("back in version 1.12") << "import com.nokia.Test 1.12\n" "Test {}" << "TestType2"; QTest::newRow("old in version 1.9") << "import com.nokia.Test 1.9\n" "OldTest {}" << "TestType"; QTest::newRow("old in version 1.11") << "import com.nokia.Test 1.11\n" "OldTest {}" << "TestType"; QTest::newRow("no old in version 1.12") << "import com.nokia.Test 1.12\n" "OldTest {}" << ""; QTest::newRow("multiversion 1") << "import com.nokia.Test 1.11\n" "import com.nokia.Test 1.12\n" "Test {}" << "TestType2"; QTest::newRow("multiversion 2") << "import com.nokia.Test 1.11\n" "import com.nokia.Test 1.12\n" "OldTest {}" << "TestType"; QTest::newRow("qualified multiversion 3") << "import com.nokia.Test 1.0 as T0\n" "import com.nokia.Test 1.8 as T8\n" "T0.Test {}" << "TestType"; QTest::newRow("qualified multiversion 4") << "import com.nokia.Test 1.0 as T0\n" "import com.nokia.Test 1.8 as T8\n" "T8.Test {}" << "TestType2"; QTest::newRow("qualified multiversion 5") << "import com.nokia.Test 1.0 as T0\n" "import com.nokia.Test 1.10 as T10\n" "T10.Test {}" << ""; } void tst_qmllanguage::importsBuiltin() { QFETCH(QString, qml); QFETCH(QString, type); testType(qml,type); } void tst_qmllanguage::importsLocal_data() { QTest::addColumn("qml"); QTest::addColumn("type"); // import locals QTest::newRow("local import") << "import \"subdir\"\n" "Test {}" << "QFxRect"; QTest::newRow("local import as") << "import \"subdir\" as T\n" "T.Test {}" << "QFxRect"; QTest::newRow("wrong local import as") << "import \"subdir\" as T\n" "Test {}" << ""; QTest::newRow("library precedence over local import") << "import \"subdir\"\n" "import com.nokia.Test 1.0\n" "Test {}" << "TestType"; } void tst_qmllanguage::importsLocal() { QFETCH(QString, qml); QFETCH(QString, type); testType(qml,type); } void tst_qmllanguage::importsInstalled_data() { QTest::addColumn("qml"); QTest::addColumn("type"); // import installed QTest::newRow("installed import") << "import com.nokia.installedtest 1.0\n" "InstalledTest {}" << "QFxRect"; QTest::newRow("installed import") << "import com.nokia.installedtest 1.4\n" "InstalledTest {}" << "QFxText"; } void tst_qmllanguage::importsInstalled() { QFETCH(QString, qml); QFETCH(QString, type); testType(qml,type); } void tst_qmllanguage::importsOrder_data() { QTest::addColumn("qml"); QTest::addColumn("type"); QTest::newRow("installed import overrides 1") << "import com.nokia.installedtest 1.0\n" "import com.nokia.installedtest 1.4\n" "InstalledTest {}" << "QFxText"; QTest::newRow("installed import overrides 2") << "import com.nokia.installedtest 1.4\n" "import com.nokia.installedtest 1.0\n" "InstalledTest {}" << "QFxRect"; QTest::newRow("installed import re-overrides 1") << "import com.nokia.installedtest 1.4\n" "import com.nokia.installedtest 1.0\n" "import com.nokia.installedtest 1.4\n" "InstalledTest {}" << "QFxText"; QTest::newRow("installed import re-overrides 2") << "import com.nokia.installedtest 1.4\n" "import com.nokia.installedtest 1.0\n" "import com.nokia.installedtest 1.4\n" "import com.nokia.installedtest 1.0\n" "InstalledTest {}" << "QFxRect"; QTest::newRow("installed import versus builtin 1") << "import com.nokia.installedtest 1.5\n" "import Qt 4.6\n" "Rectangle {}" << "QFxRect"; QTest::newRow("installed import versus builtin 2") << "import Qt 4.6\n" "import com.nokia.installedtest 1.5\n" "Rectangle {}" << "QFxText"; QTest::newRow("namespaces cannot be overridden by types 1") << "import Qt 4.6 as Rectangle\n" "import com.nokia.installedtest 1.5\n" "Rectangle {}" << ""; QTest::newRow("namespaces cannot be overridden by types 2") << "import Qt 4.6 as Rectangle\n" "import com.nokia.installedtest 1.5\n" "Rectangle.Image {}" << "QFxImage"; } void tst_qmllanguage::importsOrder() { QFETCH(QString, qml); QFETCH(QString, type); testType(qml,type); } void tst_qmllanguage::crash1() { QmlComponent component(&engine, "Component {}"); } QTEST_MAIN(tst_qmllanguage) #include "tst_qmllanguage.moc"