aboutsummaryrefslogtreecommitdiffstats
path: root/tests/auto/qml/qqmllanguage/tst_qqmllanguage.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'tests/auto/qml/qqmllanguage/tst_qqmllanguage.cpp')
-rw-r--r--tests/auto/qml/qqmllanguage/tst_qqmllanguage.cpp285
1 files changed, 271 insertions, 14 deletions
diff --git a/tests/auto/qml/qqmllanguage/tst_qqmllanguage.cpp b/tests/auto/qml/qqmllanguage/tst_qqmllanguage.cpp
index 4d2f773dbf..c6076410b2 100644
--- a/tests/auto/qml/qqmllanguage/tst_qqmllanguage.cpp
+++ b/tests/auto/qml/qqmllanguage/tst_qqmllanguage.cpp
@@ -123,6 +123,7 @@ private slots:
void dynamicProperties();
void dynamicPropertiesNested();
void listProperties();
+ void listPropertiesInheritanceNoCrash();
void badListItemType();
void dynamicObjectProperties();
void dynamicSignalsAndSlots();
@@ -133,6 +134,8 @@ private slots:
void autoComponentCreationInGroupProperty();
void propertyValueSource();
void requiredProperty();
+ void requiredPropertyFromCpp_data();
+ void requiredPropertyFromCpp();
void attachedProperties();
void dynamicObjects();
void customVariantTypes();
@@ -321,6 +324,10 @@ private slots:
void listContainingDeletedObject();
void overrideSingleton();
+ void revisionedPropertyOfAttachedObjectProperty();
+
+ void arrayToContainer();
+ void qualifiedScopeInCustomParser();
private:
QQmlEngine engine;
@@ -1486,6 +1493,16 @@ void tst_qqmllanguage::listProperties()
QCOMPARE(object->property("test").toInt(), 2);
}
+// Tests that initializing list properties of a base class does not crash
+// (QTBUG-82171)
+void tst_qqmllanguage::listPropertiesInheritanceNoCrash()
+{
+ QQmlEngine engine;
+ QQmlComponent component(&engine, testFileUrl("listPropertiesChild.qml"));
+ QScopedPointer<QObject> object(component.create()); // should not crash
+ QVERIFY(object != nullptr);
+}
+
void tst_qqmllanguage::badListItemType()
{
QQmlComponent component(&engine, testFileUrl("badListItemType.qml"));
@@ -1674,8 +1691,103 @@ void tst_qqmllanguage::requiredProperty()
QVERIFY(!component.errors().empty());
}
{
+ QQmlComponent component(&engine, testFileUrl("requiredProperties.4.qml"));
+ QScopedPointer<QObject> object(component.create());
+ QVERIFY(!component.errors().empty());
+ QVERIFY(component.errorString().contains("Required property objectName was not initialized"));
+ }
+ {
QQmlComponent component(&engine, testFileUrl("requiredProperties.3.qml"));
+ QScopedPointer<QObject> object(component.create());
+ QVERIFY(!component.errors().empty());
+ QVERIFY(component.errorString().contains("Required property i was not initialized"));
+ }
+ {
+ QQmlComponent component(&engine, testFileUrl("requiredProperties.5.qml"));
+ QScopedPointer<QObject> object(component.create());
+ QVERIFY(!component.errors().empty());
+ QVERIFY(component.errorString().contains("Required property i was not initialized"));
+ }
+ {
+ QQmlComponent component(&engine, testFileUrl("requiredProperties.6.qml"));
+ VERIFY_ERRORS(0);
+ QScopedPointer<QObject> object(component.create());
+ QVERIFY(object);
+ }
+ {
+ QQmlComponent component(&engine, testFileUrl("requiredProperties.7.qml"));
+ QScopedPointer<QObject> object(component.create());
QVERIFY(!component.errors().empty());
+ QVERIFY(component.errorString().contains("Property blub was marked as required but does not exist"));
+ }
+}
+
+class MyClassWithRequiredProperty : public QObject
+{
+public:
+ Q_OBJECT
+ Q_PROPERTY(int test MEMBER m_test REQUIRED NOTIFY testChanged)
+ Q_SIGNAL void testChanged();
+private:
+ int m_test;
+};
+
+class ChildClassWithoutOwnRequired : public MyClassWithRequiredProperty
+{
+public:
+ Q_OBJECT
+ Q_PROPERTY(int test2 MEMBER m_test2 NOTIFY test2Changed)
+ Q_SIGNAL void test2Changed();
+private:
+ int m_test2;
+};
+
+class ChildClassWithOwnRequired : public MyClassWithRequiredProperty
+{
+public:
+ Q_OBJECT
+ Q_PROPERTY(int test2 MEMBER m_test2 REQUIRED NOTIFY test2Changed)
+ Q_SIGNAL void test2Changed();
+private:
+ int m_test2;
+};
+
+void tst_qqmllanguage::requiredPropertyFromCpp_data()
+{
+ qmlRegisterType<MyClassWithRequiredProperty>("example.org", 1, 0, "MyClass");
+ qmlRegisterType<ChildClassWithoutOwnRequired>("example.org", 1, 0, "Child");
+ qmlRegisterType<ChildClassWithOwnRequired>("example.org", 1, 0, "Child2");
+
+
+ QTest::addColumn<QUrl>("setFile");
+ QTest::addColumn<QUrl>("notSetFile");
+ QTest::addColumn<QString>("errorMessage");
+ QTest::addColumn<int>("expectedValue");
+
+ QTest::addRow("direct") << testFileUrl("cppRequiredProperty.qml") << testFileUrl("cppRequiredPropertyNotSet.qml") << QString(":4 Required property test was not initialized\n") << 42;
+ QTest::addRow("in parent") << testFileUrl("cppRequiredPropertyInParent.qml") << testFileUrl("cppRequiredPropertyInParentNotSet.qml") << QString(":4 Required property test was not initialized\n") << 42;
+ QTest::addRow("in child and parent") << testFileUrl("cppRequiredPropertyInChildAndParent.qml") << testFileUrl("cppRequiredPropertyInChildAndParentNotSet.qml") << QString(":4 Required property test2 was not initialized\n") << 18;
+}
+
+void tst_qqmllanguage::requiredPropertyFromCpp()
+{
+ QQmlEngine engine;
+ QFETCH(QUrl, setFile);
+ QFETCH(QUrl, notSetFile);
+ QFETCH(QString, errorMessage);
+ QFETCH(int, expectedValue);
+ {
+ QQmlComponent comp(&engine, notSetFile);
+ QScopedPointer<QObject> o { comp.create() };
+ QVERIFY(o.isNull());
+ QVERIFY(comp.isError());
+ QCOMPARE(comp.errorString(), notSetFile.toString() + errorMessage);
+ }
+ {
+ QQmlComponent comp(&engine, setFile);
+ QScopedPointer<QObject> o { comp.create() };
+ QVERIFY(!o.isNull());
+ QCOMPARE(o->property("test").toInt(), expectedValue);
}
}
@@ -1747,21 +1859,30 @@ void tst_qqmllanguage::valueTypes()
void tst_qqmllanguage::cppnamespace()
{
- {
- QQmlComponent component(&engine, testFileUrl("cppnamespace.qml"));
+ QScopedPointer<QObject> object;
+
+ auto create = [&](const char *file) {
+ QQmlComponent component(&engine, testFileUrl(file));
VERIFY_ERRORS(0);
- QScopedPointer<QObject> object(component.create());
+ object.reset(component.create());
QVERIFY(object != nullptr);
+ };
- QCOMPARE(object->property("intProperty").toInt(), (int)MyNamespace::MyOtherNSEnum::OtherKey2);
- }
+ auto createAndCheck = [&](const char *file) {
+ create(file);
+ return !QTest::currentTestFailed();
+ };
- {
- QQmlComponent component(&engine, testFileUrl("cppnamespace.2.qml"));
- VERIFY_ERRORS(0);
- QScopedPointer<QObject> object(component.create());
- QVERIFY(object != nullptr);
- }
+ QVERIFY(createAndCheck("cppnamespace.qml"));
+ QCOMPARE(object->property("intProperty").toInt(),
+ (int)MyNamespace::MyOtherNSEnum::OtherKey2);
+
+ QVERIFY(createAndCheck("cppstaticnamespace.qml"));
+ QCOMPARE(object->property("intProperty").toInt(),
+ (int)MyStaticNamespace::MyOtherNSEnum::OtherKey2);
+
+ QVERIFY(createAndCheck("cppnamespace.2.qml"));
+ QVERIFY(createAndCheck("cppstaticnamespace.2.qml"));
}
void tst_qqmllanguage::aliasProperties()
@@ -5318,7 +5439,7 @@ void tst_qqmllanguage::selfReference()
const QMetaObject *metaObject = o->metaObject();
QMetaProperty selfProperty = metaObject->property(metaObject->indexOfProperty("self"));
- QCOMPARE(selfProperty.userType(), compilationUnit->metaTypeId);
+ QCOMPARE(selfProperty.userType(), compilationUnit->metaTypeId.id());
QByteArray typeName = selfProperty.typeName();
QVERIFY(typeName.endsWith('*'));
@@ -5327,7 +5448,7 @@ void tst_qqmllanguage::selfReference()
QMetaMethod selfFunction = metaObject->method(metaObject->indexOfMethod("returnSelf()"));
QVERIFY(selfFunction.isValid());
- QCOMPARE(selfFunction.returnType(), compilationUnit->metaTypeId);
+ QCOMPARE(selfFunction.returnType(), compilationUnit->metaTypeId.id());
QMetaMethod selfSignal;
@@ -5341,7 +5462,7 @@ void tst_qqmllanguage::selfReference()
QVERIFY(selfSignal.isValid());
QCOMPARE(selfSignal.parameterCount(), 1);
- QCOMPARE(selfSignal.parameterType(0), compilationUnit->metaTypeId);
+ QCOMPARE(selfSignal.parameterType(0), compilationUnit->metaTypeId.id());
}
void tst_qqmllanguage::selfReferencingSingleton()
@@ -5418,6 +5539,85 @@ void tst_qqmllanguage::overrideSingleton()
check("uncreatable", "UncreatableSingleton");
}
+class AttachedObject;
+class InnerObject : public QObject
+{
+ Q_OBJECT
+ Q_PROPERTY(bool revisionedProperty READ revisionedProperty WRITE setRevisionedProperty
+ NOTIFY revisionedPropertyChanged REVISION 2)
+
+public:
+ InnerObject(QObject *parent = nullptr) : QObject(parent) {}
+
+ bool revisionedProperty() const { return m_revisionedProperty; }
+ void setRevisionedProperty(bool revisionedProperty)
+ {
+ if (revisionedProperty != m_revisionedProperty) {
+ m_revisionedProperty = revisionedProperty;
+ emit revisionedPropertyChanged();
+ }
+ }
+
+ static AttachedObject *qmlAttachedProperties(QObject *object);
+
+signals:
+ Q_REVISION(2) void revisionedPropertyChanged();
+
+private:
+ bool m_revisionedProperty = false;
+};
+
+class AttachedObject : public QObject
+{
+ Q_OBJECT
+ Q_PROPERTY(InnerObject *attached READ attached CONSTANT)
+
+public:
+ explicit AttachedObject(QObject *parent = nullptr) :
+ QObject(parent),
+ m_attached(new InnerObject(this))
+ {}
+
+ InnerObject *attached() const { return m_attached; }
+
+private:
+ InnerObject *m_attached;
+};
+
+class OuterObject : public QObject
+{
+ Q_OBJECT
+public:
+ explicit OuterObject(QObject *parent = nullptr) : QObject(parent) {}
+};
+
+AttachedObject *InnerObject::qmlAttachedProperties(QObject *object)
+{
+ return new AttachedObject(object);
+}
+
+QML_DECLARE_TYPE(InnerObject)
+QML_DECLARE_TYPEINFO(InnerObject, QML_HAS_ATTACHED_PROPERTIES)
+
+void tst_qqmllanguage::revisionedPropertyOfAttachedObjectProperty()
+{
+ qmlRegisterAnonymousType<AttachedObject>("foo", 2);
+ qmlRegisterType<InnerObject>("foo", 2, 0, "InnerObject");
+ qmlRegisterType<InnerObject, 2>("foo", 2, 2, "InnerObject");
+ qmlRegisterType<OuterObject>("foo", 2, 2, "OuterObject");
+
+ QQmlEngine engine;
+ QQmlComponent component(&engine);
+ component.setData("import foo 2.2\n"
+ "OuterObject {\n"
+ " InnerObject.attached.revisionedProperty: true\n"
+ "}", QUrl());
+
+ QVERIFY(component.isReady());
+ QScopedPointer<QObject> obj(component.create());
+ QVERIFY(!obj.isNull());
+}
+
void tst_qqmllanguage::inlineComponent()
{
QFETCH(QUrl, componentUrl);
@@ -5450,6 +5650,9 @@ void tst_qqmllanguage::inlineComponent_data()
QTest::newRow("Non-toplevel IC is found") << testFileUrl("inlineComponentUser5.qml") << QColorConstants::Svg::red << 24;
QTest::newRow("Resolved in correct order") << testFileUrl("inlineComponentOrder.qml") << QColorConstants::Blue << 200;
+
+ QTest::newRow("ID resolves correctly") << testFileUrl("inlineComponentWithId.qml") << QColorConstants::Svg::red << 42;
+ QTest::newRow("Alias resolves correctly") << testFileUrl("inlineComponentWithAlias.qml") << QColorConstants::Svg::lime << 42;
}
void tst_qqmllanguage::inlineComponentReferenceCycle_data()
@@ -5540,6 +5743,60 @@ void tst_qqmllanguage::nonExistingInlineComponent()
QCOMPARE(error.column(), column);
}
+class TestItem : public QObject
+{
+ Q_OBJECT
+ Q_PROPERTY( QVector<QPointF> positions MEMBER m_points )
+
+public:
+ TestItem() = default;
+ QVector< QPointF > m_points;
+};
+
+
+Q_DECLARE_METATYPE(QVector<QPointF>);
+void tst_qqmllanguage::arrayToContainer()
+{
+ QQmlEngine engine;
+ qmlRegisterType<TestItem>("qt.test", 1, 0, "TestItem");
+ QVector<QPointF> points { QPointF (2.0, 3.0) };
+ engine.rootContext()->setContextProperty("test", QVariant::fromValue(points));
+ QQmlComponent component(&engine, testFileUrl("arrayToContainer.qml"));
+ VERIFY_ERRORS(0);
+ QScopedPointer<TestItem> root(qobject_cast<TestItem *>(component.createWithInitialProperties( {{"vector", QVariant::fromValue(points)}} )));
+ QVERIFY(root);
+ QCOMPARE(root->m_points.at(0), QPointF (2.0, 3.0) );
+}
+
+class EnumTester : public QObject
+{
+ Q_OBJECT
+public:
+ enum Types
+ {
+ FIRST = 0,
+ SECOND,
+ THIRD
+ };
+ Q_ENUM(Types)
+};
+
+void tst_qqmllanguage::qualifiedScopeInCustomParser()
+{
+ qmlRegisterUncreatableType<EnumTester>("scoped.custom.test", 1, 0, "EnumTester",
+ "Object only creatable in C++");
+ QQmlEngine engine;
+ QQmlComponent component(&engine);
+ component.setData("import QtQml.Models 2.12\n"
+ "import scoped.custom.test 1.0 as BACKEND\n"
+ "ListModel {\n"
+ " ListElement { text: \"a\"; type: BACKEND.EnumTester.FIRST }\n"
+ "}\n", QUrl());
+ QVERIFY(component.isReady());
+ QScopedPointer<QObject> obj(component.create());
+ QVERIFY(!obj.isNull());
+}
+
QTEST_MAIN(tst_qqmllanguage)
#include "tst_qqmllanguage.moc"