aboutsummaryrefslogtreecommitdiffstats
path: root/tests
diff options
context:
space:
mode:
Diffstat (limited to 'tests')
-rw-r--r--tests/auto/qml/CMakeLists.txt1
-rw-r--r--tests/auto/qml/qjsengine/tst_qjsengine.cpp21
-rw-r--r--tests/auto/qml/qqmllanguage/data/BindingOverrider.qml5
-rw-r--r--tests/auto/qml/qqmllanguage/data/SimpleWidget.qml25
-rw-r--r--tests/auto/qml/qqmllanguage/data/badICAnnotation.qml26
-rw-r--r--tests/auto/qml/qqmllanguage/data/typedObjectList.qml13
-rw-r--r--tests/auto/qml/qqmllanguage/tst_qqmllanguage.cpp51
-rw-r--r--tests/auto/qml/qqmllistmodel/data/deadModelData.qml45
-rw-r--r--tests/auto/qml/qqmllistmodel/tst_qqmllistmodel.cpp62
-rw-r--r--tests/auto/qml/qv4estable/CMakeLists.txt24
-rw-r--r--tests/auto/qml/qv4estable/tst_qv4estable.cpp40
-rw-r--r--tests/auto/quick/qquickanimations/tst_qquickanimations.cpp36
-rw-r--r--tests/auto/quick/qquicklayouts/data/tst_rowlayout.qml47
-rw-r--r--tests/auto/quick/qquicklistview/data/snapToItemWithSectionAtStart.qml52
-rw-r--r--tests/auto/quick/qquicklistview/tst_qquicklistview.cpp22
-rw-r--r--tests/auto/quick/qquickmultipointtoucharea/BLACKLIST2
-rw-r--r--tests/auto/quick/qquicktableview/tst_qquicktableview.cpp81
-rw-r--r--tests/auto/quick/qquicktext/data/elideZeroWidthWithMargins.qml27
-rw-r--r--tests/auto/quick/qquicktext/tst_qquicktext.cpp12
-rw-r--r--tests/auto/quickcontrols2/controls/data/tst_control.qml30
-rw-r--r--tests/auto/quickcontrols2/qquickpopup/data/resetHoveredForItemsWithinOverlay.qml28
-rw-r--r--tests/auto/quickcontrols2/qquickpopup/tst_qquickpopup.cpp35
-rw-r--r--tests/auto/quickwidgets/qquickwidget/tst_qquickwidget.cpp3
23 files changed, 687 insertions, 1 deletions
diff --git a/tests/auto/qml/CMakeLists.txt b/tests/auto/qml/CMakeLists.txt
index 5fe0b0950f..4b2fb9c1e7 100644
--- a/tests/auto/qml/CMakeLists.txt
+++ b/tests/auto/qml/CMakeLists.txt
@@ -120,6 +120,7 @@ if(QT_FEATURE_private_tests)
add_subdirectory(qqmltablemodel)
add_subdirectory(qv4assembler)
add_subdirectory(qv4mm)
+ add_subdirectory(qv4estable)
add_subdirectory(qv4identifiertable)
add_subdirectory(qv4regexp)
if(QT_FEATURE_process AND NOT QNX)
diff --git a/tests/auto/qml/qjsengine/tst_qjsengine.cpp b/tests/auto/qml/qjsengine/tst_qjsengine.cpp
index c2c6f3f43f..8d2b5179f8 100644
--- a/tests/auto/qml/qjsengine/tst_qjsengine.cpp
+++ b/tests/auto/qml/qjsengine/tst_qjsengine.cpp
@@ -293,6 +293,7 @@ private slots:
void spreadNoOverflow();
void deleteDefineCycle();
+ void deleteFromSparseArray();
public:
Q_INVOKABLE QJSValue throwingCppMethod1();
@@ -5837,6 +5838,26 @@ void tst_QJSEngine::deleteDefineCycle()
QVERIFY(stackTrace.isEmpty());
}
+void tst_QJSEngine::deleteFromSparseArray()
+{
+ QJSEngine engine;
+
+ // Should not crash
+ const QJSValue result = engine.evaluate(QLatin1String(R"((function() {
+ let o = [];
+ o[10000] = 10;
+ o[20000] = 20;
+ for (let k in o)
+ delete o[k];
+ return o;
+ })())"));
+
+ QVERIFY(result.isArray());
+ QCOMPARE(result.property("length").toNumber(), 20001);
+ QVERIFY(result.property(10000).isUndefined());
+ QVERIFY(result.property(20000).isUndefined());
+}
+
QTEST_MAIN(tst_QJSEngine)
#include "tst_qjsengine.moc"
diff --git a/tests/auto/qml/qqmllanguage/data/BindingOverrider.qml b/tests/auto/qml/qqmllanguage/data/BindingOverrider.qml
new file mode 100644
index 0000000000..de7e1e96a3
--- /dev/null
+++ b/tests/auto/qml/qqmllanguage/data/BindingOverrider.qml
@@ -0,0 +1,5 @@
+import QtQml 2.15
+
+SimpleWidget {
+ width: 20
+}
diff --git a/tests/auto/qml/qqmllanguage/data/SimpleWidget.qml b/tests/auto/qml/qqmllanguage/data/SimpleWidget.qml
new file mode 100644
index 0000000000..9150ebaa4e
--- /dev/null
+++ b/tests/auto/qml/qqmllanguage/data/SimpleWidget.qml
@@ -0,0 +1,25 @@
+import QtQuick 2.15
+
+Item {
+ id: outer
+
+ property real innerWidth: 0
+
+ Item {
+ id: inner
+ width: style.width
+ onWidthChanged: outer.innerWidth = width
+ }
+
+ width: inner.width
+
+ onWidthChanged: {
+ if (width !== inner.width)
+ inner.width = width // overwrite binding
+ }
+
+ QtObject {
+ id: style
+ property int width: 50
+ }
+}
diff --git a/tests/auto/qml/qqmllanguage/data/badICAnnotation.qml b/tests/auto/qml/qqmllanguage/data/badICAnnotation.qml
new file mode 100644
index 0000000000..78555ac7dc
--- /dev/null
+++ b/tests/auto/qml/qqmllanguage/data/badICAnnotation.qml
@@ -0,0 +1,26 @@
+
+import QtQml
+
+QtObject {
+ id: self
+
+ function doStuff(status: Binding.NotAnInlineComponent) : int {
+ return status
+ }
+
+ function doStuff2(status: InlineComponentBase.IC) : QtObject {
+ return status
+ }
+
+ function doStuff3(status: InlineComponentBase.NotIC) : QtObject {
+ return status
+ }
+
+ property InlineComponentBase.IC ic: InlineComponentBase.IC {}
+
+ property int a: doStuff(5)
+ property QtObject b: doStuff2(ic)
+ property QtObject c: doStuff3(ic)
+ property QtObject d: doStuff2(self)
+}
+
diff --git a/tests/auto/qml/qqmllanguage/data/typedObjectList.qml b/tests/auto/qml/qqmllanguage/data/typedObjectList.qml
new file mode 100644
index 0000000000..89c66249cf
--- /dev/null
+++ b/tests/auto/qml/qqmllanguage/data/typedObjectList.qml
@@ -0,0 +1,13 @@
+import QtQml
+
+QtObject {
+ property var b;
+ property Component c: QtObject {}
+
+ // In 6.5 and earlier we don't have heap-managed QQmlListProperty, yet.
+ property list<Component> ll;
+
+ function returnList(a: Component) : list<Component> { ll.push(a); return ll; }
+
+ Component.onCompleted: b = { b: returnList(c) }
+}
diff --git a/tests/auto/qml/qqmllanguage/tst_qqmllanguage.cpp b/tests/auto/qml/qqmllanguage/tst_qqmllanguage.cpp
index 3d1f023425..95e838476f 100644
--- a/tests/auto/qml/qqmllanguage/tst_qqmllanguage.cpp
+++ b/tests/auto/qml/qqmllanguage/tst_qqmllanguage.cpp
@@ -394,6 +394,11 @@ private slots:
void deepAliasOnICOrReadonly();
void writeNumberToEnumAlias();
+ void badInlineComponentAnnotation();
+
+ void typedObjectList();
+
+ void overrideInnerBinding();
private:
QQmlEngine engine;
@@ -6747,6 +6752,52 @@ void tst_qqmllanguage::writeNumberToEnumAlias()
QCOMPARE(o->property("strokeStyle").toInt(), 1);
}
+void tst_qqmllanguage::badInlineComponentAnnotation()
+{
+ QQmlEngine engine;
+ const QUrl url = testFileUrl("badICAnnotation.qml");
+ QQmlComponent c(&engine, testFileUrl("badICAnnotation.qml"));
+ QVERIFY2(c.isReady(), qPrintable(c.errorString()));
+
+ QScopedPointer<QObject> o(c.create());
+ QVERIFY(!o.isNull());
+
+ QCOMPARE(o->property("a").toInt(), 5);
+
+ QObject *ic = o->property("ic").value<QObject *>();
+ QVERIFY(ic);
+
+ QCOMPARE(o->property("b").value<QObject *>(), ic);
+ QCOMPARE(o->property("c").value<QObject *>(), ic);
+}
+
+void tst_qqmllanguage::typedObjectList()
+{
+ QQmlEngine e;
+ QQmlComponent c(&e, testFileUrl("typedObjectList.qml"));
+ QVERIFY2(c.isReady(), qPrintable(c.errorString()));
+ QScopedPointer<QObject> o(c.create());
+ QVERIFY(!o.isNull());
+
+ QJSValue b = o->property("b").value<QJSValue>();
+ auto list = qjsvalue_cast<QQmlListProperty<QQmlComponent>>(b.property(QStringLiteral("b")));
+
+ QCOMPARE(list.count(&list), 1);
+ QVERIFY(list.at(&list, 0) != nullptr);
+}
+
+void tst_qqmllanguage::overrideInnerBinding()
+{
+ QQmlEngine e;
+ QQmlComponent c(&e, testFileUrl("BindingOverrider.qml"));
+ QVERIFY2(c.isReady(), qPrintable(c.errorString()));
+ QScopedPointer<QObject> o(c.create());
+ QVERIFY(!o.isNull());
+
+ QCOMPARE(o->property("width").toReal(), 20.0);
+ QCOMPARE(o->property("innerWidth").toReal(), 20.0);
+}
+
QTEST_MAIN(tst_qqmllanguage)
#include "tst_qqmllanguage.moc"
diff --git a/tests/auto/qml/qqmllistmodel/data/deadModelData.qml b/tests/auto/qml/qqmllistmodel/data/deadModelData.qml
new file mode 100644
index 0000000000..fc3dd6fa11
--- /dev/null
+++ b/tests/auto/qml/qqmllistmodel/data/deadModelData.qml
@@ -0,0 +1,45 @@
+import QtQml
+
+QtObject {
+ function swapCorpses() {
+ const lhsData = getModelData(lhsButtonListModel);
+ const rhsData = getModelData(rhsButtonListModel);
+
+ lhsButtonListModel.clear();
+ rhsButtonListModel.clear();
+
+ addToModel(lhsButtonListModel, rhsData);
+ addToModel(rhsButtonListModel, lhsData);
+ }
+
+ property ListModel l1: ListModel {
+ id: lhsButtonListModel
+ }
+
+ property ListModel l2: ListModel {
+ id: rhsButtonListModel
+ }
+
+ Component.onCompleted: {
+ lhsButtonListModel.append({ "ident": 1, "buttonText": "B 1"});
+ lhsButtonListModel.append({ "ident": 2, "buttonText": "B 2"});
+ lhsButtonListModel.append({ "ident": 3, "buttonText": "B 3"});
+
+ rhsButtonListModel.append({ "ident": 4, "buttonText": "B 4"});
+ rhsButtonListModel.append({ "ident": 5, "buttonText": "B 5"});
+ rhsButtonListModel.append({ "ident": 6, "buttonText": "B 6"});
+ }
+
+ function getModelData(model) {
+ var dataList = []
+ for (var i = 0; i < model.count; ++i)
+ dataList.push(model.get(i));
+
+ return dataList;
+ }
+
+ function addToModel(model, buttonData) {
+ for (var i = 0; i < buttonData.length; ++i)
+ model.append(buttonData[i]);
+ }
+}
diff --git a/tests/auto/qml/qqmllistmodel/tst_qqmllistmodel.cpp b/tests/auto/qml/qqmllistmodel/tst_qqmllistmodel.cpp
index fbdf6d90f3..f440eab6b7 100644
--- a/tests/auto/qml/qqmllistmodel/tst_qqmllistmodel.cpp
+++ b/tests/auto/qml/qqmllistmodel/tst_qqmllistmodel.cpp
@@ -140,6 +140,7 @@ private slots:
void destroyComponentObject();
void objectOwnershipFlip();
void protectQObjectFromGC();
+ void deadModelData();
};
bool tst_qqmllistmodel::compareVariantList(const QVariantList &testList, QVariant object)
@@ -1940,6 +1941,67 @@ void tst_qqmllistmodel::protectQObjectFromGC()
}
}
+void tst_qqmllistmodel::deadModelData()
+{
+ QQmlEngine engine;
+ QQmlComponent component(&engine, testFileUrl("deadModelData.qml"));
+ QVERIFY2(component.isReady(), qPrintable(component.errorString()));
+ QScopedPointer<QObject> o(component.create());
+ QVERIFY(!o.isNull());
+
+ QQmlListModel *l1 = o->property("l1").value<QQmlListModel *>();
+ QVERIFY(l1);
+ QQmlListModel *l2 = o->property("l2").value<QQmlListModel *>();
+ QVERIFY(l2);
+
+ QCOMPARE(l1->count(), 3);
+ QCOMPARE(l2->count(), 3);
+
+ for (int i = 0; i < 3; ++i) {
+ QObject *i1 = qjsvalue_cast<QObject *>(l1->get(i));
+ QVERIFY(i1);
+ QCOMPARE(i1->property("ident").value<double>(), i + 1);
+ QCOMPARE(i1->property("buttonText").value<QString>(),
+ QLatin1String("B %1").arg(QLatin1Char('0' + i + 1)));
+
+ QObject *i2 = qjsvalue_cast<QObject *>(l2->get(i));
+ QVERIFY(i2);
+ QCOMPARE(i2->property("ident").value<double>(), i + 4);
+ QCOMPARE(i2->property("buttonText").value<QString>(),
+ QLatin1String("B %1").arg(QLatin1Char('0' + i + 4)));
+ }
+
+ for (int i = 0; i < 6; ++i) {
+ QTest::ignoreMessage(
+ QtWarningMsg,
+ QRegularExpression(".*: ident is undefined. Adding an object with a undefined "
+ "member does not create a role for it."));
+ QTest::ignoreMessage(
+ QtWarningMsg,
+ QRegularExpression(".*: buttonText is undefined. Adding an object with a undefined "
+ "member does not create a role for it."));
+ }
+
+ QMetaObject::invokeMethod(o.data(), "swapCorpses");
+
+ // We get default-created values for all the roles now.
+
+ QCOMPARE(l1->count(), 3);
+ QCOMPARE(l2->count(), 3);
+
+ for (int i = 0; i < 3; ++i) {
+ QObject *i1 = qjsvalue_cast<QObject *>(l1->get(i));
+ QVERIFY(i1);
+ QCOMPARE(i1->property("ident").value<double>(), double());
+ QCOMPARE(i1->property("buttonText").value<QString>(), QString());
+
+ QObject *i2 = qjsvalue_cast<QObject *>(l2->get(i));
+ QVERIFY(i2);
+ QCOMPARE(i2->property("ident").value<double>(), double());
+ QCOMPARE(i2->property("buttonText").value<QString>(), QString());
+ }
+}
+
QTEST_MAIN(tst_qqmllistmodel)
#include "tst_qqmllistmodel.moc"
diff --git a/tests/auto/qml/qv4estable/CMakeLists.txt b/tests/auto/qml/qv4estable/CMakeLists.txt
new file mode 100644
index 0000000000..01d2663a04
--- /dev/null
+++ b/tests/auto/qml/qv4estable/CMakeLists.txt
@@ -0,0 +1,24 @@
+# Copyright (C) 2024 The Qt Company Ltd.
+# SPDX-License-Identifier: BSD-3-Clause
+
+#####################################################################
+## tst_qv4estable Test:
+#####################################################################
+
+if(NOT QT_BUILD_STANDALONE_TESTS AND NOT QT_BUILDING_QT)
+ cmake_minimum_required(VERSION 3.16)
+ project(tst_qv4estable LANGUAGES CXX)
+ find_package(Qt6BuildInternals REQUIRED COMPONENTS STANDALONE_TEST)
+endif()
+
+qt_internal_add_test(tst_qv4estable
+ SOURCES
+ tst_qv4estable.cpp
+ LIBRARIES
+ Qt::Gui
+ Qt::Qml
+ Qt::QmlPrivate
+)
+
+## Scopes:
+#####################################################################
diff --git a/tests/auto/qml/qv4estable/tst_qv4estable.cpp b/tests/auto/qml/qv4estable/tst_qv4estable.cpp
new file mode 100644
index 0000000000..eecb672bc6
--- /dev/null
+++ b/tests/auto/qml/qv4estable/tst_qv4estable.cpp
@@ -0,0 +1,40 @@
+// Copyright (C) 2024 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only
+
+#include <qtest.h>
+#include <private/qv4estable_p.h>
+
+class tst_qv4estable : public QObject
+{
+ Q_OBJECT
+
+private slots:
+ void checkRemoveAvoidsHeapBufferOverflow();
+};
+
+// QTBUG-123999
+void tst_qv4estable::checkRemoveAvoidsHeapBufferOverflow()
+{
+ QV4::ESTable estable;
+
+ // Fill the ESTable with values so it is at max capacity.
+ QCOMPARE(estable.m_capacity, 8u);
+ for (uint i = 0; i < estable.m_capacity; ++i) {
+ estable.set(QV4::Value::fromUInt32(i), QV4::Value::fromUInt32(i));
+ }
+ // Our |m_keys| array should now contain eight values.
+ // > [v0, v1, v2, v3, v4, v5, v6, v7]
+ for (uint i = 0; i < estable.m_capacity; ++i) {
+ QVERIFY(estable.m_keys[i].sameValueZero(QV4::Value::fromUInt32(i)));
+ }
+ QCOMPARE(estable.m_capacity, 8u);
+ QCOMPARE(estable.m_size, 8u);
+
+ // Remove the first item from the set to verify that asan does not trip.
+ // Relies on the CI platform propagating asan flag to all tests.
+ estable.remove(QV4::Value::fromUInt32(0));
+}
+
+QTEST_MAIN(tst_qv4estable)
+
+#include "tst_qv4estable.moc"
diff --git a/tests/auto/quick/qquickanimations/tst_qquickanimations.cpp b/tests/auto/quick/qquickanimations/tst_qquickanimations.cpp
index 30b934eeec..579eeb7c0a 100644
--- a/tests/auto/quick/qquickanimations/tst_qquickanimations.cpp
+++ b/tests/auto/quick/qquickanimations/tst_qquickanimations.cpp
@@ -119,6 +119,7 @@ private slots:
void cleanupWhenRenderThreadStops();
void infiniteLoopsWithoutFrom();
void targetsDeletedNotRemoved();
+ void alwaysRunToEndSetFalseRestartBug();
};
#define QTIMED_COMPARE(lhs, rhs) do { \
for (int ii = 0; ii < 5; ++ii) { \
@@ -2081,6 +2082,41 @@ void tst_qquickanimations::targetsDeletedNotRemoved()
}
}
+//QTBUG-125224
+void tst_qquickanimations::alwaysRunToEndSetFalseRestartBug()
+{
+ QQuickRectangle rect;
+ QQuickSequentialAnimation sequential;
+ QQuickPropertyAnimation beginAnim;
+ QQuickPropertyAnimation endAnim;
+
+ beginAnim.setTargetObject(&rect);
+ beginAnim.setProperty("x");
+ beginAnim.setTo(200);
+ beginAnim.setDuration(1000);
+
+ endAnim.setTargetObject(&rect);
+ endAnim.setProperty("x");
+ endAnim.setFrom(200);
+ endAnim.setDuration(1000);
+
+ beginAnim.setGroup(&sequential);
+ endAnim.setGroup(&sequential);
+
+ sequential.setLoops(-1);
+ sequential.setAlwaysRunToEnd(true);
+
+ QCOMPARE(sequential.loops(), -1);
+ QVERIFY(sequential.alwaysRunToEnd());
+ sequential.start();
+ sequential.stop();
+ sequential.setAlwaysRunToEnd(false);
+ sequential.start();
+ QCOMPARE(sequential.isRunning(), true);
+ sequential.stop();
+ QCOMPARE(sequential.isRunning(), false);
+}
+
QTEST_MAIN(tst_qquickanimations)
#include "tst_qquickanimations.moc"
diff --git a/tests/auto/quick/qquicklayouts/data/tst_rowlayout.qml b/tests/auto/quick/qquicklayouts/data/tst_rowlayout.qml
index 5e8f6f9bcf..37166af119 100644
--- a/tests/auto/quick/qquicklayouts/data/tst_rowlayout.qml
+++ b/tests/auto/quick/qquicklayouts/data/tst_rowlayout.qml
@@ -1308,6 +1308,53 @@ Item {
compare(rootRect.item1.width, 100)
}
+ //---------------------------
+ // Layout with negative size
+ Component {
+ id: negativeSize_Component
+ Item {
+ id: rootItem
+ width: 0
+ height: 0
+ // default width x height: (0 x 0)
+ RowLayout {
+ spacing: 0
+ anchors.fill: parent
+ anchors.leftMargin: 1 // since parent size == (0 x 0), it causes layout size
+ anchors.bottomMargin: 1 // to become (-1, -1)
+ Item {
+ Layout.fillWidth: true
+ Layout.fillHeight: true
+ }
+ }
+ }
+ }
+
+ function test_negativeSize() {
+ let rootItem = createTemporaryObject(negativeSize_Component, container)
+ let rowLayout = rootItem.children[0]
+ let item = rowLayout.children[0]
+
+ // 1 doesn't work in 6.2 because that will make the layout of size 0x0
+ // Setting the geometry of a layout to 0x0 doesn't work because
+ // QQuickLayout::geometryChange() early returns if !newGeometry.isValid()
+ // This check has been later removed.
+ const arr = [7, /*1,*/ 7, 0]
+ arr.forEach((n) => {
+ rootItem.width = n
+ rootItem.height = n
+
+ // n === 0 is special: It will cause the layout to have a
+ // negative size. In this case it will simply not rearrange its
+ // child (and leave it at its previous size, 6)
+ const expectedItemExtent = n === 0 ? 6 : n - 1
+
+ compare(item.width, expectedItemExtent)
+ compare(item.height, expectedItemExtent)
+ });
+ }
+
+
//---------------------------
Component {
id: rowlayoutWithTextItems_Component
diff --git a/tests/auto/quick/qquicklistview/data/snapToItemWithSectionAtStart.qml b/tests/auto/quick/qquicklistview/data/snapToItemWithSectionAtStart.qml
new file mode 100644
index 0000000000..0d4c233345
--- /dev/null
+++ b/tests/auto/quick/qquicklistview/data/snapToItemWithSectionAtStart.qml
@@ -0,0 +1,52 @@
+import QtQuick
+
+ListView {
+ id: listView
+ width: 240
+ height: 300
+
+ model: ListModel {
+ ListElement { section: "section 1" }
+ ListElement { section: "section 1" }
+ ListElement { section: "section 1" }
+ ListElement { section: "section 2" }
+ ListElement { section: "section 2" }
+ ListElement { section: "section 2" }
+ ListElement { section: "section 3" }
+ ListElement { section: "section 3" }
+ ListElement { section: "section 3" }
+ ListElement { section: "section 4" }
+ ListElement { section: "section 4" }
+ ListElement { section: "section 4" }
+ ListElement { section: "section 5" }
+ ListElement { section: "section 5" }
+ ListElement { section: "section 5" }
+ }
+
+ section.property: "section"
+ section.labelPositioning: ViewSection.InlineLabels | ViewSection.CurrentLabelAtStart
+ section.delegate: Rectangle {
+ width: listView.width
+ height: 30
+ Text {
+ anchors.fill: parent
+ text: section
+ }
+ color: "lightblue"
+ }
+
+ snapMode: ListView.SnapToItem
+
+ delegate: Rectangle {
+ width: listView.width
+ height: 30
+ Text {
+ anchors.fill: parent
+ text: index
+ }
+ border {
+ width: 1
+ color: "black"
+ }
+ }
+}
diff --git a/tests/auto/quick/qquicklistview/tst_qquicklistview.cpp b/tests/auto/quick/qquicklistview/tst_qquicklistview.cpp
index 24196e2ba1..8f3aa551e1 100644
--- a/tests/auto/quick/qquicklistview/tst_qquicklistview.cpp
+++ b/tests/auto/quick/qquicklistview/tst_qquicklistview.cpp
@@ -193,6 +193,7 @@ private slots:
void headerSnapToItem_data();
void headerSnapToItem();
void snapToItemWithSpacing_QTBUG_59852();
+ void snapToItemWithSectionAtStart();
void snapOneItemResize_QTBUG_43555();
void snapOneItem_data();
void snapOneItem();
@@ -5407,6 +5408,27 @@ void tst_QQuickListView::snapToItemWithSpacing_QTBUG_59852()
releaseView(window);
}
+void tst_QQuickListView::snapToItemWithSectionAtStart() // QTBUG-30768
+{
+ QQuickView window;
+ QVERIFY(QQuickTest::showView(window, testFileUrl("snapToItemWithSectionAtStart.qml")));
+ QQuickListView *listView = qobject_cast<QQuickListView *>(window.rootObject());
+ QTRY_VERIFY(listView);
+
+ // Both sections and elements are 30px high. The list height is 300px, so
+ // it fits exactly 10 elements. We can do some random flicks, but the
+ // content position always MUST be divisible by 30.
+ for (int i = 0; i < 10; ++i) {
+ const bool even = (i % 2 == 0);
+ const QPoint start = even ? QPoint(20, 100 + i * 5) : QPoint(20, 20 + i * 3);
+ const QPoint end = even ? start - QPoint(0, 50 + i * 10) : start + QPoint(0, 50 + i * 5);
+
+ flick(&window, start, end, 180);
+ QTRY_COMPARE(listView->isMoving(), false); // wait until it stops
+ QCOMPARE(int(listView->contentY()) % 30, 0);
+ }
+}
+
static void drag_helper(QWindow *window, QPoint *startPos, const QPoint &delta)
{
QPoint pos = *startPos;
diff --git a/tests/auto/quick/qquickmultipointtoucharea/BLACKLIST b/tests/auto/quick/qquickmultipointtoucharea/BLACKLIST
index 2488eff270..46db6477f5 100644
--- a/tests/auto/quick/qquickmultipointtoucharea/BLACKLIST
+++ b/tests/auto/quick/qquickmultipointtoucharea/BLACKLIST
@@ -4,3 +4,5 @@ ubuntu-22.04
[nested]
ubuntu-20.04
ubuntu-22.04
+[inFlickable]
+* # QTBUG-127628
diff --git a/tests/auto/quick/qquicktableview/tst_qquicktableview.cpp b/tests/auto/quick/qquicktableview/tst_qquicktableview.cpp
index 5991621376..5330d8d01f 100644
--- a/tests/auto/quick/qquicktableview/tst_qquicktableview.cpp
+++ b/tests/auto/quick/qquicktableview/tst_qquicktableview.cpp
@@ -185,6 +185,8 @@ private slots:
void checkSyncView_pageFlicking();
void checkSyncView_emptyModel();
void checkSyncView_topLeftChanged();
+ void checkSyncView_dontRelayoutWhileFlicking();
+ void checkSyncView_detectTopLeftPositionChanged();
void delegateWithRequiredProperties();
void checkThatFetchMoreIsCalledWhenScrolledToTheEndOfTable();
void replaceModel();
@@ -3108,6 +3110,85 @@ void tst_QQuickTableView::checkSyncView_topLeftChanged()
QCOMPARE(tableViewV->topRow(), tableView->topRow());
}
+void tst_QQuickTableView::checkSyncView_dontRelayoutWhileFlicking()
+{
+ // Check that we don't do a full relayout in a sync child when
+ // a new row or column is flicked into the view. Normal load
+ // and unload of edges should suffice, equal to how the main
+ // TableView (syncView) does it.
+ LOAD_TABLEVIEW("syncviewsimple.qml");
+ GET_QML_TABLEVIEW(tableViewHV);
+
+ auto model = TestModelAsVariant(100, 100);
+ tableView->setModel(model);
+ tableViewHV->setModel(model);
+
+ tableView->setColumnWidthProvider(QJSValue());
+ tableView->setRowHeightProvider(QJSValue());
+ view->rootObject()->setProperty("delegateWidth", 50);
+ view->rootObject()->setProperty("delegateHeight", 50);
+
+ WAIT_UNTIL_POLISHED;
+
+ // To check that we don't do a relayout when flicking horizontally, we use a "trick"
+ // where we check the rebuildOptions when we receive the rightColumnChanged
+ // signal. If this signal is emitted as a part of a relayout, rebuildOptions
+ // would still be different from RebuildOption::None at that point.
+ bool columnFlickedIn = false;
+ connect(tableViewHV, &QQuickTableView::rightColumnChanged, [&] {
+ columnFlickedIn = true;
+ QCOMPARE(tableViewHVPrivate->rebuildOptions, QQuickTableViewPrivate::RebuildOption::None);
+ });
+
+ // We do the same for vertical flicking
+ bool rowFlickedIn = false;
+ connect(tableViewHV, &QQuickTableView::bottomRowChanged, [&] {
+ rowFlickedIn = true;
+ QCOMPARE(tableViewHVPrivate->rebuildOptions, QQuickTableViewPrivate::RebuildOption::None);
+ });
+
+ // Move the main tableview so that a new column is flicked in
+ tableView->setContentX(60);
+ QTRY_VERIFY(columnFlickedIn);
+
+ // Move the main tableview so that a new row is flicked in
+ tableView->setContentY(60);
+ QTRY_VERIFY(rowFlickedIn);
+}
+
+void tst_QQuickTableView::checkSyncView_detectTopLeftPositionChanged()
+{
+ // It can happen that, during a resize of columns or rows from using a float-based
+ // slider, that the position of the top-left delegate item is shifted a bit left or
+ // right because of rounding issues. And this again can over time, as you flick, make
+ // the loadedTableOuterRect get slightly out of sync in the sync child compared to the
+ // sync view. TableView will detect if this happens (in syncSyncView), and correct for
+ // it. And this test will test that it works.
+ LOAD_TABLEVIEW("syncviewsimple.qml");
+ GET_QML_TABLEVIEW(tableViewHV);
+
+ auto model = TestModelAsVariant(100, 100);
+ tableView->setModel(model);
+ tableViewHV->setModel(model);
+
+ WAIT_UNTIL_POLISHED;
+
+ // Writing an auto test to trigger this rounding issue is very hard. So to keep it
+ // simple, we cheat by just moving the loadedTableOuterRect directly, and
+ // check that the syncView child detects it, and corrects it, upon doing a
+ // forceLayout()
+ tableViewPrivate->loadedTableOuterRect.moveLeft(20);
+ tableViewPrivate->loadedTableOuterRect.moveTop(30);
+ tableViewPrivate->relayoutTableItems();
+ tableViewHV->forceLayout();
+
+ QCOMPARE(tableViewPrivate->loadedTableOuterRect.left(), 20);
+ QCOMPARE(tableViewHVPrivate->loadedTableOuterRect.left(), 20);
+
+ QCOMPARE(tableViewPrivate->loadedTableOuterRect.top(), 30);
+ QCOMPARE(tableViewHVPrivate->loadedTableOuterRect.top(), 30);
+}
+
void tst_QQuickTableView::checkThatFetchMoreIsCalledWhenScrolledToTheEndOfTable()
{
LOAD_TABLEVIEW("plaintableview.qml");
diff --git a/tests/auto/quick/qquicktext/data/elideZeroWidthWithMargins.qml b/tests/auto/quick/qquicktext/data/elideZeroWidthWithMargins.qml
new file mode 100644
index 0000000000..bb269e6ad5
--- /dev/null
+++ b/tests/auto/quick/qquicktext/data/elideZeroWidthWithMargins.qml
@@ -0,0 +1,27 @@
+import QtQuick
+
+Item {
+ id: root
+ property bool ok: false
+ width: 640
+ height: 480
+
+ Text {
+ id: text
+ text: "This is a quite long text. Click me and i should remain visible!!! Sadly this doesn't happen"
+ elide: Text.ElideRight
+ anchors {
+ fill: parent
+ margins: 1
+ }
+ }
+
+ Component.onCompleted: {
+ text.width = 300;
+ text.height = 0;
+ text.width = 0;
+ text.height = 30;
+ text.width = 300;
+ root.ok = text.paintedWidth > 0 && text.paintedHeight > 0
+ }
+}
diff --git a/tests/auto/quick/qquicktext/tst_qquicktext.cpp b/tests/auto/quick/qquicktext/tst_qquicktext.cpp
index 476297918d..ea90fc74d6 100644
--- a/tests/auto/quick/qquicktext/tst_qquicktext.cpp
+++ b/tests/auto/quick/qquicktext/tst_qquicktext.cpp
@@ -69,6 +69,7 @@ private slots:
void wrap();
void elide();
void elideParentChanged();
+ void elideRelayoutAfterZeroWidth_data();
void elideRelayoutAfterZeroWidth();
void multilineElide_data();
void multilineElide();
@@ -611,10 +612,19 @@ void tst_qquicktext::elideParentChanged()
QCOMPARE(actualItemImageGrab, expectedItemImageGrab);
}
+void tst_qquicktext::elideRelayoutAfterZeroWidth_data()
+{
+ QTest::addColumn<QByteArray>("fileName");
+
+ QTest::newRow("no_margins") << QByteArray("elideZeroWidth.qml");
+ QTest::newRow("with_margins") << QByteArray("elideZeroWidthWithMargins.qml");
+}
+
void tst_qquicktext::elideRelayoutAfterZeroWidth()
{
+ QFETCH(const QByteArray, fileName);
QQmlEngine engine;
- QQmlComponent component(&engine, testFileUrl("elideZeroWidth.qml"));
+ QQmlComponent component(&engine, testFileUrl(fileName.constData()));
QScopedPointer<QObject> root(component.create());
QVERIFY2(root, qPrintable(component.errorString()));
QVERIFY(root->property("ok").toBool());
diff --git a/tests/auto/quickcontrols2/controls/data/tst_control.qml b/tests/auto/quickcontrols2/controls/data/tst_control.qml
index e12cbbf4ef..5103d9afd4 100644
--- a/tests/auto/quickcontrols2/controls/data/tst_control.qml
+++ b/tests/auto/quickcontrols2/controls/data/tst_control.qml
@@ -503,6 +503,36 @@ TestCase {
}
Component {
+ id: backgroundTest2
+ Button {
+ id: btn
+ width: 100
+ height: 100
+ topInset: 0
+ objectName: ""
+
+ background: Rectangle {
+ id: bg
+ implicitHeight: 80
+ border.color: "red"
+ y: btn.objectName === "aaa" ? 20 : 0
+ }
+ }
+ }
+
+ // QTBUG-120033: Make sure that the binding for y on the tab button's background doesn't get removed
+ function test_background2() {
+ let button = createTemporaryObject(backgroundTest2, testCase)
+ verify(button)
+
+ verify(button.background.y === 0)
+ button.objectName = "aaa"
+ verify(button.background.y === 20)
+ button.objectName = ""
+ verify(button.background.y === 0)
+ }
+
+ Component {
id: component2
T.Control {
id: item2
diff --git a/tests/auto/quickcontrols2/qquickpopup/data/resetHoveredForItemsWithinOverlay.qml b/tests/auto/quickcontrols2/qquickpopup/data/resetHoveredForItemsWithinOverlay.qml
new file mode 100644
index 0000000000..a7e66718ee
--- /dev/null
+++ b/tests/auto/quickcontrols2/qquickpopup/data/resetHoveredForItemsWithinOverlay.qml
@@ -0,0 +1,28 @@
+import QtQuick
+import QtQuick.Controls
+
+ApplicationWindow {
+ id: root
+ width: 100
+ height: 100
+ property alias controlsPopup: _controlsPopup
+ property alias blockInputPopup: _blockInputPopup
+ Popup {
+ id: _controlsPopup
+ width: parent.width
+ height: parent.height
+ modal: true
+ Control {
+ id: controls
+ anchors.fill: parent
+ hoverEnabled: true
+ contentItem: Text { text: "Test Control" }
+ }
+ }
+ Popup {
+ id: _blockInputPopup
+ width: parent.width
+ height: parent.height
+ modal: true
+ }
+}
diff --git a/tests/auto/quickcontrols2/qquickpopup/tst_qquickpopup.cpp b/tests/auto/quickcontrols2/qquickpopup/tst_qquickpopup.cpp
index a587c085a4..2895ac4a83 100644
--- a/tests/auto/quickcontrols2/qquickpopup/tst_qquickpopup.cpp
+++ b/tests/auto/quickcontrols2/qquickpopup/tst_qquickpopup.cpp
@@ -121,6 +121,7 @@ private slots:
void shrinkPopupThatWasLargerThanWindow();
void mirroredCombobox();
void rotatedCombobox();
+ void resetHoveredStateForItemsWithinPopup();
private:
static bool hasWindowActivation();
@@ -2038,6 +2039,40 @@ void tst_QQuickPopup::rotatedCombobox()
}
}
+void tst_QQuickPopup::resetHoveredStateForItemsWithinPopup()
+{
+ QQuickControlsApplicationHelper helper(this, "resetHoveredForItemsWithinOverlay.qml");
+ QVERIFY2(helper.ready, helper.failureMessage());
+
+ QQuickWindow *window = helper.window;
+ window->show();
+ QVERIFY(QTest::qWaitForWindowExposed(window));
+
+ QQuickPopup *controlsPopup = window->property("controlsPopup").value<QQuickPopup*>();
+ QVERIFY(controlsPopup);
+
+ QQuickPopup *blockInputPopup = window->property("blockInputPopup").value<QQuickPopup*>();
+ QVERIFY(controlsPopup);
+
+ controlsPopup->open();
+ QTRY_VERIFY(controlsPopup->isOpened());
+
+ QTest::mouseMove(window, QPoint(window->width() / 2 + 2, window->height() / 2 + 2));
+ QTest::mouseMove(window, QPoint(window->width() / 2, window->height() / 2));
+
+ auto *controlItem = qobject_cast<QQuickControl *>(controlsPopup->contentItem()->childItems().at(0));
+ QVERIFY(controlItem);
+ // Check hover enabled for the control item within the popup
+ QTRY_VERIFY(controlItem->isHovered());
+
+ // Open the modal popup window over the existing control item
+ blockInputPopup->open();
+ QTRY_VERIFY(blockInputPopup->isOpened());
+
+ // Control item hovered shall be disabled once we open the modal popup
+ QTRY_VERIFY(!controlItem->isHovered());
+}
+
QTEST_QUICKCONTROLS_MAIN(tst_QQuickPopup)
#include "tst_qquickpopup.moc"
diff --git a/tests/auto/quickwidgets/qquickwidget/tst_qquickwidget.cpp b/tests/auto/quickwidgets/qquickwidget/tst_qquickwidget.cpp
index 54673b70ce..f0bfd3c79c 100644
--- a/tests/auto/quickwidgets/qquickwidget/tst_qquickwidget.cpp
+++ b/tests/auto/quickwidgets/qquickwidget/tst_qquickwidget.cpp
@@ -711,6 +711,9 @@ void tst_qquickwidget::touchMultipleWidgets()
QWidget window;
QQuickWidget *leftQuick = new QQuickWidget;
leftQuick->setSource(testFileUrl("button.qml"));
+ if (!leftQuick->testAttribute(Qt::WA_AcceptTouchEvents))
+ QSKIP("irrelevant on non-touch platforms");
+
QQuickWidget *rightQuick = new QQuickWidget;
rightQuick->setSource(testFileUrl("button.qml"));