aboutsummaryrefslogtreecommitdiffstats
path: root/tests/auto
diff options
context:
space:
mode:
authorUlf Hermann <ulf.hermann@qt.io>2023-01-03 15:45:31 +0100
committerUlf Hermann <ulf.hermann@qt.io>2023-01-20 20:39:11 +0100
commitec58c0ddb7fe1ebf33c80335ab9435e53fd00274 (patch)
treed30a8779fa5fb82bcc9e3b31e581d3962dc81d21 /tests/auto
parentea5200b82f21e0f4d080d3fc256b218e0ee56f3d (diff)
QML: Add a pragma for value type behavior
Unfortunately value types behave differently when compiled to C++. Document the difference and introduce a pragma to make them behave one way or the other. Pick-to: 6.5 Fixes: QTBUG-109221 Change-Id: Ib2685153c0b4ae209bafbea7a01229377fdb47dd Reviewed-by: Fabian Kosmale <fabian.kosmale@qt.io>
Diffstat (limited to 'tests/auto')
-rw-r--r--tests/auto/qml/qmlcppcodegen/data/CMakeLists.txt2
-rw-r--r--tests/auto/qml/qmlcppcodegen/data/valueTypeCopy.qml34
-rw-r--r--tests/auto/qml/qmlcppcodegen/data/valueTypeReference.qml34
-rw-r--r--tests/auto/qml/qmlcppcodegen/tst_qmlcppcodegen.cpp35
4 files changed, 105 insertions, 0 deletions
diff --git a/tests/auto/qml/qmlcppcodegen/data/CMakeLists.txt b/tests/auto/qml/qmlcppcodegen/data/CMakeLists.txt
index e66af303ca..be74e062c0 100644
--- a/tests/auto/qml/qmlcppcodegen/data/CMakeLists.txt
+++ b/tests/auto/qml/qmlcppcodegen/data/CMakeLists.txt
@@ -190,8 +190,10 @@ set(qml_files
unusedAttached.qml
urlString.qml
usingCxxTypesFromFileImports.qml
+ valueTypeCopy.qml
valueTypeLists.qml
valueTypeProperty.qml
+ valueTypeReference.qml
variantlist.qml
versionmismatch.qml
voidfunction.qml
diff --git a/tests/auto/qml/qmlcppcodegen/data/valueTypeCopy.qml b/tests/auto/qml/qmlcppcodegen/data/valueTypeCopy.qml
new file mode 100644
index 0000000000..cca634753d
--- /dev/null
+++ b/tests/auto/qml/qmlcppcodegen/data/valueTypeCopy.qml
@@ -0,0 +1,34 @@
+pragma ValueTypeBehavior: Copy
+import QtQml
+
+QtObject {
+ id: root
+
+ property list<double> numbers: {
+ var result = [];
+ for (var i = 0; i < 10; ++i)
+ result[i] = i;
+ return result;
+ }
+
+ property rect r: ({x: 1, y: 2, width: 3, height: 4})
+
+ function evil() : double {
+ var numbers = root.numbers;
+ root.numbers = [];
+ var a = 0;
+ for (var j = 0; j < 10; ++j) {
+ a += numbers[j];
+ }
+ return a;
+ }
+
+ function fvil() : double {
+ var r = root.r;
+ root.r = {x: 5, y: 6, width: 7, height: 8};
+ return r.x;
+ }
+
+ property double e: evil()
+ property double f: fvil()
+}
diff --git a/tests/auto/qml/qmlcppcodegen/data/valueTypeReference.qml b/tests/auto/qml/qmlcppcodegen/data/valueTypeReference.qml
new file mode 100644
index 0000000000..568f39820c
--- /dev/null
+++ b/tests/auto/qml/qmlcppcodegen/data/valueTypeReference.qml
@@ -0,0 +1,34 @@
+pragma ValueTypeBehavior: Reference
+import QtQml
+
+QtObject {
+ id: root
+
+ property list<double> numbers: {
+ var result = [];
+ for (var i = 0; i < 10; ++i)
+ result[i] = i;
+ return result;
+ }
+
+ property rect r: ({x: 1, y: 2, width: 3, height: 4})
+
+ function evil() : double {
+ var numbers = root.numbers;
+ root.numbers = [];
+ var a = 0;
+ for (var j = 0; j < 10; ++j) {
+ a += numbers[j];
+ }
+ return a;
+ }
+
+ function fvil() : double {
+ var r = root.r;
+ root.r = {x: 5, y: 6, width: 7, height: 8};
+ return r.x;
+ }
+
+ property double e: evil()
+ property double f: fvil()
+}
diff --git a/tests/auto/qml/qmlcppcodegen/tst_qmlcppcodegen.cpp b/tests/auto/qml/qmlcppcodegen/tst_qmlcppcodegen.cpp
index 1e88ecd7b7..405e65853a 100644
--- a/tests/auto/qml/qmlcppcodegen/tst_qmlcppcodegen.cpp
+++ b/tests/auto/qml/qmlcppcodegen/tst_qmlcppcodegen.cpp
@@ -162,6 +162,7 @@ private slots:
void equalityVarAndNonStorable();
void equalityQObjects();
void dateConversions();
+ void valueTypeBehavior();
};
void tst_QmlCppCodegen::initTestCase()
@@ -3125,6 +3126,40 @@ void tst_QmlCppCodegen::dateConversions()
QCOMPARE(ref->myTime(), (engine.coerceValue<QDate, QTime>(date)));
}
+static QRegularExpression bindingLoopMessage(const QUrl &url, char var)
+{
+ // The actual string depends on how many times QObject* was registered with what parameters.
+ return QRegularExpression(
+ "%1:4:1: QML [^:]+: Binding loop detected for property \"%2\""_L1
+ .arg(url.toString()).arg(QLatin1Char(var)));
+}
+
+void tst_QmlCppCodegen::valueTypeBehavior()
+{
+ QQmlEngine engine;
+
+ const QUrl copy(u"qrc:/qt/qml/TestTypes/valueTypeCopy.qml"_s);
+
+ QQmlComponent c1(&engine, copy);
+ QVERIFY2(c1.isReady(), qPrintable(c1.errorString()));
+ QTest::ignoreMessage(QtWarningMsg, bindingLoopMessage(copy, 'e'));
+ QTest::ignoreMessage(QtWarningMsg, bindingLoopMessage(copy, 'f'));
+ QScopedPointer<QObject> o1(c1.create());
+ QVERIFY(!o1.isNull());
+ QCOMPARE(o1->property("e").toDouble(), 45.0);
+ QCOMPARE(o1->property("f").toDouble(), 1.0);
+
+ const QUrl reference(u"qrc:/qt/qml/TestTypes/valueTypeReference.qml"_s);
+ QQmlComponent c2(&engine, reference);
+ QVERIFY2(c2.isReady(), qPrintable(c2.errorString()));
+ QTest::ignoreMessage(QtWarningMsg, bindingLoopMessage(reference, 'e'));
+ QTest::ignoreMessage(QtWarningMsg, bindingLoopMessage(reference, 'f'));
+ QScopedPointer<QObject> o2(c2.create());
+ QVERIFY(!o2.isNull());
+ QVERIFY(qIsNaN(o2->property("e").toDouble()));
+ QCOMPARE(o2->property("f").toDouble(), 5.0);
+}
+
QTEST_MAIN(tst_QmlCppCodegen)
#include "tst_qmlcppcodegen.moc"