diff options
author | Tarja Sundqvist <[email protected]> | 2024-11-22 10:46:11 +0200 |
---|---|---|
committer | Tarja Sundqvist <[email protected]> | 2024-11-22 10:46:11 +0200 |
commit | 64364dbe06b46e5f355c3b2a6684a3eae4f54a7a (patch) | |
tree | b501b88601bbda604da2adac9307c47b6d3733b2 /tests/auto | |
parent | 6b64e58767c6dd32a29a261e3327fa88b5613621 (diff) | |
parent | 4d94cd012575956a7633fc19d87059f7a8e0dda2 (diff) |
Merge tag 'v6.2.11-lts' into tqtc/lts-6.2-opensource
Qt 6.2.11-lts release
Conflicts solved:
dependencies.yaml
Change-Id: I088fe99748b323fbdf49c3766c262eb2a05131d9
Diffstat (limited to 'tests/auto')
31 files changed, 1394 insertions, 32 deletions
diff --git a/tests/auto/qml/debugger/qv4debugger/data/breakPointInJSModule.qml b/tests/auto/qml/debugger/qv4debugger/data/breakPointInJSModule.qml new file mode 100644 index 0000000000..2582a23ec5 --- /dev/null +++ b/tests/auto/qml/debugger/qv4debugger/data/breakPointInJSModule.qml @@ -0,0 +1,4 @@ +import QtQml 2.15 +import "module1.js" as Module1 + +QtObject {} diff --git a/tests/auto/qml/debugger/qv4debugger/data/module1.js b/tests/auto/qml/debugger/qv4debugger/data/module1.js new file mode 100644 index 0000000000..9ce1f1e6b1 --- /dev/null +++ b/tests/auto/qml/debugger/qv4debugger/data/module1.js @@ -0,0 +1,5 @@ +.pragma library + +.import "module2.mjs" as Module2 + +Module2.crashMe(); diff --git a/tests/auto/qml/debugger/qv4debugger/data/module2.mjs b/tests/auto/qml/debugger/qv4debugger/data/module2.mjs new file mode 100644 index 0000000000..80f82af953 --- /dev/null +++ b/tests/auto/qml/debugger/qv4debugger/data/module2.mjs @@ -0,0 +1,7 @@ +import * as Module3 from "module3.mjs" +import * as Module4 from "module4.mjs" + +export function crashMe() +{ + console.log("Hello world!"); +} diff --git a/tests/auto/qml/debugger/qv4debugger/data/module3.mjs b/tests/auto/qml/debugger/qv4debugger/data/module3.mjs new file mode 100644 index 0000000000..e69de29bb2 --- /dev/null +++ b/tests/auto/qml/debugger/qv4debugger/data/module3.mjs diff --git a/tests/auto/qml/debugger/qv4debugger/data/module4.mjs b/tests/auto/qml/debugger/qv4debugger/data/module4.mjs new file mode 100644 index 0000000000..e69de29bb2 --- /dev/null +++ b/tests/auto/qml/debugger/qv4debugger/data/module4.mjs diff --git a/tests/auto/qml/debugger/qv4debugger/tst_qv4debugger.cpp b/tests/auto/qml/debugger/qv4debugger/tst_qv4debugger.cpp index b9b2fd6b69..331d978dd7 100644 --- a/tests/auto/qml/debugger/qv4debugger/tst_qv4debugger.cpp +++ b/tests/auto/qml/debugger/qv4debugger/tst_qv4debugger.cpp @@ -241,10 +241,14 @@ public: QJsonArray scopes = frameObj.value(QLatin1String("scopes")).toArray(); int nscopes = scopes.size(); int s = 0; - for (s = 0; s < nscopes; ++s) { - QJsonObject o = scopes.at(s).toObject(); - if (o.value(QLatin1String("type")).toInt(-2) == 1) // CallContext - break; + if (m_targetScope != -1) { + s = m_targetScope; + } else { + for (s = 0; s < nscopes; ++s) { + QJsonObject o = scopes.at(s).toObject(); + if (o.value(QLatin1String("type")).toInt(-2) == 1) // CallContext + break; + } } if (s == nscopes) return; @@ -274,6 +278,7 @@ public: bool m_wasPaused; QV4Debugger::PauseReason m_pauseReason; bool m_captureContextInfo; + int m_targetScope = -1; QList<QV4Debugger::ExecutionState> m_statesWhenPaused; QList<TestBreakPoint> m_breakPointsToAddWhenPaused; QVector<QV4::StackFrame> m_stackTrace; @@ -347,6 +352,9 @@ private slots: void readThis(); void signalParameters(); void debuggerNoCrash(); + + void breakPointInJSModule(); + private: QV4Debugger *debugger() const { @@ -992,6 +1000,35 @@ void tst_qv4debugger::debuggerNoCrash() debugThread->wait(); } +void tst_qv4debugger::breakPointInJSModule() +{ + QQmlEngine engine; + QV4::ExecutionEngine *v4 = engine.handle(); + QPointer<QV4Debugger> v4Debugger = new QV4Debugger(v4); + v4->setDebugger(v4Debugger.data()); + + QScopedPointer<QThread> debugThread(new QThread); + debugThread->start(); + QScopedPointer<TestAgent> debuggerAgent(new TestAgent(v4)); + debuggerAgent->addDebugger(v4Debugger); + debuggerAgent->moveToThread(debugThread.data()); + + QQmlComponent component(&engine, testFileUrl("breakPointInJSModule.qml")); + QVERIFY2(component.isReady(), qPrintable(component.errorString())); + + debuggerAgent->m_captureContextInfo = true; + debuggerAgent->m_targetScope = 1; + v4Debugger->addBreakPoint("module2.mjs", 6); + + QScopedPointer<QObject> obj(component.create()); + QVERIFY(!obj.isNull()); + + QVERIFY(!debuggerAgent->m_capturedScope.isEmpty()); + + debugThread->quit(); + debugThread->wait(); +} + tst_qv4debugger::tst_qv4debugger() : QQmlDataTest(QT_QMLTEST_DATADIR) { } QTEST_MAIN(tst_qv4debugger) diff --git a/tests/auto/qml/qjsengine/tst_qjsengine.cpp b/tests/auto/qml/qjsengine/tst_qjsengine.cpp index 81ac086294..7883ca721d 100644 --- a/tests/auto/qml/qjsengine/tst_qjsengine.cpp +++ b/tests/auto/qml/qjsengine/tst_qjsengine.cpp @@ -43,6 +43,7 @@ #include <QScopeGuard> #include <QUrl> #include <QModelIndex> +#include <QtQml/qqmllist.h> #ifdef Q_CC_MSVC #define NO_INLINE __declspec(noinline) @@ -1658,6 +1659,13 @@ void tst_QJSEngine::valueConversion_basic() QCOMPARE(eng.fromScriptValue<QChar>(eng.toScriptValue(c)), c); } + { + QList<QObject *> list = {this}; + QQmlListProperty<QObject> prop(this, &list); + QJSValue jsVal = eng.toScriptValue(prop); + QCOMPARE(eng.fromScriptValue<QQmlListProperty<QObject>>(jsVal), prop); + } + QVERIFY(eng.toScriptValue(static_cast<void *>(nullptr)).isNull()); } diff --git a/tests/auto/qml/qmlcachegen/data/truncateTest.qml b/tests/auto/qml/qmlcachegen/data/truncateTest.qml new file mode 100644 index 0000000000..fee768cf77 --- /dev/null +++ b/tests/auto/qml/qmlcachegen/data/truncateTest.qml @@ -0,0 +1,764 @@ +import QtQuick 2.15 +import QtQuick.Layouts 2.15 + +Item { + width: 400 + height: 400 + + component Button : Item { + property string text + property Item background + } + + ColumnLayout { + Button { + text: "A Special Button" + background: Rectangle { + implicitWidth: 100 + implicitHeight: 40 + color: "red" + border.color: "#26282a" + border.width: 1 + radius: 4 + } + } + Button { + text: "A Special Button" + background: Rectangle { + implicitWidth: 100 + implicitHeight: 40 + color: "red" + border.color: "#26282a" + border.width: 1 + radius: 4 + } + } + Button { + text: "A Special Button" + background: Rectangle { + implicitWidth: 100 + implicitHeight: 40 + color: "red" + border.color: "#26282a" + border.width: 1 + radius: 4 + } + } + Button { + text: "A Special Button" + background: Rectangle { + implicitWidth: 100 + implicitHeight: 40 + color: "red" + border.color: "#26282a" + border.width: 1 + radius: 4 + } + } + Button { + text: "A Special Button" + background: Rectangle { + implicitWidth: 100 + implicitHeight: 40 + color: "red" + border.color: "#26282a" + border.width: 1 + radius: 4 + } + } + Button { + text: "A Special Button" + background: Rectangle { + implicitWidth: 100 + implicitHeight: 40 + color: "red" + border.color: "#26282a" + border.width: 1 + radius: 4 + } + } + Button { + text: "A Special Button" + background: Rectangle { + implicitWidth: 100 + implicitHeight: 40 + color: "red" + border.color: "#26282a" + border.width: 1 + radius: 4 + } + } + Button { + text: "A Special Button" + background: Rectangle { + implicitWidth: 100 + implicitHeight: 40 + color: "red" + border.color: "#26282a" + border.width: 1 + radius: 4 + } + } + Button { + text: "A Special Button" + background: Rectangle { + implicitWidth: 100 + implicitHeight: 40 + color: "red" + border.color: "#26282a" + border.width: 1 + radius: 4 + } + } + Button { + text: "A Special Button" + background: Rectangle { + implicitWidth: 100 + implicitHeight: 40 + color: "red" + border.color: "#26282a" + border.width: 1 + radius: 4 + } + } + Button { + text: "A Special Button" + background: Rectangle { + implicitWidth: 100 + implicitHeight: 40 + color: "red" + border.color: "#26282a" + border.width: 1 + radius: 4 + } + } + Button { + text: "A Special Button" + background: Rectangle { + implicitWidth: 100 + implicitHeight: 40 + color: "red" + border.color: "#26282a" + border.width: 1 + radius: 4 + } + } + Button { + text: "A Special Button" + background: Rectangle { + implicitWidth: 100 + implicitHeight: 40 + color: "red" + border.color: "#26282a" + border.width: 1 + radius: 4 + } + } + Button { + text: "A Special Button" + background: Rectangle { + implicitWidth: 100 + implicitHeight: 40 + color: "red" + border.color: "#26282a" + border.width: 1 + radius: 4 + } + } + Button { + text: "A Special Button" + background: Rectangle { + implicitWidth: 100 + implicitHeight: 40 + color: "red" + border.color: "#26282a" + border.width: 1 + radius: 4 + } + } + Button { + text: "A Special Button" + background: Rectangle { + implicitWidth: 100 + implicitHeight: 40 + color: "red" + border.color: "#26282a" + border.width: 1 + radius: 4 + } + } + Button { + text: "A Special Button" + background: Rectangle { + implicitWidth: 100 + implicitHeight: 40 + color: "red" + border.color: "#26282a" + border.width: 1 + radius: 4 + } + } + Button { + text: "A Special Button" + background: Rectangle { + implicitWidth: 100 + implicitHeight: 40 + color: "red" + border.color: "#26282a" + border.width: 1 + radius: 4 + } + } + Button { + text: "A Special Button" + background: Rectangle { + implicitWidth: 100 + implicitHeight: 40 + color: "red" + border.color: "#26282a" + border.width: 1 + radius: 4 + } + } + Button { + text: "A Special Button" + background: Rectangle { + implicitWidth: 100 + implicitHeight: 40 + color: "red" + border.color: "#26282a" + border.width: 1 + radius: 4 + } + } + Button { + text: "A Special Button" + background: Rectangle { + implicitWidth: 100 + implicitHeight: 40 + color: "red" + border.color: "#26282a" + border.width: 1 + radius: 4 + } + } + Button { + text: "A Special Button" + background: Rectangle { + implicitWidth: 100 + implicitHeight: 40 + color: "red" + border.color: "#26282a" + border.width: 1 + radius: 4 + } + } + Button { + text: "A Special Button" + background: Rectangle { + implicitWidth: 100 + implicitHeight: 40 + color: "red" + border.color: "#26282a" + border.width: 1 + radius: 4 + } + } + Button { + text: "A Special Button" + background: Rectangle { + implicitWidth: 100 + implicitHeight: 40 + color: "red" + border.color: "#26282a" + border.width: 1 + radius: 4 + } + } + Button { + text: "A Special Button" + background: Rectangle { + implicitWidth: 100 + implicitHeight: 40 + color: "red" + border.color: "#26282a" + border.width: 1 + radius: 4 + } + } + Button { + text: "A Special Button" + background: Rectangle { + implicitWidth: 100 + implicitHeight: 40 + color: "red" + border.color: "#26282a" + border.width: 1 + radius: 4 + } + } + Button { + text: "A Special Button" + background: Rectangle { + implicitWidth: 100 + implicitHeight: 40 + color: "red" + border.color: "#26282a" + border.width: 1 + radius: 4 + } + } + Button { + text: "A Special Button" + background: Rectangle { + implicitWidth: 100 + implicitHeight: 40 + color: "red" + border.color: "#26282a" + border.width: 1 + radius: 4 + } + } + Button { + text: "A Special Button" + background: Rectangle { + implicitWidth: 100 + implicitHeight: 40 + color: "red" + border.color: "#26282a" + border.width: 1 + radius: 4 + } + } + Button { + text: "A Special Button" + background: Rectangle { + implicitWidth: 100 + implicitHeight: 40 + color: "red" + border.color: "#26282a" + border.width: 1 + radius: 4 + } + } + Button { + text: "A Special Button" + background: Rectangle { + implicitWidth: 100 + implicitHeight: 40 + color: "red" + border.color: "#26282a" + border.width: 1 + radius: 4 + } + } + Button { + text: "A Special Button" + background: Rectangle { + implicitWidth: 100 + implicitHeight: 40 + color: "red" + border.color: "#26282a" + border.width: 1 + radius: 4 + } + } + Button { + text: "A Special Button" + background: Rectangle { + implicitWidth: 100 + implicitHeight: 40 + color: "red" + border.color: "#26282a" + border.width: 1 + radius: 4 + } + } + Button { + text: "A Special Button" + background: Rectangle { + implicitWidth: 100 + implicitHeight: 40 + color: "red" + border.color: "#26282a" + border.width: 1 + radius: 4 + } + } + Button { + text: "A Special Button" + background: Rectangle { + implicitWidth: 100 + implicitHeight: 40 + color: "red" + border.color: "#26282a" + border.width: 1 + radius: 4 + } + } + Button { + text: "A Special Button" + background: Rectangle { + implicitWidth: 100 + implicitHeight: 40 + color: "red" + border.color: "#26282a" + border.width: 1 + radius: 4 + } + } + Button { + text: "A Special Button" + background: Rectangle { + implicitWidth: 100 + implicitHeight: 40 + color: "red" + border.color: "#26282a" + border.width: 1 + radius: 4 + } + } + Button { + text: "A Special Button" + background: Rectangle { + implicitWidth: 100 + implicitHeight: 40 + color: "red" + border.color: "#26282a" + border.width: 1 + radius: 4 + } + } + Button { + text: "A Special Button" + background: Rectangle { + implicitWidth: 100 + implicitHeight: 40 + color: "red" + border.color: "#26282a" + border.width: 1 + radius: 4 + } + } + Button { + text: "A Special Button" + background: Rectangle { + implicitWidth: 100 + implicitHeight: 40 + color: "red" + border.color: "#26282a" + border.width: 1 + radius: 4 + } + } + Button { + text: "A Special Button" + background: Rectangle { + implicitWidth: 100 + implicitHeight: 40 + color: "red" + border.color: "#26282a" + border.width: 1 + radius: 4 + } + } + Button { + text: "A Special Button" + background: Rectangle { + implicitWidth: 100 + implicitHeight: 40 + color: "red" + border.color: "#26282a" + border.width: 1 + radius: 4 + } + } + Button { + text: "A Special Button" + background: Rectangle { + implicitWidth: 100 + implicitHeight: 40 + color: "red" + border.color: "#26282a" + border.width: 1 + radius: 4 + } + } + Button { + text: "A Special Button" + background: Rectangle { + implicitWidth: 100 + implicitHeight: 40 + color: "red" + border.color: "#26282a" + border.width: 1 + radius: 4 + } + } + Button { + text: "A Special Button" + background: Rectangle { + implicitWidth: 100 + implicitHeight: 40 + color: "red" + border.color: "#26282a" + border.width: 1 + radius: 4 + } + } + Button { + text: "A Special Button" + background: Rectangle { + implicitWidth: 100 + implicitHeight: 40 + color: "red" + border.color: "#26282a" + border.width: 1 + radius: 4 + } + } + Button { + text: "A Special Button" + background: Rectangle { + implicitWidth: 100 + implicitHeight: 40 + color: "red" + border.color: "#26282a" + border.width: 1 + radius: 4 + } + } + Button { + text: "A Special Button" + background: Rectangle { + implicitWidth: 100 + implicitHeight: 40 + color: "red" + border.color: "#26282a" + border.width: 1 + radius: 4 + } + } + Button { + text: "A Special Button" + background: Rectangle { + implicitWidth: 100 + implicitHeight: 40 + color: "red" + border.color: "#26282a" + border.width: 1 + radius: 4 + } + } + Button { + text: "A Special Button" + background: Rectangle { + implicitWidth: 100 + implicitHeight: 40 + color: "red" + border.color: "#26282a" + border.width: 1 + radius: 4 + } + } + Button { + text: "A Special Button" + background: Rectangle { + implicitWidth: 100 + implicitHeight: 40 + color: "red" + border.color: "#26282a" + border.width: 1 + radius: 4 + } + } + Button { + text: "A Special Button" + background: Rectangle { + implicitWidth: 100 + implicitHeight: 40 + color: "red" + border.color: "#26282a" + border.width: 1 + radius: 4 + } + } + Button { + text: "A Special Button" + background: Rectangle { + implicitWidth: 100 + implicitHeight: 40 + color: "red" + border.color: "#26282a" + border.width: 1 + radius: 4 + } + } + Button { + text: "A Special Button" + background: Rectangle { + implicitWidth: 100 + implicitHeight: 40 + color: "red" + border.color: "#26282a" + border.width: 1 + radius: 4 + } + } + Button { + text: "A Special Button" + background: Rectangle { + implicitWidth: 100 + implicitHeight: 40 + color: "red" + border.color: "#26282a" + border.width: 1 + radius: 4 + } + } + Button { + text: "A Special Button" + background: Rectangle { + implicitWidth: 100 + implicitHeight: 40 + color: "red" + border.color: "#26282a" + border.width: 1 + radius: 4 + } + } + Button { + text: "A Special Button" + background: Rectangle { + implicitWidth: 100 + implicitHeight: 40 + color: "red" + border.color: "#26282a" + border.width: 1 + radius: 4 + } + } + Button { + text: "A Special Button" + background: Rectangle { + implicitWidth: 100 + implicitHeight: 40 + color: "red" + border.color: "#26282a" + border.width: 1 + radius: 4 + } + } + Button { + text: "A Special Button" + background: Rectangle { + implicitWidth: 100 + implicitHeight: 40 + color: "red" + border.color: "#26282a" + border.width: 1 + radius: 4 + } + } + Button { + text: "A Special Button" + background: Rectangle { + implicitWidth: 100 + implicitHeight: 40 + color: "red" + border.color: "#26282a" + border.width: 1 + radius: 4 + } + } + Button { + text: "A Special Button" + background: Rectangle { + implicitWidth: 100 + implicitHeight: 40 + color: "red" + border.color: "#26282a" + border.width: 1 + radius: 4 + } + } + Button { + text: "A Special Button" + background: Rectangle { + implicitWidth: 100 + implicitHeight: 40 + color: "red" + border.color: "#26282a" + border.width: 1 + radius: 4 + } + } + Button { + text: "A Special Button" + background: Rectangle { + implicitWidth: 100 + implicitHeight: 40 + color: "red" + border.color: "#26282a" + border.width: 1 + radius: 4 + } + } + Button { + text: "A Special Button" + background: Rectangle { + implicitWidth: 100 + implicitHeight: 40 + color: "red" + border.color: "#26282a" + border.width: 1 + radius: 4 + } + } + Button { + text: "A Special Button" + background: Rectangle { + implicitWidth: 100 + implicitHeight: 40 + color: "red" + border.color: "#26282a" + border.width: 1 + radius: 4 + } + } + Button { + text: "A Special Button" + background: Rectangle { + implicitWidth: 100 + implicitHeight: 40 + color: "red" + border.color: "#26282a" + border.width: 1 + radius: 4 + } + } + Button { + text: "A Special Button" + background: Rectangle { + implicitWidth: 100 + implicitHeight: 40 + color: "red" + border.color: "#26282a" + border.width: 1 + radius: 4 + } + } + Button { + text: "A Special Button" + background: Rectangle { + implicitWidth: 100 + implicitHeight: 40 + color: "red" + border.color: "#26282a" + border.width: 1 + radius: 4 + } + } + + } +} diff --git a/tests/auto/qml/qmlcachegen/tst_qmlcachegen.cpp b/tests/auto/qml/qmlcachegen/tst_qmlcachegen.cpp index a2639bc532..f235bbe557 100644 --- a/tests/auto/qml/qmlcachegen/tst_qmlcachegen.cpp +++ b/tests/auto/qml/qmlcachegen/tst_qmlcachegen.cpp @@ -86,6 +86,8 @@ private slots: void inlineComponent(); void posthocRequired(); + void gracefullyHandleTruncatedCacheFile(); + void scriptStringCachegenInteraction(); void saveableUnitPointer(); }; @@ -782,6 +784,23 @@ void tst_qmlcachegen::posthocRequired() QVERIFY(component.errorString().contains(QStringLiteral("Required property x was not initialized"))); } +void tst_qmlcachegen::gracefullyHandleTruncatedCacheFile() +{ +#if defined(QTEST_CROSS_COMPILED) + QSKIP("Cannot call qmlcachegen on cross-compiled target."); +#endif + + bool ok = generateCache(testFile("truncateTest.qml")); + QVERIFY(ok); + const QString qmlcFile = testFile("truncateTest.qmlc"); + QVERIFY(QFile::exists(qmlcFile)); + QFile::resize(qmlcFile, QFileInfo(qmlcFile).size() / 2); + QQmlEngine engine; + CleanlyLoadingComponent component(&engine, testFileUrl("truncateTest.qml")); + QScopedPointer<QObject> obj(component.create()); + QVERIFY(!obj.isNull()); +} + void tst_qmlcachegen::scriptStringCachegenInteraction() { #if defined(QTEST_CROSS_COMPILED) diff --git a/tests/auto/qml/qqmlecmascript/data/methodCallOnDerivedSingleton.qml b/tests/auto/qml/qqmlecmascript/data/methodCallOnDerivedSingleton.qml new file mode 100644 index 0000000000..9d2ee433fd --- /dev/null +++ b/tests/auto/qml/qqmlecmascript/data/methodCallOnDerivedSingleton.qml @@ -0,0 +1,6 @@ +import Qt.test +import QtQml + +QtObject { + Component.onCompleted: SingletonInheritanceTest.trackPage("test", {x: 42}) +} diff --git a/tests/auto/qml/qqmlecmascript/testtypes.cpp b/tests/auto/qml/qqmlecmascript/testtypes.cpp index cd83702d3a..803e09a2e9 100644 --- a/tests/auto/qml/qqmlecmascript/testtypes.cpp +++ b/tests/auto/qml/qqmlecmascript/testtypes.cpp @@ -561,6 +561,8 @@ void registerTypes() qmlRegisterType<Receiver>("Qt.test", 1,0, "Receiver"); qmlRegisterType<Sender>("Qt.test", 1,0, "Sender"); qmlRegisterTypesAndRevisions<ReadOnlyBindable>("Qt.test", 1); + + qmlRegisterTypesAndRevisions<SingletonRegistrationWrapper>("Qt.test", 1); } #include "testtypes.moc" diff --git a/tests/auto/qml/qqmlecmascript/testtypes.h b/tests/auto/qml/qqmlecmascript/testtypes.h index a3df73972e..622d7c44c8 100644 --- a/tests/auto/qml/qqmlecmascript/testtypes.h +++ b/tests/auto/qml/qqmlecmascript/testtypes.h @@ -1892,6 +1892,42 @@ public: QBindable<int> bindableX() const { return &_xProp; } }; +class SingletonBase : public QObject { + Q_OBJECT + +public: + Q_INVOKABLE virtual void trackPage(const QString&) {} + Q_INVOKABLE virtual void trackPage(const QString&, const QVariantMap&) {} + + bool m_okay = false; +}; + +class SingletonImpl : public SingletonBase { + Q_OBJECT + +public: + Q_INVOKABLE virtual void trackPage(const QString&) override {} + Q_INVOKABLE virtual void trackPage(const QString&, const QVariantMap&) override + { + m_okay = true; + } +}; + +class SingletonRegistrationWrapper { + Q_GADGET + QML_FOREIGN(SingletonBase) + QML_NAMED_ELEMENT(SingletonInheritanceTest) + QML_SINGLETON + +public: + static SingletonBase* create(QQmlEngine*, QJSEngine*) { + return new SingletonImpl(); + } + +private: + SingletonRegistrationWrapper() = default; +}; + void registerTypes(); #endif // TESTTYPES_H diff --git a/tests/auto/qml/qqmlecmascript/tst_qqmlecmascript.cpp b/tests/auto/qml/qqmlecmascript/tst_qqmlecmascript.cpp index e976ec46a3..c30c4de825 100644 --- a/tests/auto/qml/qqmlecmascript/tst_qqmlecmascript.cpp +++ b/tests/auto/qml/qqmlecmascript/tst_qqmlecmascript.cpp @@ -437,6 +437,8 @@ private slots: void doNotCrashOnReadOnlyBindable(); + + void methodCallOnDerivedSingleton(); private: // static void propertyVarWeakRefCallback(v8::Persistent<v8::Value> object, void* parameter); static void verifyContextLifetime(const QQmlRefPointer<QQmlContextData> &ctxt); @@ -10146,6 +10148,20 @@ void tst_qqmlecmascript::doNotCrashOnReadOnlyBindable() QCOMPARE(o->property("x").toInt(), 7); } + +void tst_qqmlecmascript::methodCallOnDerivedSingleton() +{ + QQmlEngine engine; + QQmlComponent c(&engine, testFile("methodCallOnDerivedSingleton.qml")); + QVERIFY2(c.isReady(), qPrintable(c.errorString())); + QScopedPointer<QObject> o(c.create()); + QVERIFY(o); + int singletonTypeId = qmlTypeId("Qt.test", 1, 0, "SingletonInheritanceTest"); + auto singleton = engine.singletonInstance<SingletonBase *>(singletonTypeId); + QVERIFY(singleton); + QVERIFY(singleton->m_okay); +} + QTEST_MAIN(tst_qqmlecmascript) #include "tst_qqmlecmascript.moc" diff --git a/tests/auto/qml/qqmlengine/data/bindingInstallUseAfterFree.qml b/tests/auto/qml/qqmlengine/data/bindingInstallUseAfterFree.qml new file mode 100644 index 0000000000..596ab10ee7 --- /dev/null +++ b/tests/auto/qml/qqmlengine/data/bindingInstallUseAfterFree.qml @@ -0,0 +1,19 @@ +import QtQuick + +Item { + visible: false + + property int test: 1 + + Component { + id: comp + Item { + width: { width = test * 100 } + } + } + + Loader { + sourceComponent: comp + width: 100 + } +} diff --git a/tests/auto/qml/qqmlengine/tst_qqmlengine.cpp b/tests/auto/qml/qqmlengine/tst_qqmlengine.cpp index d2ec48ffb4..953bce9603 100644 --- a/tests/auto/qml/qqmlengine/tst_qqmlengine.cpp +++ b/tests/auto/qml/qqmlengine/tst_qqmlengine.cpp @@ -92,6 +92,7 @@ private slots: void attachedObjectAsObject(); void listPropertyAsQJSValue(); void stringToColor(); + void bindingInstallUseAfterFree(); public slots: QObject *createAQObjectForOwnershipTest () @@ -1436,6 +1437,15 @@ void tst_qqmlengine::stringToColor() QCOMPARE(color, variant); } +void tst_qqmlengine::bindingInstallUseAfterFree() +{ + QQmlEngine engine; + QQmlComponent c(&engine, testFileUrl("bindingInstallUseAfterFree.qml")); + QVERIFY2(c.isReady(), qPrintable(c.errorString())); + std::unique_ptr<QObject> o{ c.create() }; + QVERIFY(o); +} + QTEST_MAIN(tst_qqmlengine) #include "tst_qqmlengine.moc" diff --git a/tests/auto/qml/qqmllanguage/data/DeepAliasOnIC.qml b/tests/auto/qml/qqmllanguage/data/DeepAliasOnIC.qml new file mode 100644 index 0000000000..bde2ad9813 --- /dev/null +++ b/tests/auto/qml/qqmllanguage/data/DeepAliasOnIC.qml @@ -0,0 +1,28 @@ +import QtQml + +QtObject { + id: root + objectName: "theRoot" + + component ObjectWithColor: QtObject { + property string color + property var varvar + } + + property ObjectWithColor border: ObjectWithColor { + id: border + objectName: root.objectName + color: root.trueBorderColor + varvar: root.trueBorderVarvar + } + + readonly property rect readonlyRect: Qt.rect(12, 13, 14, 15) + + property alias borderObjectName: border.objectName + property alias borderColor: border.color + property alias borderVarvar: border.varvar + property alias readonlyRectX: root.readonlyRect.x + + property string trueBorderColor: "green" + property var trueBorderVarvar: 1234 +} diff --git a/tests/auto/qml/qqmllanguage/data/TypeAnnotationCycle1.qml b/tests/auto/qml/qqmllanguage/data/TypeAnnotationCycle1.qml new file mode 100644 index 0000000000..6186faa00b --- /dev/null +++ b/tests/auto/qml/qqmllanguage/data/TypeAnnotationCycle1.qml @@ -0,0 +1,15 @@ +import QtQml + +QtObject { + id: self + property QtObject b + property Component c + function a() : TypeAnnotationCycle2 { return c.createObject() as TypeAnnotationCycle2 } + + Component.onCompleted: { + c = Qt.createComponent("TypeAnnotationCycle2.qml"); + let v = a(); + v.addTypeAnnotationCycle1(self as TypeAnnotationCycle1); + b = v.b; + } +} diff --git a/tests/auto/qml/qqmllanguage/data/TypeAnnotationCycle2.qml b/tests/auto/qml/qqmllanguage/data/TypeAnnotationCycle2.qml new file mode 100644 index 0000000000..9e3ffa86d2 --- /dev/null +++ b/tests/auto/qml/qqmllanguage/data/TypeAnnotationCycle2.qml @@ -0,0 +1,6 @@ +import QtQml + +QtObject { + property QtObject b + function addTypeAnnotationCycle1(c: TypeAnnotationCycle1) { b = c; } +} diff --git a/tests/auto/qml/qqmllanguage/data/deepAliasOnICUser.qml b/tests/auto/qml/qqmllanguage/data/deepAliasOnICUser.qml new file mode 100644 index 0000000000..50eaa7c3e2 --- /dev/null +++ b/tests/auto/qml/qqmllanguage/data/deepAliasOnICUser.qml @@ -0,0 +1,9 @@ +import QtQml + +DeepAliasOnIC { + borderObjectName: "theLeaf" + borderColor: "black" + borderVarvar: "mauve" +} + + diff --git a/tests/auto/qml/qqmllanguage/data/deepAliasOnReadonly.qml b/tests/auto/qml/qqmllanguage/data/deepAliasOnReadonly.qml new file mode 100644 index 0000000000..f5ae62406b --- /dev/null +++ b/tests/auto/qml/qqmllanguage/data/deepAliasOnReadonly.qml @@ -0,0 +1,5 @@ +import QtQml + +DeepAliasOnIC { + readonlyRectX: 55 +} diff --git a/tests/auto/qml/qqmllanguage/tst_qqmllanguage.cpp b/tests/auto/qml/qqmllanguage/tst_qqmllanguage.cpp index 0d26772c6c..41fb24a76c 100644 --- a/tests/auto/qml/qqmllanguage/tst_qqmllanguage.cpp +++ b/tests/auto/qml/qqmllanguage/tst_qqmllanguage.cpp @@ -390,6 +390,9 @@ private slots: void callMethodOfAttachedDerived(); + void typeAnnotationCycle(); + void deepAliasOnICOrReadonly(); + private: QQmlEngine engine; QStringList defaultImportPathList; @@ -6692,6 +6695,45 @@ void tst_qqmllanguage::callMethodOfAttachedDerived() QCOMPARE(o->property("v").toInt(), 99); } +void tst_qqmllanguage::typeAnnotationCycle() +{ + QQmlEngine engine; + + const QUrl url = testFileUrl("TypeAnnotationCycle1.qml"); + const QUrl url2 = testFileUrl("TypeAnnotationCycle2.qml"); + + QTest::ignoreMessage( + QtWarningMsg, + qPrintable( + QLatin1String("Cyclic dependency detected between \"%1\" and \"%2\"") + .arg(url.toString(), url2.toString()))); + + QQmlComponent c(&engine, url); + QVERIFY(!c.isReady()); +} + +void tst_qqmllanguage::deepAliasOnICOrReadonly() +{ + QQmlEngine engine; + QQmlComponent c(&engine, testFileUrl("deepAliasOnICUser.qml")); + QVERIFY2(c.isReady(), qPrintable(c.errorString())); + QScopedPointer<QObject> o(c.create()); + QVERIFY(!o.isNull()); + + QCOMPARE(o->property("borderColor").toString(), QLatin1String("black")); + QCOMPARE(o->property("borderObjectName").toString(), QLatin1String("theLeaf")); + + const QVariant var = o->property("borderVarvar"); + QCOMPARE(var.metaType(), QMetaType::fromType<QString>()); + QCOMPARE(var.toString(), QLatin1String("mauve")); + + QQmlComponent c2(&engine, testFileUrl("deepAliasOnReadonly.qml")); + QVERIFY(c2.isError()); + QVERIFY(c2.errorString().contains( + QLatin1String( + "Invalid property assignment: \"readonlyRectX\" is a read-only property"))); +} + QTEST_MAIN(tst_qqmllanguage) #include "tst_qqmllanguage.moc" diff --git a/tests/auto/quick/pointerhandlers/flickableinterop/data/pinchOnFlickableWithParentTapHandler.qml b/tests/auto/quick/pointerhandlers/flickableinterop/data/pinchOnFlickableWithParentTapHandler.qml new file mode 100644 index 0000000000..2660952f16 --- /dev/null +++ b/tests/auto/quick/pointerhandlers/flickableinterop/data/pinchOnFlickableWithParentTapHandler.qml @@ -0,0 +1,24 @@ +import QtQuick + +Rectangle { + width: 320 + height: 320 + + TapHandler { + onTapped: color = "tomato" + } + + Flickable { + anchors.fill: parent + contentWidth: content.width + contentHeight: content.height + Rectangle { + id: content + objectName: "pinchable" + width: 150 + height: 150 + color: "wheat" + PinchHandler {} + } + } +} diff --git a/tests/auto/quick/pointerhandlers/flickableinterop/tst_flickableinterop.cpp b/tests/auto/quick/pointerhandlers/flickableinterop/tst_flickableinterop.cpp index 0bf6b3fdcc..b7f49834d1 100644 --- a/tests/auto/quick/pointerhandlers/flickableinterop/tst_flickableinterop.cpp +++ b/tests/auto/quick/pointerhandlers/flickableinterop/tst_flickableinterop.cpp @@ -36,6 +36,7 @@ #include <QtQuick/private/qquickitemview_p.h> #include <QtQuick/private/qquickpointerhandler_p.h> #include <QtQuick/private/qquickdraghandler_p.h> +#include <QtQuick/private/qquickpinchhandler_p.h> #include <QtQuick/private/qquicktaphandler_p.h> #include <QtQuick/private/qquicktableview_p.h> #include <qpa/qwindowsysteminterface.h> @@ -81,10 +82,14 @@ private slots: void touchAndDragHandlerOnFlickable_data(); void touchAndDragHandlerOnFlickable(); void pinchHandlerOnFlickable(); + void nativeGesturePinchOnFlickableWithParentTapHandler_data(); + void nativeGesturePinchOnFlickableWithParentTapHandler(); private: void createView(QScopedPointer<QQuickView> &window, const char *fileName); QPointingDevice *touchDevice; + QScopedPointer<QPointingDevice> touchpad = QScopedPointer<QPointingDevice>( + QTest::createTouchDevice(QInputDevice::DeviceType::TouchPad)); }; void tst_FlickableInterop::createView(QScopedPointer<QQuickView> &window, const char *fileName) @@ -879,6 +884,119 @@ void tst_FlickableInterop::pinchHandlerOnFlickable() QCOMPARE(flickMoveSpy.count(), 0); // Flickable never moved } +void tst_FlickableInterop::nativeGesturePinchOnFlickableWithParentTapHandler_data() +{ + QTest::addColumn<const QPointingDevice*>("device"); + QTest::addColumn<Qt::MouseButton>("button"); + QTest::addColumn<Qt::NativeGestureType>("gesture"); + QTest::addColumn<qreal>("value"); + QTest::addColumn<qreal>("expectedPropertyValue"); + + const QPointingDevice *constTouchPad = touchpad.data(); + + // expectedPropertyValue is 10 in newer Qt versions, but in 6.2 QQuickPinchHandler::onActiveChanged() resets the first rotation + QTest::newRow("touchpad: left and rotate") << constTouchPad << Qt::LeftButton << Qt::RotateNativeGesture << 5.0 << 5.0; + QTest::newRow("touchpad: right and rotate") << constTouchPad << Qt::RightButton << Qt::RotateNativeGesture << 5.0 << 5.0; + + // whereas zoom is cumulative as expected + QTest::newRow("touchpad: left and scale") << constTouchPad << Qt::LeftButton << Qt::ZoomNativeGesture << 0.1 << 1.21; + QTest::newRow("touchpad: right and scale") << constTouchPad << Qt::RightButton << Qt::ZoomNativeGesture << 0.1 << 1.21; + + const auto *mouse = QPointingDevice::primaryPointingDevice(); + if (mouse->type() == QInputDevice::DeviceType::Mouse) { + QTest::newRow("mouse: left and rotate") << mouse << Qt::LeftButton << Qt::RotateNativeGesture << 5.0 << 10.0; + QTest::newRow("mouse: right and rotate") << mouse << Qt::RightButton << Qt::RotateNativeGesture << 5.0 << 10.0; + QTest::newRow("mouse: left and scale") << mouse << Qt::LeftButton << Qt::ZoomNativeGesture << 0.1 << 1.21; + QTest::newRow("mouse: right and scale") << mouse << Qt::RightButton << Qt::ZoomNativeGesture << 0.1 << 1.21; + } else { + qCWarning(lcPointerTests) << "skipping mouse tests: primary device is not a mouse" << mouse; + } +} + +void tst_FlickableInterop::nativeGesturePinchOnFlickableWithParentTapHandler() +{ + QFETCH(const QPointingDevice*, device); + QFETCH(Qt::MouseButton, button); + QFETCH(Qt::NativeGestureType, gesture); + QFETCH(qreal, value); + QFETCH(qreal, expectedPropertyValue); + + QQuickView window; + QVERIFY(QQuickTest::showView(window, testFileUrl("pinchOnFlickableWithParentTapHandler.qml"))); + QQuickFlickable *flickable = window.rootObject()->findChild<QQuickFlickable*>(); + QVERIFY(flickable); + QQuickPointerHandler *pinchHandler = flickable->findChild<QQuickPinchHandler*>(); + QVERIFY(pinchHandler); + QQuickItem *pinchable = pinchHandler->target(); + QVERIFY(pinchable); + QQuickTapHandler *tapHandler = window.rootObject()->findChild<QQuickTapHandler*>(); + QVERIFY(tapHandler); + const bool expectTap = button & tapHandler->acceptedButtons(); + + QSignalSpy flickMoveSpy(flickable, &QQuickFlickable::movementStarted); + QSignalSpy grabChangedSpy(touchDevice, &QPointingDevice::grabChanged); + QSignalSpy tapActiveSpy(tapHandler, &QQuickTapHandler::activeChanged); + QSignalSpy tapSpy(tapHandler, &QQuickTapHandler::tapped); + + QObject *grabber = nullptr; + connect(device, &QPointingDevice::grabChanged, + [&grabber](QObject *g, QPointingDevice::GrabTransition transition, const QPointerEvent *, const QEventPoint &) { + if (transition == QPointingDevice::GrabTransition::GrabExclusive) + grabber = g; + }); + + const QPoint pinchPos(75, 75); + const QPoint outsidePos(200, 200); + + // move to position + QTest::mouseMove(&window, pinchPos); + + // pinch via native gesture + ulong ts = 502; // after the mouse move, which is at time 501 in practice + QWindowSystemInterface::handleGestureEvent(&window, ts++, touchpad.get(), + Qt::BeginNativeGesture, pinchPos, pinchPos); + if (lcPointerTests().isDebugEnabled()) QTest::qWait(500); + for (int i = 0; i < 2; ++i) { + QWindowSystemInterface::handleGestureEventWithRealValue(&window, ts++, touchpad.get(), + gesture, value, pinchPos, pinchPos); + } + if (gesture == Qt::RotateNativeGesture) + QTRY_COMPARE(pinchHandler->parentItem()->rotation(), expectedPropertyValue); + else if (gesture == Qt::ZoomNativeGesture) + QTRY_COMPARE(pinchHandler->parentItem()->scale(), expectedPropertyValue); + QVERIFY(pinchHandler->active()); + QCOMPARE(grabChangedSpy.count(), 0); + QCOMPARE(grabber, nullptr); + if (lcPointerTests().isDebugEnabled()) QTest::qWait(500); + QWindowSystemInterface::handleGestureEvent(&window, ts++, touchpad.get(), + Qt::EndNativeGesture, pinchPos, pinchPos); + + // tap in square: TapHandler detects tap iff acceptedButtons permits + // TODO delay; unfortunately this also begins at timestamp 502 because we don't have testlib + // functions to send gesture events, and QQuickTest::pointerPress() doesn't take a delay value + QQuickTest::pointerPress(device, &window, 0, pinchPos, button); + QCOMPARE(tapHandler->point().id(), expectTap ? 0 : -1); + QQuickTest::pointerRelease(device, &window, 0, pinchPos, button); + if (lcPointerTests().isDebugEnabled()) QTest::qWait(500); + QCOMPARE(tapSpy.size(), expectTap); + QCOMPARE(tapActiveSpy.size(), 0); + QCOMPARE(tapHandler->point().id(), -1); // does not keep tracking after release + + // move outside: nothing should happen; + // but QTBUG-108896 happened because TapHandler was setting pointInfo to track this moving point + QQuickTest::pointerMove(device, &window, 0, outsidePos); + QCOMPARE(tapHandler->point().id(), -1); // does not track after mouse move + + // tap outside: nothing happens + tapSpy.clear(); + tapActiveSpy.clear(); + QQuickTest::pointerPress(device, &window, 0, outsidePos, button); + QQuickTest::pointerRelease(device, &window, 0, outsidePos, button); + if (lcPointerTests().isDebugEnabled()) QTest::qWait(500); + QCOMPARE(tapSpy.size(), 0); + QCOMPARE(tapActiveSpy.size(), 0); +} + QTEST_MAIN(tst_FlickableInterop) #include "tst_flickableinterop.moc" diff --git a/tests/auto/quick/qquickmultipointtoucharea/data/nestedPinchArea.qml b/tests/auto/quick/qquickmultipointtoucharea/data/nestedPinchArea.qml new file mode 100644 index 0000000000..0e51804b30 --- /dev/null +++ b/tests/auto/quick/qquickmultipointtoucharea/data/nestedPinchArea.qml @@ -0,0 +1,44 @@ +import QtQuick 2.15 + +MultiPointTouchArea { + width: 240 + height: 320 + mouseEnabled: true + property int pressedCount: 0 + property int updatedCount: 0 + property int releasedCount: 0 + + onPressed: (points) => { pressedCount = points.length } + onUpdated: (points) => { updatedCount = points.length } + onReleased: (points) => { releasedCount = points.length } + + touchPoints: [ + TouchPoint { + id: point1 + objectName: "point1" + }, + TouchPoint { + id: point2 + objectName: "point2" + } + ] + + PinchArea { + anchors.fill: parent + } + + Rectangle { + width: 30; height: 30 + color: "green" + x: point1.x + y: point1.y + } + + Rectangle { + id: rectangle + width: 30; height: 30 + color: "yellow" + x: point2.x + y: point2.y + } +} diff --git a/tests/auto/quick/qquickmultipointtoucharea/tst_qquickmultipointtoucharea.cpp b/tests/auto/quick/qquickmultipointtoucharea/tst_qquickmultipointtoucharea.cpp index 3e6a7fce16..f85fba45d6 100644 --- a/tests/auto/quick/qquickmultipointtoucharea/tst_qquickmultipointtoucharea.cpp +++ b/tests/auto/quick/qquickmultipointtoucharea/tst_qquickmultipointtoucharea.cpp @@ -74,6 +74,7 @@ private slots: void cancel(); void stationaryTouchWithChangingPressure(); void touchFiltering(); + void nestedPinchAreaMouse(); private: QQuickView *createAndShowView(const QString &file); @@ -1385,6 +1386,49 @@ void tst_QQuickMultiPointTouchArea::touchFiltering() // QTBUG-74028 QCOMPARE(mptaSpy.count(), 1); } +void tst_QQuickMultiPointTouchArea::nestedPinchAreaMouse() // QTBUG-83662 +{ + QScopedPointer<QQuickView> window(createAndShowView("nestedPinchArea.qml")); + QQuickMultiPointTouchArea *mpta = qobject_cast<QQuickMultiPointTouchArea *>(window->rootObject()); + QVERIFY(mpta); + QQuickTouchPoint *point1 = mpta->findChild<QQuickTouchPoint*>("point1"); + QCOMPARE(point1->pressed(), false); + QQuickTouchPoint *point2 = mpta->findChild<QQuickTouchPoint*>("point2"); + QCOMPARE(point2->pressed(), false); + QSignalSpy pressedSpy(mpta, &QQuickMultiPointTouchArea::pressed); + QSignalSpy updatedSpy(mpta, &QQuickMultiPointTouchArea::updated); + QSignalSpy releasedSpy(mpta, &QQuickMultiPointTouchArea::released); + QPoint p1(20, 20); + QTest::mousePress(window.data(), Qt::LeftButton, Qt::NoModifier, p1); + QCOMPARE(point1->pressed(), true); + QCOMPARE(point2->pressed(), false); + QCOMPARE(pressedSpy.count(), 1); + QCOMPARE(mpta->property("pressedCount").toInt(), 1); + QCOMPARE(updatedSpy.count(), 0); + QCOMPARE(mpta->property("updatedCount").toInt(), 0); + QCOMPARE(releasedSpy.count(), 0); + QCOMPARE(mpta->property("releasedCount").toInt(), 0); + p1 += QPoint(0, 15); + QTest::mouseMove(window.data(), p1); + QCOMPARE(point1->pressed(), true); + QCOMPARE(point2->pressed(), false); + QCOMPARE(pressedSpy.count(), 1); + QCOMPARE(mpta->property("pressedCount").toInt(), 1); + QCOMPARE(updatedSpy.count(), 1); + QCOMPARE(mpta->property("updatedCount").toInt(), 1); + QCOMPARE(releasedSpy.count(), 0); + QCOMPARE(mpta->property("releasedCount").toInt(), 0); + QTest::mouseRelease(window.data(), Qt::LeftButton, Qt::NoModifier, p1); + QCOMPARE(point1->pressed(), false); + QCOMPARE(point2->pressed(), false); + QCOMPARE(pressedSpy.count(), 1); + QCOMPARE(mpta->property("pressedCount").toInt(), 1); + QCOMPARE(updatedSpy.count(), 1); + QCOMPARE(mpta->property("updatedCount").toInt(), 1); + QCOMPARE(releasedSpy.count(), 1); + QCOMPARE(mpta->property("releasedCount").toInt(), 1); +} + QTEST_MAIN(tst_QQuickMultiPointTouchArea) #include "tst_qquickmultipointtoucharea.moc" diff --git a/tests/auto/quick/qquicktableview/data/deletedDelegate.qml b/tests/auto/quick/qquicktableview/data/deletedDelegate.qml new file mode 100644 index 0000000000..ec3161bbac --- /dev/null +++ b/tests/auto/quick/qquicktableview/data/deletedDelegate.qml @@ -0,0 +1,25 @@ +import QtQuick 2.15 + +Item { + width: 800 + height: 600 + + Component { + id: dyn + Item { + property Component comp: Item {} + } + } + + TableView { + id: tv + anchors.fill: parent + objectName: "tableview" + } + + Component.onCompleted: { + let o = dyn.createObject(); + tv.delegate = o.comp; + o.destroy(); + } +} diff --git a/tests/auto/quick/qquicktableview/data/resetJsModelData.qml b/tests/auto/quick/qquicktableview/data/resetJsModelData.qml new file mode 100644 index 0000000000..def5346147 --- /dev/null +++ b/tests/auto/quick/qquicktableview/data/resetJsModelData.qml @@ -0,0 +1,19 @@ +import QtQuick + +Item { + width: 100 + height: 300 + + property alias tableView: tableView + + TableView { + id: tableView + anchors.fill: parent + property int modelUpdated: 0 + onModelChanged: { ++modelUpdated } + delegate: Item { + implicitHeight: 10 + implicitWidth: 10 + } + } +} diff --git a/tests/auto/quick/qquicktableview/tst_qquicktableview.cpp b/tests/auto/quick/qquicktableview/tst_qquicktableview.cpp index 97dae95fce..ec568a21e4 100644 --- a/tests/auto/quick/qquicktableview/tst_qquicktableview.cpp +++ b/tests/auto/quick/qquicktableview/tst_qquicktableview.cpp @@ -122,7 +122,7 @@ private slots: void isColumnLoadedAndIsRowLoaded(); void checkForceLayoutFunction(); void checkForceLayoutEndUpDoingALayout(); - void checkForceLayoutDuringModelChange(); + void checkForceLayoutInbetweenAddingRowsToModel(); void checkForceLayoutWhenAllItemsAreHidden(); void checkContentWidthAndHeight(); void checkContentWidthAndHeightForSmallTables(); @@ -213,6 +213,8 @@ private slots: void testSelectableStartPosEndPosOutsideView(); void testSelectableScrollTowardsPos(); void resettingRolesRespected(); + void deletedDelegate(); + void checkRebuildJsModel(); }; tst_QQuickTableView::tst_QQuickTableView() @@ -681,10 +683,11 @@ void tst_QQuickTableView::checkForceLayoutEndUpDoingALayout() QCOMPARE(tableView->contentHeight(), (9 * (newDelegateSize + rowSpacing)) - rowSpacing); } -void tst_QQuickTableView::checkForceLayoutDuringModelChange() +void tst_QQuickTableView::checkForceLayoutInbetweenAddingRowsToModel() { - // Check that TableView doesn't assert if we call - // forceLayout() in the middle of a model change. + // Check that TableView doesn't assert if we call forceLayout() while waiting + // for a callback from the model that the row count has changed. Also make sure + // that we don't move the contentItem while doing so. LOAD_TABLEVIEW("plaintableview.qml"); const int initialRowCount = 10; @@ -699,9 +702,13 @@ void tst_QQuickTableView::checkForceLayoutDuringModelChange() WAIT_UNTIL_POLISHED; + const int contentY = 10; + tableView->setContentY(contentY); QCOMPARE(tableView->rows(), initialRowCount); + QCOMPARE(tableView->contentY(), contentY); model.addRow(0); QCOMPARE(tableView->rows(), initialRowCount + 1); + QCOMPARE(tableView->contentY(), contentY); } void tst_QQuickTableView::checkForceLayoutWhenAllItemsAreHidden() @@ -3989,6 +3996,45 @@ void tst_QQuickTableView::resettingRolesRespected() QTRY_VERIFY(tableView->property("success").toBool()); } +void tst_QQuickTableView::deletedDelegate() +{ + QQmlEngine engine; + QQmlComponent component(&engine, testFileUrl("deletedDelegate.qml")); + std::unique_ptr<QObject> root(component.create()); + QVERIFY(root); + auto tv = root->findChild<QQuickTableView *>("tableview"); + QVERIFY(tv); + // we need one event loop iteration for the deferred delete to trigger + // thus the QTRY_VERIFY + QTRY_COMPARE(tv->delegate(), nullptr); +} + +void tst_QQuickTableView::checkRebuildJsModel() +{ + LOAD_TABLEVIEW("resetJsModelData.qml"); // gives us 'tableView' variable + + // Generate javascript model + const int size = 5; + const char* modelUpdated = "modelUpdated"; + + QJSEngine jsEngine; + QJSValue jsArray; + jsArray = jsEngine.newArray(size); + for (int i = 0; i < size; ++i) + jsArray.setProperty(i, QRandomGenerator::global()->generate()); + + QVariant jsModel = QVariant::fromValue(jsArray); + tableView->setModel(jsModel); + WAIT_UNTIL_POLISHED; + + // Model change would be triggered for the first time + QCOMPARE(tableView->property(modelUpdated).toInt(), 1); + + // Set the same model once again and check if model changes + tableView->setModel(jsModel); + QCOMPARE(tableView->property(modelUpdated).toInt(), 1); +} + QTEST_MAIN(tst_QQuickTableView) #include "tst_qquicktableview.moc" diff --git a/tests/auto/quickcontrols2/qquickmenu/data/scrollableWithFixedHeight.qml b/tests/auto/quickcontrols2/qquickmenu/data/scrollableWithFixedHeight.qml new file mode 100644 index 0000000000..1156d30aef --- /dev/null +++ b/tests/auto/quickcontrols2/qquickmenu/data/scrollableWithFixedHeight.qml @@ -0,0 +1,27 @@ +// Copyright (C) 2023 The Qt Company Ltd. +// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause + +import QtQuick +import QtQuick.Controls +import QtQuick.Window + +Window { + width: 300 + height: 300 + + property alias menu: menu + + Menu { + id: menu + anchors.centerIn: parent + height: 100 + visible: true + Repeater { + model: 10 + delegate: MenuItem { + objectName: text + text: (index + 1) + } + } + } +} diff --git a/tests/auto/quickcontrols2/qquickmenu/tst_qquickmenu.cpp b/tests/auto/quickcontrols2/qquickmenu/tst_qquickmenu.cpp index 0176c2db35..4b1628038d 100644 --- a/tests/auto/quickcontrols2/qquickmenu/tst_qquickmenu.cpp +++ b/tests/auto/quickcontrols2/qquickmenu/tst_qquickmenu.cpp @@ -1778,6 +1778,7 @@ void tst_QQuickMenu::scrollable_data() QTest::addRow("Window") << QString::fromLatin1("windowScrollable.qml"); QTest::addRow("ApplicationWindow") << QString::fromLatin1("applicationWindowScrollable.qml"); QTest::addRow("WithPadding") << QString::fromLatin1("scrollableWithPadding.qml"); + QTest::addRow("FixedHeight") << QString::fromLatin1("scrollableWithFixedHeight.qml"); } void tst_QQuickMenu::scrollable() diff --git a/tests/auto/quickcontrols2/sanity/tst_sanity.cpp b/tests/auto/quickcontrols2/sanity/tst_sanity.cpp index c29a191cd9..dc1a4b3836 100644 --- a/tests/auto/quickcontrols2/sanity/tst_sanity.cpp +++ b/tests/auto/quickcontrols2/sanity/tst_sanity.cpp @@ -458,11 +458,6 @@ void tst_Sanity::attachedObjects_data() QTest::newRow("Basic/HorizontalHeaderView.qml") << ignoredNames << StringPairSet {}; QTest::newRow("Basic/ItemDelegate.qml") << ignoredNames << StringPairSet {}; QTest::newRow("Basic/Label.qml") << ignoredNames << StringPairSet {}; - QTest::newRow("Basic/Menu.qml") << ignoredNames << StringPairSet { - { "QQuickOverlayAttached", "Menu_QMLTYPE" }, - { "QQuickScrollIndicatorAttached", "QQuickListView" }, - { "QQuickWindowAttached", "QQuickListView" } - }; QTest::newRow("Basic/MenuBar.qml") << ignoredNames << StringPairSet {}; QTest::newRow("Basic/MenuBarItem.qml") << ignoredNames << StringPairSet {}; QTest::newRow("Basic/MenuItem.qml") << ignoredNames << StringPairSet {}; @@ -513,11 +508,6 @@ void tst_Sanity::attachedObjects_data() QTest::newRow("Fusion/HorizontalHeaderView.qml") << ignoredNames << StringPairSet {}; QTest::newRow("Fusion/ItemDelegate.qml") << ignoredNames << StringPairSet {}; QTest::newRow("Fusion/Label.qml") << ignoredNames << StringPairSet {}; - QTest::newRow("Fusion/Menu.qml") << ignoredNames << StringPairSet { - { "QQuickOverlayAttached", "Menu_QMLTYPE" }, - { "QQuickScrollIndicatorAttached", "QQuickListView" }, - { "QQuickWindowAttached", "QQuickListView" } - }; QTest::newRow("Fusion/MenuBar.qml") << ignoredNames << StringPairSet {}; QTest::newRow("Fusion/MenuBarItem.qml") << ignoredNames << StringPairSet {}; QTest::newRow("Fusion/MenuItem.qml") << ignoredNames << StringPairSet {}; @@ -573,13 +563,6 @@ void tst_Sanity::attachedObjects_data() QTest::newRow("Material/HorizontalHeaderView.qml") << ignoredNames << StringPairSet {}; QTest::newRow("Material/ItemDelegate.qml") << ignoredNames << StringPairSet {{ "QQuickMaterialStyle", "ItemDelegate_QMLTYPE" }}; QTest::newRow("Material/Label.qml") << ignoredNames << StringPairSet {{ "QQuickMaterialStyle", "Label_QMLTYPE" }}; - QTest::newRow("Material/Menu.qml") << ignoredNames << StringPairSet { - { "QQuickOverlayAttached", "Menu_QMLTYPE" }, - { "QQuickMaterialStyle", "Menu_QMLTYPE" }, - { "QQuickScrollIndicatorAttached", "QQuickListView" }, - { "QQuickWindowAttached", "QQuickListView" }, - { "QQuickMaterialStyle", "ScrollIndicator_QMLTYPE" } - }; QTest::newRow("Material/MenuBar.qml") << ignoredNames << StringPairSet {{ "QQuickMaterialStyle", "MenuBar_QMLTYPE" }}; QTest::newRow("Material/MenuBarItem.qml") << ignoredNames << StringPairSet {{ "QQuickMaterialStyle", "MenuBarItem_QMLTYPE" }}; QTest::newRow("Material/MenuItem.qml") << ignoredNames << StringPairSet {{ "QQuickMaterialStyle", "MenuItem_QMLTYPE" }}; @@ -646,13 +629,6 @@ void tst_Sanity::attachedObjects_data() QTest::newRow("Universal/HorizontalHeaderView.qml") << ignoredNames << StringPairSet {}; QTest::newRow("Universal/ItemDelegate.qml") << ignoredNames << StringPairSet {{ "QQuickUniversalStyle", "ItemDelegate_QMLTYPE" }}; QTest::newRow("Universal/Label.qml") << ignoredNames << StringPairSet {{ "QQuickUniversalStyle", "Label_QMLTYPE" }}; - QTest::newRow("Universal/Menu.qml") << ignoredNames << StringPairSet { - { "QQuickOverlayAttached", "Menu_QMLTYPE" }, - { "QQuickUniversalStyle", "Menu_QMLTYPE" }, - { "QQuickScrollIndicatorAttached", "QQuickListView" }, - { "QQuickWindowAttached", "QQuickListView" }, - { "QQuickUniversalStyle", "ScrollIndicator_QMLTYPE" } - }; QTest::newRow("Universal/MenuBar.qml") << ignoredNames << StringPairSet {{ "QQuickUniversalStyle", "MenuBar_QMLTYPE" }}; QTest::newRow("Universal/MenuBarItem.qml") << ignoredNames << StringPairSet {{ "QQuickUniversalStyle", "MenuBarItem_QMLTYPE" }}; QTest::newRow("Universal/MenuItem.qml") << ignoredNames << StringPairSet {{ "QQuickUniversalStyle", "MenuItem_QMLTYPE" }}; |