aboutsummaryrefslogtreecommitdiffstats
path: root/tests/auto/qml/qqmllanguage
diff options
context:
space:
mode:
Diffstat (limited to 'tests/auto/qml/qqmllanguage')
-rw-r--r--tests/auto/qml/qqmllanguage/CMakeLists.txt7
-rw-r--r--tests/auto/qml/qqmllanguage/data/Broken.qml5
-rw-r--r--tests/auto/qml/qqmllanguage/data/ComponentType.qml8
-rw-r--r--tests/auto/qml/qqmllanguage/data/GroupFailureInner.qml2
-rw-r--r--tests/auto/qml/qqmllanguage/data/GroupFailureOuter.qml5
-rw-r--r--tests/auto/qml/qqmllanguage/data/MyRectangle.qml10
-rw-r--r--tests/auto/qml/qqmllanguage/data/SignalInlineComponentArg.qml21
-rw-r--r--tests/auto/qml/qqmllanguage/data/alias.15.qml21
-rw-r--r--tests/auto/qml/qqmllanguage/data/alias.15a.qml12
-rw-r--r--tests/auto/qml/qqmllanguage/data/alias.19.qml11
-rw-r--r--tests/auto/qml/qqmllanguage/data/ambiguousBinding/TestCase.qml6
-rw-r--r--tests/auto/qml/qqmllanguage/data/ambiguousBinding/ambiguousContainingType.qml3
-rw-r--r--tests/auto/qml/qqmllanguage/data/asBroken.qml6
-rw-r--r--tests/auto/qml/qqmllanguage/data/badGroupedProperty.qml10
-rw-r--r--tests/auto/qml/qqmllanguage/data/bindingAliasToComponentUrl.qml10
-rw-r--r--tests/auto/qml/qqmllanguage/data/bindingAliasToComponentUrl2.qml11
-rw-r--r--tests/auto/qml/qqmllanguage/data/componentMix.qml18
-rw-r--r--tests/auto/qml/qqmllanguage/data/foreignExtended.qml7
-rw-r--r--tests/auto/qml/qqmllanguage/data/fuzzed.1.errors.txt3
-rw-r--r--tests/auto/qml/qqmllanguage/data/groupFailure.qml5
-rw-r--r--tests/auto/qml/qqmllanguage/data/jittedAsCast.qml15
-rw-r--r--tests/auto/qml/qqmllanguage/data/sameNameAliasProperty.qml7
-rw-r--r--tests/auto/qml/qqmllanguage/data/sameNamePropertyAlias.qml7
-rw-r--r--tests/auto/qml/qqmllanguage/data/signalInlineComponentArg1.qml30
-rw-r--r--tests/auto/qml/qqmllanguage/data/thisInArrow.qml39
-rw-r--r--tests/auto/qml/qqmllanguage/data/uncreatableAttached.qml8
-rw-r--r--tests/auto/qml/qqmllanguage/data/variantListConversion.qml3
-rw-r--r--tests/auto/qml/qqmllanguage/testtypes.cpp2
-rw-r--r--tests/auto/qml/qqmllanguage/testtypes.h95
-rw-r--r--tests/auto/qml/qqmllanguage/tst_qqmllanguage.cpp305
30 files changed, 676 insertions, 16 deletions
diff --git a/tests/auto/qml/qqmllanguage/CMakeLists.txt b/tests/auto/qml/qqmllanguage/CMakeLists.txt
index e7fa05d23e..08d747b818 100644
--- a/tests/auto/qml/qqmllanguage/CMakeLists.txt
+++ b/tests/auto/qml/qqmllanguage/CMakeLists.txt
@@ -12,18 +12,15 @@ list(APPEND test_data ${test_data_glob})
qt_internal_add_test(tst_qqmllanguage
SOURCES
- ../../shared/testhttpserver.cpp ../../shared/testhttpserver.h
- ../../shared/util.cpp ../../shared/util.h
testtypes.cpp testtypes.h
tst_qqmllanguage.cpp
- INCLUDE_DIRECTORIES
- ../../shared
PUBLIC_LIBRARIES
Qt::CorePrivate
Qt::Gui
Qt::GuiPrivate
Qt::Network
Qt::QmlPrivate
+ Qt::QuickTestUtilsPrivate
TESTDATA ${test_data}
)
@@ -67,4 +64,4 @@ set_target_properties(tst_qqmllanguage PROPERTIES
QT_QML_MODULE_URI StaticTest
)
-qt6_qml_type_registration(tst_qqmllanguage)
+_qt_internal_qml_type_registration(tst_qqmllanguage)
diff --git a/tests/auto/qml/qqmllanguage/data/Broken.qml b/tests/auto/qml/qqmllanguage/data/Broken.qml
new file mode 100644
index 0000000000..e1b61f31f4
--- /dev/null
+++ b/tests/auto/qml/qqmllanguage/data/Broken.qml
@@ -0,0 +1,5 @@
+import QtQml
+
+QtObject {
+ notThere: 5
+}
diff --git a/tests/auto/qml/qqmllanguage/data/ComponentType.qml b/tests/auto/qml/qqmllanguage/data/ComponentType.qml
new file mode 100644
index 0000000000..e8addde1c4
--- /dev/null
+++ b/tests/auto/qml/qqmllanguage/data/ComponentType.qml
@@ -0,0 +1,8 @@
+import QtQml
+
+Component {
+ id: componentRoot
+ QtObject {
+ objectName: "enclosed"
+ }
+}
diff --git a/tests/auto/qml/qqmllanguage/data/GroupFailureInner.qml b/tests/auto/qml/qqmllanguage/data/GroupFailureInner.qml
new file mode 100644
index 0000000000..7972cc9683
--- /dev/null
+++ b/tests/auto/qml/qqmllanguage/data/GroupFailureInner.qml
@@ -0,0 +1,2 @@
+import QtQml
+QtObject { property url u }
diff --git a/tests/auto/qml/qqmllanguage/data/GroupFailureOuter.qml b/tests/auto/qml/qqmllanguage/data/GroupFailureOuter.qml
new file mode 100644
index 0000000000..2a34a29789
--- /dev/null
+++ b/tests/auto/qml/qqmllanguage/data/GroupFailureOuter.qml
@@ -0,0 +1,5 @@
+import QtQml
+
+QtObject {
+ property GroupFailureInner b
+}
diff --git a/tests/auto/qml/qqmllanguage/data/MyRectangle.qml b/tests/auto/qml/qqmllanguage/data/MyRectangle.qml
new file mode 100644
index 0000000000..4d5e7c6c8d
--- /dev/null
+++ b/tests/auto/qml/qqmllanguage/data/MyRectangle.qml
@@ -0,0 +1,10 @@
+import QtQuick
+
+Item {
+ property alias rectangle1AnchorsleftMargin: rectangle1.anchors.leftMargin
+
+ Rectangle {
+ id: rectangle1
+ anchors.leftMargin: 250
+ }
+}
diff --git a/tests/auto/qml/qqmllanguage/data/SignalInlineComponentArg.qml b/tests/auto/qml/qqmllanguage/data/SignalInlineComponentArg.qml
new file mode 100644
index 0000000000..0424ac1534
--- /dev/null
+++ b/tests/auto/qml/qqmllanguage/data/SignalInlineComponentArg.qml
@@ -0,0 +1,21 @@
+import QtQuick
+
+Item {
+ component Abc: Item {
+ property string success
+ }
+
+ signal canYouFeelIt(arg1: Abc)
+ property Abc someAbc: Abc {
+ success: "Signal was called"
+ }
+ property string success: "Signal not called yet"
+
+ Component.onCompleted: {
+ canYouFeelIt(someAbc);
+ }
+
+ onCanYouFeelIt: (arg) => {
+ success = arg.success
+ }
+}
diff --git a/tests/auto/qml/qqmllanguage/data/alias.15.qml b/tests/auto/qml/qqmllanguage/data/alias.15.qml
index 5f3de9c83e..7e362d8823 100644
--- a/tests/auto/qml/qqmllanguage/data/alias.15.qml
+++ b/tests/auto/qml/qqmllanguage/data/alias.15.qml
@@ -9,4 +9,25 @@ Item {
Item {
id: symbol
}
+
+ Rectangle {
+ id: txtElevationValue
+
+ property Rectangle background: Rectangle { }
+
+ state: "ValidatorInvalid"
+
+ states: [
+ State {
+ name: "ValidatorInvalid"
+ PropertyChanges {
+ target: txtElevationValue
+ background.border.color: "red" // this line caused the segfault in qtbug107795
+ }
+ },
+ State {
+ name: "ValidatorAcceptable"
+ }
+ ]
+ }
}
diff --git a/tests/auto/qml/qqmllanguage/data/alias.15a.qml b/tests/auto/qml/qqmllanguage/data/alias.15a.qml
new file mode 100644
index 0000000000..ba8097c997
--- /dev/null
+++ b/tests/auto/qml/qqmllanguage/data/alias.15a.qml
@@ -0,0 +1,12 @@
+import QtQuick 2.15
+
+Item {
+ id: root
+
+ property alias symbol: symbol
+ symbol.layer.enabled: true
+
+ Item {
+ id: symbol
+ }
+}
diff --git a/tests/auto/qml/qqmllanguage/data/alias.19.qml b/tests/auto/qml/qqmllanguage/data/alias.19.qml
new file mode 100644
index 0000000000..a96c0c694d
--- /dev/null
+++ b/tests/auto/qml/qqmllanguage/data/alias.19.qml
@@ -0,0 +1,11 @@
+import QtQuick
+
+Item {
+ id: myThing
+ width: 1920
+
+ MyRectangle {
+ rectangle1AnchorsleftMargin: myThing.width / 2
+ Component.onCompleted: myThing.height = rectangle1AnchorsleftMargin
+ }
+}
diff --git a/tests/auto/qml/qqmllanguage/data/ambiguousBinding/TestCase.qml b/tests/auto/qml/qqmllanguage/data/ambiguousBinding/TestCase.qml
new file mode 100644
index 0000000000..c76d2b679e
--- /dev/null
+++ b/tests/auto/qml/qqmllanguage/data/ambiguousBinding/TestCase.qml
@@ -0,0 +1,6 @@
+import QtQml 2.15
+import QtTest 1.0
+
+QtObject {
+ component Comp: QtObject {}
+}
diff --git a/tests/auto/qml/qqmllanguage/data/ambiguousBinding/ambiguousContainingType.qml b/tests/auto/qml/qqmllanguage/data/ambiguousBinding/ambiguousContainingType.qml
new file mode 100644
index 0000000000..765dc91fe1
--- /dev/null
+++ b/tests/auto/qml/qqmllanguage/data/ambiguousBinding/ambiguousContainingType.qml
@@ -0,0 +1,3 @@
+import QtQml 2.15
+
+TestCase {}
diff --git a/tests/auto/qml/qqmllanguage/data/asBroken.qml b/tests/auto/qml/qqmllanguage/data/asBroken.qml
new file mode 100644
index 0000000000..381a012df6
--- /dev/null
+++ b/tests/auto/qml/qqmllanguage/data/asBroken.qml
@@ -0,0 +1,6 @@
+import QtQml
+
+QtObject {
+ id: self
+ property var selfAsBroken: self as Broken
+}
diff --git a/tests/auto/qml/qqmllanguage/data/badGroupedProperty.qml b/tests/auto/qml/qqmllanguage/data/badGroupedProperty.qml
new file mode 100644
index 0000000000..1b8ba61725
--- /dev/null
+++ b/tests/auto/qml/qqmllanguage/data/badGroupedProperty.qml
@@ -0,0 +1,10 @@
+import QtQml
+
+QtObject {
+ id: testItem
+ property rect rect
+ onComplete {
+ rect.x: 2
+ rect.width: 22
+ }
+}
diff --git a/tests/auto/qml/qqmllanguage/data/bindingAliasToComponentUrl.qml b/tests/auto/qml/qqmllanguage/data/bindingAliasToComponentUrl.qml
new file mode 100644
index 0000000000..44fbd03354
--- /dev/null
+++ b/tests/auto/qml/qqmllanguage/data/bindingAliasToComponentUrl.qml
@@ -0,0 +1,10 @@
+import QtQuick
+Item {
+ id: root
+ Component {
+ id: accessibleNormal
+ Item {}
+ }
+ property alias accessibleNormalUrl: accessibleNormal.url
+ property url urlClone: root.accessibleNormalUrl // crashes qml utility
+}
diff --git a/tests/auto/qml/qqmllanguage/data/bindingAliasToComponentUrl2.qml b/tests/auto/qml/qqmllanguage/data/bindingAliasToComponentUrl2.qml
new file mode 100644
index 0000000000..cfdec5e39b
--- /dev/null
+++ b/tests/auto/qml/qqmllanguage/data/bindingAliasToComponentUrl2.qml
@@ -0,0 +1,11 @@
+import QtQuick
+Item {
+ id: root
+ Component {
+ id: accessibleNormal
+ ComponentType {
+ id: inaccessibleNormal
+ }
+ }
+ property alias accessibleNormalProgress: accessibleNormal.progress
+}
diff --git a/tests/auto/qml/qqmllanguage/data/componentMix.qml b/tests/auto/qml/qqmllanguage/data/componentMix.qml
new file mode 100644
index 0000000000..0edc997484
--- /dev/null
+++ b/tests/auto/qml/qqmllanguage/data/componentMix.qml
@@ -0,0 +1,18 @@
+import QtQml
+
+QtObject {
+ component View: QtObject {
+ default property Component delegate
+ }
+
+ component Things : QtObject {
+ property QtObject view: View { delegate: QtObject {} }
+ }
+
+ component Delegated : View {
+ delegate: QtObject {}
+ }
+
+ property Things things: Things {}
+ property Delegated delegated: Delegated {}
+}
diff --git a/tests/auto/qml/qqmllanguage/data/foreignExtended.qml b/tests/auto/qml/qqmllanguage/data/foreignExtended.qml
index 4863e0d567..b01af6d229 100644
--- a/tests/auto/qml/qqmllanguage/data/foreignExtended.qml
+++ b/tests/auto/qml/qqmllanguage/data/foreignExtended.qml
@@ -5,12 +5,17 @@ QtObject {
property Foreign foreign: Foreign {
objectName: "foreign"
}
- property Extended extended: Extended {}
+ property Extended extended: Extended {
+ objectName: "extended"
+ property int changeCount: 0
+ onExtensionChanged: ++changeCount
+ }
property ForeignExtended foreignExtended: ForeignExtended {
objectName: "foreignExtended"
}
property int extendedBase: extended.base
+ property int extendedChangeCount: extended.changeCount
property int extendedInvokable: extended.invokable()
property int extendedSlot: extended.slot()
diff --git a/tests/auto/qml/qqmllanguage/data/fuzzed.1.errors.txt b/tests/auto/qml/qqmllanguage/data/fuzzed.1.errors.txt
index e399799fe9..758be7feae 100644
--- a/tests/auto/qml/qqmllanguage/data/fuzzed.1.errors.txt
+++ b/tests/auto/qml/qqmllanguage/data/fuzzed.1.errors.txt
@@ -1,2 +1 @@
-2:8:Cannot assign to non-existent property "_G"
-
+2:11:Non-existent attached object
diff --git a/tests/auto/qml/qqmllanguage/data/groupFailure.qml b/tests/auto/qml/qqmllanguage/data/groupFailure.qml
new file mode 100644
index 0000000000..e8f8999482
--- /dev/null
+++ b/tests/auto/qml/qqmllanguage/data/groupFailure.qml
@@ -0,0 +1,5 @@
+import QtQml
+
+GroupFailureOuter {
+ b.u: null
+}
diff --git a/tests/auto/qml/qqmllanguage/data/jittedAsCast.qml b/tests/auto/qml/qqmllanguage/data/jittedAsCast.qml
new file mode 100644
index 0000000000..e1798a5d35
--- /dev/null
+++ b/tests/auto/qml/qqmllanguage/data/jittedAsCast.qml
@@ -0,0 +1,15 @@
+import QtQml
+
+QtObject {
+ property QtObject obj: Timer {
+ interval: 1
+ running: true
+ repeat: true
+ onTriggered: {
+ if (++interval === 10)
+ running = false
+ }
+ }
+ property bool running: (obj as Timer).running
+ property int interval: (obj as Timer).interval
+}
diff --git a/tests/auto/qml/qqmllanguage/data/sameNameAliasProperty.qml b/tests/auto/qml/qqmllanguage/data/sameNameAliasProperty.qml
new file mode 100644
index 0000000000..288fd618a6
--- /dev/null
+++ b/tests/auto/qml/qqmllanguage/data/sameNameAliasProperty.qml
@@ -0,0 +1,7 @@
+import QtQml 2.15
+
+QtObject {
+ id: root
+ property int a
+ property alias a: root.a
+}
diff --git a/tests/auto/qml/qqmllanguage/data/sameNamePropertyAlias.qml b/tests/auto/qml/qqmllanguage/data/sameNamePropertyAlias.qml
new file mode 100644
index 0000000000..bb26ba4396
--- /dev/null
+++ b/tests/auto/qml/qqmllanguage/data/sameNamePropertyAlias.qml
@@ -0,0 +1,7 @@
+import QtQml 2.15
+
+QtObject {
+ id: root
+ property alias a: root.a
+ property int a
+}
diff --git a/tests/auto/qml/qqmllanguage/data/signalInlineComponentArg1.qml b/tests/auto/qml/qqmllanguage/data/signalInlineComponentArg1.qml
new file mode 100644
index 0000000000..e20710edd9
--- /dev/null
+++ b/tests/auto/qml/qqmllanguage/data/signalInlineComponentArg1.qml
@@ -0,0 +1,30 @@
+import QtQuick
+
+// this file performs two tests: first, using a signal with a inline component from another file
+// and second, calling the signal from another file using an inline component from another file
+
+Item {
+ signal canYouFeelIt(arg1:SignalInlineComponentArg.Abc)
+
+ property SignalInlineComponentArg.Abc someAbc: SignalInlineComponentArg.Abc {
+ success: "Own signal was called with component from another file"
+ }
+
+ property SignalInlineComponentArg fromAnotherFile: SignalInlineComponentArg {}
+
+ // success of own signal call with parameter from another file
+ property string successFromOwnSignal: "Signal not called yet"
+ // makes it easier to test
+ property string successFromSignalFromFile: fromAnotherFile.success
+
+ Component.onCompleted: {
+ canYouFeelIt(someAbc);
+ fromAnotherFile.someAbc.success = "Signal was called from another file"
+ fromAnotherFile.canYouFeelIt(fromAnotherFile.someAbc)
+ }
+
+ onCanYouFeelIt: (arg) => {
+ successFromOwnSignal = arg.success
+ }
+}
+
diff --git a/tests/auto/qml/qqmllanguage/data/thisInArrow.qml b/tests/auto/qml/qqmllanguage/data/thisInArrow.qml
new file mode 100644
index 0000000000..7dd19782e6
--- /dev/null
+++ b/tests/auto/qml/qqmllanguage/data/thisInArrow.qml
@@ -0,0 +1,39 @@
+import QtQml
+
+QtObject {
+ id: root
+
+ property int width: 43
+ Component.onCompleted: () => { console.log(this.width); }
+
+ property var arrow: () => { return this; }
+ property var func: function() { return this; }
+
+ property QtObject child: QtObject {
+ property var aa;
+ property var ff;
+
+ Component.onCompleted: {
+ root.arrowResult = root.arrow();
+ root.funcResult = root.func();
+
+ var a = root.arrow;
+ root.aResult = a();
+ var f = root.func;
+ root.fResult = f();
+
+ aa = a;
+ root.aaResult = aa();
+
+ ff = f;
+ root.ffResult = ff();
+ }
+ }
+
+ property var arrowResult
+ property var funcResult
+ property var aResult
+ property var fResult
+ property var aaResult
+ property var ffResult
+}
diff --git a/tests/auto/qml/qqmllanguage/data/uncreatableAttached.qml b/tests/auto/qml/qqmllanguage/data/uncreatableAttached.qml
new file mode 100644
index 0000000000..4a861ea075
--- /dev/null
+++ b/tests/auto/qml/qqmllanguage/data/uncreatableAttached.qml
@@ -0,0 +1,8 @@
+import QtQml
+import ABC
+
+QtObject {
+ id: testItem
+ objectName: "00000000000000000000"
+ ItemAttached.attachedName: "111111111"
+}
diff --git a/tests/auto/qml/qqmllanguage/data/variantListConversion.qml b/tests/auto/qml/qqmllanguage/data/variantListConversion.qml
index 334bf17393..19760a64ee 100644
--- a/tests/auto/qml/qqmllanguage/data/variantListConversion.qml
+++ b/tests/auto/qml/qqmllanguage/data/variantListConversion.qml
@@ -1,7 +1,8 @@
import Test
+import QtQml
Foo {
a.a: 12
b.a: 13
- fooProperty: [a, b]
+ fooProperty: [a, b, Component]
}
diff --git a/tests/auto/qml/qqmllanguage/testtypes.cpp b/tests/auto/qml/qqmllanguage/testtypes.cpp
index fd541fd36a..92e24bc332 100644
--- a/tests/auto/qml/qqmllanguage/testtypes.cpp
+++ b/tests/auto/qml/qqmllanguage/testtypes.cpp
@@ -177,7 +177,7 @@ void EnumSupportingCustomParser::verifyBindings(const QQmlRefPointer<QV4::Execut
return;
}
- if (binding->type != QV4::CompiledData::Binding::Type_Script) {
+ if (binding->type() != QV4::CompiledData::Binding::Type_Script) {
error(binding, QStringLiteral("Custom parser invoked with the wrong property value. Expected script that evaluates to enum"));
return;
}
diff --git a/tests/auto/qml/qqmllanguage/testtypes.h b/tests/auto/qml/qqmllanguage/testtypes.h
index 2ffc324cae..e43424c9ca 100644
--- a/tests/auto/qml/qqmllanguage/testtypes.h
+++ b/tests/auto/qml/qqmllanguage/testtypes.h
@@ -1464,13 +1464,23 @@ public:
class Extension : public QObject
{
Q_OBJECT
- Q_PROPERTY(int extension READ extension CONSTANT)
+ Q_PROPERTY(int extension READ extension WRITE setExtension NOTIFY extensionChanged FINAL)
public:
Extension(QObject *parent = nullptr) : QObject(parent) {}
- int extension() const { return 42; }
+ int extension() const { return ext; }
+ void setExtension(int e) {
+ if (e != ext) {
+ ext = e;
+ emit extensionChanged();
+ }
+ }
Q_INVOKABLE int invokable() { return 123; }
+Q_SIGNALS:
+ void extensionChanged();
public slots:
int slot() { return 456; }
+private:
+ int ext = 42;
};
class Extended : public QObject
@@ -1566,6 +1576,33 @@ public:
int own() const { return 93; }
};
+class ExtendedNamespaceByObject : public QObject
+{
+ Q_OBJECT
+ QML_ELEMENT
+ QML_EXTENDED_NAMESPACE(Extension)
+
+ Q_PROPERTY(QString dummy READ dummy CONSTANT)
+ Q_PROPERTY(int extension READ extension WRITE setExtension NOTIFY extensionChanged)
+
+ int m_ext = 0;
+
+public:
+ ExtendedNamespaceByObject(QObject *parent = nullptr) : QObject(parent) {}
+ QString dummy() const { return QStringLiteral("dummy"); }
+ int extension() const { return m_ext; }
+ void setExtension(int e)
+ {
+ if (e != m_ext) {
+ m_ext = e;
+ Q_EMIT extensionChanged();
+ }
+ }
+
+Q_SIGNALS:
+ void extensionChanged();
+};
+
class FactorySingleton : public QObject
{
Q_OBJECT
@@ -1773,6 +1810,60 @@ private:
QVariantList mFooProperty;
};
+class ItemAttached : public QObject
+{
+ Q_OBJECT
+ Q_PROPERTY(QString attachedName READ attachedName WRITE setAttachedName NOTIFY attachedNameChanged)
+ QML_ELEMENT
+ QML_ATTACHED(ItemAttached)
+public:
+ ItemAttached(QObject *parent = nullptr) : QObject(parent) {}
+
+ QString attachedName() const { return m_name; }
+ void setAttachedName(const QString &name)
+ {
+ if (name != m_name) {
+ m_name = name;
+ emit attachedNameChanged();
+ }
+ }
+
+ static ItemAttached *qmlAttachedProperties(QObject *object)
+ {
+ if (object->objectName() != QLatin1String("foo")) {
+ qWarning("Only foo can have ItemAttached!");
+ return nullptr;
+ }
+
+ return new ItemAttached(object);
+ }
+
+signals:
+ void attachedNameChanged();
+
+private:
+ QString m_name;
+};
+
+class BindableOnly : public QObject
+{
+ Q_OBJECT
+ Q_PROPERTY(QByteArray data READ data WRITE setData BINDABLE dataBindable FINAL)
+ QML_ELEMENT
+public:
+ BindableOnly(QObject *parent = nullptr)
+ : QObject(parent)
+ {}
+
+ QBindable<QByteArray> dataBindable() { return QBindable<QByteArray>(&m_data); }
+
+ QByteArray data() const { return m_data.value(); }
+ void setData(const QByteArray &newData) { m_data.setValue(newData); }
+
+private:
+ QProperty<QByteArray> m_data;
+};
+
void registerTypes();
#endif // TESTTYPES_H
diff --git a/tests/auto/qml/qqmllanguage/tst_qqmllanguage.cpp b/tests/auto/qml/qqmllanguage/tst_qqmllanguage.cpp
index d09f903ccb..047df2f6d0 100644
--- a/tests/auto/qml/qqmllanguage/tst_qqmllanguage.cpp
+++ b/tests/auto/qml/qqmllanguage/tst_qqmllanguage.cpp
@@ -50,11 +50,12 @@
#include <private/qqmlvmemetaobject_p.h>
#include <private/qqmlcomponent_p.h>
#include <private/qqmltype_p_p.h>
+#include <private/qqmlcomponentattached_p.h>
+#include <private/qv4debugging_p.h>
#include "testtypes.h"
-#include "testhttpserver.h"
-
-#include "../../shared/util.h"
+#include <QtQuickTestUtils/private/qmlutils_p.h>
+#include <QtQuickTestUtils/private/testhttpserver_p.h>
#include <deque>
@@ -85,6 +86,9 @@ class tst_qqmllanguage : public QQmlDataTest
{
Q_OBJECT
+public:
+ tst_qqmllanguage();
+
private slots:
void initTestCase() override;
void cleanupTestCase();
@@ -242,6 +246,8 @@ private slots:
void deepProperty();
+ void groupAssignmentFailure();
+
void compositeSingletonProperties();
void compositeSingletonSameEngine();
void compositeSingletonDifferentEngine();
@@ -345,6 +351,7 @@ private slots:
void checkURLtoURLObject();
void registerValueTypes();
void extendedNamespace();
+ void extendedNamespaceByObject();
void factorySingleton();
void extendedSingleton();
void qtbug_85932();
@@ -363,7 +370,23 @@ private slots:
void propertyObserverOnReadonly();
+ void propertyAndAliasMustHaveDistinctNames_data();
+ void propertyAndAliasMustHaveDistinctNames();
+
void variantListConversion();
+ void thisInArrowFunction();
+
+ void jittedAsCast();
+
+ void ambiguousContainingType();
+ void objectAsBroken();
+ void componentMix();
+ void uncreatableAttached();
+
+ void bindableOnly();
+ void badGroupedProperty();
+ void bindingAliasToComponentUrl();
+ void signalInlineComponentArg();
private:
QQmlEngine engine;
@@ -2141,6 +2164,22 @@ void tst_qqmllanguage::aliasProperties()
QCOMPARE(subItem->property("y").toInt(), 1);
}
+ // Nested property bindings on group properties that are actually aliases (QTBUG-94983)
+ {
+ QQmlComponent component(&engine, testFileUrl("alias.15a.qml"));
+ VERIFY_ERRORS(0);
+
+ QScopedPointer<QObject> object(component.create());
+ QVERIFY(!object.isNull());
+
+ QPointer<QObject> subItem = qvariant_cast<QObject*>(object->property("symbol"));
+ QVERIFY(!subItem.isNull());
+
+ QPointer<QObject> subSubItem = qvariant_cast<QObject*>(subItem->property("layer"));
+
+ QCOMPARE(subSubItem->property("enabled").value<bool>(), true);
+ }
+
// Alias to sub-object with binding (QTBUG-57041)
{
// This is shold *not* crash.
@@ -2218,6 +2257,16 @@ void tst_qqmllanguage::aliasProperties()
QQmlComponent component(&engine, testFileUrl("alias.18.qml"));
VERIFY_ERRORS("alias.18.errors.txt");
}
+
+ // Binding on deep alias
+ {
+ QQmlComponent component(&engine, testFileUrl("alias.19.qml"));
+ VERIFY_ERRORS(0);
+
+ QScopedPointer<QObject> object(component.create());
+ QVERIFY(!object.isNull());
+ QCOMPARE(object->property("height").toInt(), 960);
+ }
}
// QTBUG-13374 Test that alias properties and signals can coexist
@@ -3730,6 +3779,11 @@ void tst_qqmllanguage::uncreatableTypesAsProperties()
QVERIFY(!object.isNull());
}
+tst_qqmllanguage::tst_qqmllanguage()
+ : QQmlDataTest(QT_QMLTEST_DATADIR)
+{
+}
+
void tst_qqmllanguage::initTestCase()
{
QQmlDataTest::initTestCase();
@@ -4355,6 +4409,17 @@ void tst_qqmllanguage::deepProperty()
QCOMPARE(font.family(), QStringLiteral("test"));
}
+void tst_qqmllanguage::groupAssignmentFailure()
+{
+ auto ep = std::make_unique<QQmlEngine>();
+ QTest::ignoreMessage(QtMsgType::QtWarningMsg, QRegularExpression(".*Invalid property assignment: url expected - Assigning null to incompatible properties in QML is deprecated. This will become a compile error in future versions of Qt..*"));
+ QQmlComponent component(ep.get(), testFileUrl("groupFailure.qml"));
+ QScopedPointer<QObject> o(component.create());
+ QVERIFY(!o);
+ ep.reset();
+ // ~QQmlComponent should not crash here
+}
+
// Tests that the implicit import has lowest precedence, in the case where
// there are conflicting types and types only found in the local import.
// Tests that just check one (or the root) type are in ::importsOrder
@@ -5502,9 +5567,20 @@ void tst_qqmllanguage::extendedForeignTypes()
QScopedPointer<QObject> o(component.create());
QVERIFY(!o.isNull());
+ QObject *extended = o->property("extended").value<QObject *>();
+ QVERIFY(extended);
+ QSignalSpy extensionChangedSpy(extended, SIGNAL(extensionChanged()));
+
QCOMPARE(o->property("extendedBase").toInt(), 43);
QCOMPARE(o->property("extendedExtension").toInt(), 42);
QCOMPARE(o->property("foreignExtendedExtension").toInt(), 42);
+
+ QCOMPARE(extensionChangedSpy.count(), 0);
+ extended->setProperty("extension", 44);
+ QCOMPARE(extensionChangedSpy.count(), 1);
+ QCOMPARE(o->property("extendedChangeCount").toInt(), 1);
+ QCOMPARE(o->property("extendedExtension").toInt(), 44);
+
QCOMPARE(o->property("foreignObjectName").toString(), QLatin1String("foreign"));
QCOMPARE(o->property("foreignExtendedObjectName").toString(), QLatin1String("foreignExtended"));
QCOMPARE(o->property("extendedInvokable").toInt(), 123);
@@ -6096,6 +6172,22 @@ void tst_qqmllanguage::extendedNamespace()
QCOMPARE(obj->property("fromExtension").toInt(), 9);
}
+void tst_qqmllanguage::extendedNamespaceByObject()
+{
+ QQmlEngine engine;
+ QQmlComponent c(&engine);
+ c.setData("import StaticTest\n"
+ "import QtQml\n"
+ "ExtendedNamespaceByObject {\n"
+ " extension: 10\n"
+ "}", QUrl());
+ QVERIFY2(c.isReady(), qPrintable(c.errorString()));
+ QScopedPointer<QObject> obj(c.create());
+ QVERIFY(!obj.isNull());
+
+ QCOMPARE(obj->property("extension").toInt(), 10);
+}
+
void tst_qqmllanguage::factorySingleton()
{
QQmlEngine engine;
@@ -6294,8 +6386,23 @@ void tst_qqmllanguage::bareInlineComponent()
QVERIFY(tab1Found);
}
+struct DummyDebugger : public QV4::Debugging::Debugger
+{
+ bool pauseAtNextOpportunity() const final { return false; }
+ void maybeBreakAtInstruction() final { }
+ void enteringFunction() final { }
+ void leavingFunction(const QV4::ReturnedValue &) final { }
+ void aboutToThrow() final { }
+};
+
void tst_qqmllanguage::hangOnWarning()
{
+ QQmlEngine engine;
+
+ // A debugger prevents the disk cache.
+ // If we load the file from disk cache we don't parse it and we don't see the warning.
+ engine.handle()->setDebugger(new DummyDebugger);
+
QTest::ignoreMessage(QtWarningMsg,
qPrintable(QStringLiteral("%1:3 : Ignored annotation")
.arg(testFileUrl("hangOnWarning.qml").toString())));
@@ -6355,6 +6462,26 @@ void tst_qqmllanguage::propertyObserverOnReadonly()
QCOMPARE(o->property("height").toDouble(), 54.2);
}
+void tst_qqmllanguage::propertyAndAliasMustHaveDistinctNames_data()
+{
+ QTest::addColumn<QString>("fileName");
+ QTest::addColumn<QString>("error");
+
+ QTest::addRow("sameNamePropertyAlias") << "sameNamePropertyAlias.qml" << "Property duplicates alias name";
+ QTest::addRow("sameNameAliasProperty") << "sameNameAliasProperty.qml" << "Alias has same name as existing property";
+}
+
+void tst_qqmllanguage::propertyAndAliasMustHaveDistinctNames()
+{
+ QFETCH(QString, fileName);
+ QFETCH(QString, error);
+ QQmlEngine engine;
+ QQmlComponent c(&engine, testFileUrl(fileName));
+ QVERIFY(!c.isReady());
+ auto actualError = c.errorString();
+ QVERIFY2(actualError.contains(error), qPrintable(actualError));
+}
+
void tst_qqmllanguage::variantListConversion()
{
QQmlEngine engine;
@@ -6365,11 +6492,181 @@ void tst_qqmllanguage::variantListConversion()
Foo *foo = qobject_cast<Foo *>(o.data());
QVERIFY(foo);
const QVariantList list = foo->getList();
- QCOMPARE(list.length(), 2);
+ QCOMPARE(list.length(), 3);
const Large l0 = qvariant_cast<Large>(list.at(0));
QCOMPARE(l0.a, 12ull);
const Large l1 = qvariant_cast<Large>(list.at(1));
QCOMPARE(l1.a, 13ull);
+ const QObject *attached = qvariant_cast<QObject *>(list.at(2));
+ QVERIFY(attached);
+ QCOMPARE(attached->metaObject(), &QQmlComponentAttached::staticMetaObject);
+}
+
+void tst_qqmllanguage::thisInArrowFunction()
+{
+ QQmlEngine engine;
+ QQmlComponent c(&engine, testFileUrl("thisInArrow.qml"));
+ QVERIFY2(c.isReady(), qPrintable(c.errorString()));
+
+ QTest::ignoreMessage(QtDebugMsg, "43");
+ QScopedPointer<QObject> o(c.create());
+ QVERIFY(!o.isNull());
+
+ QCOMPARE(qvariant_cast<QObject *>(o->property("arrowResult")), o.data());
+ QCOMPARE(qvariant_cast<QObject *>(o->property("funcResult")), o.data());
+ QCOMPARE(qvariant_cast<QObject *>(o->property("aResult")), o.data());
+ QCOMPARE(qvariant_cast<QObject *>(o->property("aaResult")), o.data());
+
+ QCOMPARE(qvariant_cast<QObject *>(o->property("fResult")), nullptr);
+ QCOMPARE(o->property("fResult").metaType(), QMetaType::fromType<QJSValue>());
+ QVERIFY(qvariant_cast<QJSValue>(o->property("fResult")).isObject());
+
+ QObject *child = qvariant_cast<QObject *>(o->property("child"));
+ QVERIFY(child != nullptr);
+ QCOMPARE(qvariant_cast<QObject *>(o->property("ffResult")), child);
+}
+
+void tst_qqmllanguage::jittedAsCast()
+{
+ QQmlEngine engine;
+ QQmlComponent c(&engine, testFileUrl("jittedAsCast.qml"));
+ QVERIFY2(c.isReady(), qPrintable(c.errorString()));
+ QScopedPointer<QObject> o(c.create());
+ QCOMPARE(o->property("running").toBool(), true);
+ QTRY_COMPARE(o->property("running").toBool(), false);
+ QCOMPARE(o->property("interval").toInt(), 10);
+}
+
+void tst_qqmllanguage::ambiguousContainingType()
+{
+ // Need to do it twice, so that we load from disk cache the second time.
+ for (int i = 0; i < 2; ++i) {
+ QQmlEngine engine;
+
+ // Should not crash when loading the type
+ QQmlComponent c(&engine, testFileUrl("ambiguousBinding/ambiguousContainingType.qml"));
+ QVERIFY2(c.isReady(), qPrintable(c.errorString()));
+ QScopedPointer<QObject> o(c.create());
+ QVERIFY(!o.isNull());
+ }
+}
+
+void tst_qqmllanguage::objectAsBroken()
+{
+ QQmlEngine engine;
+ QQmlComponent c(&engine, testFileUrl("asBroken.qml"));
+ QVERIFY2(c.isReady(), qPrintable(c.errorString()));
+ QScopedPointer<QObject> o(c.create());
+ QVERIFY(!o.isNull());
+ QVariant selfAsBroken = o->property("selfAsBroken");
+ QVERIFY(selfAsBroken.isValid());
+ QCOMPARE(selfAsBroken.metaType(), QMetaType::fromType<std::nullptr_t>());
+
+ QQmlComponent b(&engine, testFileUrl("Broken.qml"));
+ QVERIFY(b.isError());
+}
+
+void tst_qqmllanguage::componentMix()
+{
+ QQmlEngine engine;
+ QQmlComponent c(&engine, testFileUrl("componentMix.qml"));
+ QVERIFY2(c.isReady(), qPrintable(c.errorString()));
+ QScopedPointer<QObject> o(c.create());
+ QVERIFY(!o.isNull());
+ QObject *things = qvariant_cast<QObject *>(o->property("things"));
+ QVERIFY(things);
+ QObject *delegated = qvariant_cast<QObject *>(o->property("delegated"));
+ QVERIFY(delegated);
+ QObject *view = qvariant_cast<QObject *>(things->property("view"));
+ QVERIFY(view);
+ QObject *delegate = qvariant_cast<QObject *>(view->property("delegate"));
+ QVERIFY(delegate);
+ QCOMPARE(delegate->metaObject(), &QQmlComponent::staticMetaObject);
+ QObject *delegate2 = qvariant_cast<QObject *>(delegated->property("delegate"));
+ QVERIFY(delegate2);
+ QCOMPARE(delegate2->metaObject(), &QQmlComponent::staticMetaObject);
+}
+
+void tst_qqmllanguage::uncreatableAttached()
+{
+ qmlRegisterTypesAndRevisions<ItemAttached>("ABC", 1);
+ QQmlEngine engine;
+ const QUrl url = testFileUrl("uncreatableAttached.qml");
+ QQmlComponent c(&engine, url);
+ QVERIFY2(c.isReady(), qPrintable(c.errorString()));
+ QTest::ignoreMessage(QtWarningMsg, "Only foo can have ItemAttached!");
+ QScopedPointer o(c.create());
+ QVERIFY(o.isNull());
+ QVERIFY(c.errorString().contains(
+ QLatin1String("Could not create attached properties object 'ItemAttached'")));
+}
+
+void tst_qqmllanguage::bindableOnly()
+{
+ qmlRegisterTypesAndRevisions<BindableOnly>("ABC", 1);
+ QQmlEngine engine;
+
+ QQmlComponent c(&engine);
+ c.setData("import ABC\nBindableOnly {\n"
+ " data: \"sc\" + \"ore\"\n"
+ " objectName: data\n"
+ "}", QUrl(u"bindableOnly.qml"_qs));
+ QScopedPointer<QObject> o(c.create());
+ QVERIFY(!o.isNull());
+ QCOMPARE(o->property("data").value<QByteArray>(), QByteArray("score"));
+ QCOMPARE(o->objectName(), QStringLiteral("score"));
+}
+
+void tst_qqmllanguage::badGroupedProperty()
+{
+ QQmlEngine engine;
+ const QUrl url = testFileUrl("badGroupedProperty.qml");
+ QQmlComponent c(&engine, url);
+ QVERIFY(c.isError());
+ QCOMPARE(c.errorString(),
+ QStringLiteral("%1:6 Cannot assign to non-existent property \"onComplete\"\n")
+ .arg(url.toString()));
+}
+
+void tst_qqmllanguage::bindingAliasToComponentUrl()
+{
+ QQmlEngine engine;
+ {
+ QQmlComponent component(&engine, testFileUrl("bindingAliasToComponentUrl.qml"));
+ QVERIFY2(component.isReady(), qPrintable(component.errorString()));
+ QScopedPointer<QObject> object(component.create());
+ QVERIFY(object);
+ QCOMPARE(object->property("accessibleNormalUrl"), object->property("urlClone"));
+ }
+ {
+ QQmlComponent component(&engine, testFileUrl("bindingAliasToComponentUrl2.qml"));
+ QVERIFY2(component.isReady(), qPrintable(component.errorString()));
+ QScopedPointer<QObject> object(component.create());
+ QVERIFY(object);
+ QCOMPARE(object->property("accessibleNormalProgress"), QVariant(1.0));
+ }
+}
+
+void tst_qqmllanguage::signalInlineComponentArg()
+{
+ QQmlEngine engine;
+ {
+ QQmlComponent component(&engine, testFileUrl("SignalInlineComponentArg.qml"));
+ QVERIFY2(component.isReady(), qPrintable(component.errorString()));
+ QScopedPointer<QObject> object(component.create());
+
+ QCOMPARE(object->property("success"), QStringLiteral("Signal was called"));
+ }
+ {
+ QQmlComponent component(&engine, testFileUrl("signalInlineComponentArg1.qml"));
+ QVERIFY2(component.isReady(), qPrintable(component.errorString()));
+ QScopedPointer<QObject> object(component.create());
+
+ QCOMPARE(object->property("successFromOwnSignal"),
+ QStringLiteral("Own signal was called with component from another file"));
+ QCOMPARE(object->property("successFromSignalFromFile"),
+ QStringLiteral("Signal was called from another file"));
+ }
}
QTEST_MAIN(tst_qqmllanguage)