diff options
Diffstat (limited to 'tests')
101 files changed, 1630 insertions, 729 deletions
diff --git a/tests/auto/particles/shared/particlestestsshared.h b/tests/auto/particles/shared/particlestestsshared.h index 5ef1d2cabb..e1fc6f4ccd 100644 --- a/tests/auto/particles/shared/particlestestsshared.h +++ b/tests/auto/particles/shared/particlestestsshared.h @@ -31,6 +31,8 @@ #include <QtQuick/QQuickView> #include <QtTest> #include <QAbstractAnimation> +#include <QScopedPointer> + const qreal EPSILON = 0.0001; bool extremelyFuzzyCompare(qreal a, qreal b, qreal e)//For cases which can have larger variances @@ -55,17 +57,18 @@ bool myFuzzyGEQ(qreal a, qreal b) QQuickView* createView(const QUrl &filename, int additionalWait=0) { - QQuickView *view = new QQuickView(0); + QScopedPointer<QQuickView> view(new QQuickView(nullptr)); view->setSource(filename); if (view->status() != QQuickView::Ready) - return 0; + return nullptr; view->show(); - QTest::qWaitForWindowExposed(view); + if (!QTest::qWaitForWindowExposed(view.data())) + return nullptr; if (additionalWait) QTest::qWait(additionalWait); - return view; + return view.take(); } void ensureAnimTime(int requiredTime, QAbstractAnimation* anim)//With consistentTiming, who knows how long an animation really takes... diff --git a/tests/auto/qml/debugger/qqmlenginedebugservice/tst_qqmlenginedebugservice.cpp b/tests/auto/qml/debugger/qqmlenginedebugservice/tst_qqmlenginedebugservice.cpp index 99c90c142f..0ebf43eb6f 100644 --- a/tests/auto/qml/debugger/qqmlenginedebugservice/tst_qqmlenginedebugservice.cpp +++ b/tests/auto/qml/debugger/qqmlenginedebugservice/tst_qqmlenginedebugservice.cpp @@ -524,7 +524,7 @@ void tst_QQmlEngineDebugService::watch_property() QCOMPARE(spy.count(), 1); QCOMPARE(spy.at(0).at(0).value<QByteArray>(), prop.name.toUtf8()); - QCOMPARE(spy.at(0).at(1).value<QVariant>(), qVariantFromValue(origWidth*2)); + QCOMPARE(spy.at(0).at(1).value<QVariant>(), QVariant::fromValue(origWidth*2)); } void tst_QQmlEngineDebugService::watch_object() @@ -772,11 +772,11 @@ void tst_QQmlEngineDebugService::queryObject() } // test specific property values - QCOMPARE(findProperty(rect.properties, "width").value, qVariantFromValue(500)); - QCOMPARE(findProperty(rect.properties, "height").value, qVariantFromValue(600)); - QCOMPARE(findProperty(rect.properties, "color").value, qVariantFromValue(QColor("blue"))); + QCOMPARE(findProperty(rect.properties, "width").value, QVariant::fromValue(500)); + QCOMPARE(findProperty(rect.properties, "height").value, QVariant::fromValue(600)); + QCOMPARE(findProperty(rect.properties, "color").value, QVariant::fromValue(QColor("blue"))); - QCOMPARE(findProperty(text.properties, "color").value, qVariantFromValue(QColor("blue"))); + QCOMPARE(findProperty(text.properties, "color").value, QVariant::fromValue(QColor("blue"))); } else { foreach (const QQmlEngineDebugObjectReference &child, obj.children) { QVERIFY(!child.className.isEmpty()); @@ -851,11 +851,11 @@ void tst_QQmlEngineDebugService::queryObjectsForLocation() } // test specific property values - QCOMPARE(findProperty(rect.properties, "width").value, qVariantFromValue(500)); - QCOMPARE(findProperty(rect.properties, "height").value, qVariantFromValue(600)); - QCOMPARE(findProperty(rect.properties, "color").value, qVariantFromValue(QColor("blue"))); + QCOMPARE(findProperty(rect.properties, "width").value, QVariant::fromValue(500)); + QCOMPARE(findProperty(rect.properties, "height").value, QVariant::fromValue(600)); + QCOMPARE(findProperty(rect.properties, "color").value, QVariant::fromValue(QColor("blue"))); - QCOMPARE(findProperty(text.properties, "color").value, qVariantFromValue(QColor("blue"))); + QCOMPARE(findProperty(text.properties, "color").value, QVariant::fromValue(QColor("blue"))); } else { foreach (const QQmlEngineDebugObjectReference &child, obj.children) { QVERIFY(!child.className.isEmpty()); @@ -1004,15 +1004,15 @@ void tst_QQmlEngineDebugService::queryExpressionResult_data() QTest::addColumn<QString>("expr"); QTest::addColumn<QVariant>("result"); - QTest::newRow("width + 50") << "width + 50" << qVariantFromValue(60); - QTest::newRow("blueRect.width") << "blueRect.width" << qVariantFromValue(500); - QTest::newRow("bad expr") << "aeaef" << qVariantFromValue(QString("<undefined>")); - QTest::newRow("QObject*") << "varObj" << qVariantFromValue(QString("<unnamed object>")); - QTest::newRow("list of QObject*") << "varObjList" << qVariantFromValue(QVariantList() << QVariant(QString("<unnamed object>"))); + QTest::newRow("width + 50") << "width + 50" << QVariant::fromValue(60); + QTest::newRow("blueRect.width") << "blueRect.width" << QVariant::fromValue(500); + QTest::newRow("bad expr") << "aeaef" << QVariant::fromValue(QString("<undefined>")); + QTest::newRow("QObject*") << "varObj" << QVariant::fromValue(QString("<unnamed object>")); + QTest::newRow("list of QObject*") << "varObjList" << QVariant::fromValue(QVariantList() << QVariant(QString("<unnamed object>"))); QVariantMap map; map.insert(QLatin1String("rect"), QVariant(QLatin1String("<unnamed object>"))); - QTest::newRow("varObjMap") << "varObjMap" << qVariantFromValue(map); - QTest::newRow("simpleVar") << "simpleVar" << qVariantFromValue(10.05); + QTest::newRow("varObjMap") << "varObjMap" << QVariant::fromValue(map); + QTest::newRow("simpleVar") << "simpleVar" << QVariant::fromValue(10.05); } void tst_QQmlEngineDebugService::queryExpressionResultInRootContext() @@ -1052,15 +1052,15 @@ void tst_QQmlEngineDebugService::queryExpressionResultBC_data() QTest::addColumn<QString>("expr"); QTest::addColumn<QVariant>("result"); - QTest::newRow("width + 50") << "width + 50" << qVariantFromValue(60); - QTest::newRow("blueRect.width") << "blueRect.width" << qVariantFromValue(500); - QTest::newRow("bad expr") << "aeaef" << qVariantFromValue(QString("<undefined>")); - QTest::newRow("QObject*") << "varObj" << qVariantFromValue(QString("<unnamed object>")); - QTest::newRow("list of QObject*") << "varObjList" << qVariantFromValue(QVariantList() << QVariant(QString("<unnamed object>"))); + QTest::newRow("width + 50") << "width + 50" << QVariant::fromValue(60); + QTest::newRow("blueRect.width") << "blueRect.width" << QVariant::fromValue(500); + QTest::newRow("bad expr") << "aeaef" << QVariant::fromValue(QString("<undefined>")); + QTest::newRow("QObject*") << "varObj" << QVariant::fromValue(QString("<unnamed object>")); + QTest::newRow("list of QObject*") << "varObjList" << QVariant::fromValue(QVariantList() << QVariant(QString("<unnamed object>"))); QVariantMap map; map.insert(QLatin1String("rect"), QVariant(QLatin1String("<unnamed object>"))); - QTest::newRow("varObjMap") << "varObjMap" << qVariantFromValue(map); - QTest::newRow("simpleVar") << "simpleVar" << qVariantFromValue(10.05); + QTest::newRow("varObjMap") << "varObjMap" << QVariant::fromValue(map); + QTest::newRow("simpleVar") << "simpleVar" << QVariant::fromValue(10.05); } void tst_QQmlEngineDebugService::setBindingForObject() diff --git a/tests/auto/qml/debugger/qqmlpreview/tst_qqmlpreview.cpp b/tests/auto/qml/debugger/qqmlpreview/tst_qqmlpreview.cpp index 4c4c514832..c7f8ec1118 100644 --- a/tests/auto/qml/debugger/qqmlpreview/tst_qqmlpreview.cpp +++ b/tests/auto/qml/debugger/qqmlpreview/tst_qqmlpreview.cpp @@ -319,12 +319,12 @@ void tst_QQmlPreview::zoom() QTRY_VERIFY(m_files.contains(testFile(file))); float baseZoomFactor = -1; QTRY_VERIFY_WITH_TIMEOUT((baseZoomFactor = parseZoomFactor(m_process->output())) > 0, 30000); - m_client->triggerZoom(2.0f); - verifyZoomFactor(m_process, baseZoomFactor * 2.0f); - m_client->triggerZoom(1.5f); - verifyZoomFactor(m_process, baseZoomFactor * 1.5f); - m_client->triggerZoom(0.5f); - verifyZoomFactor(m_process, baseZoomFactor * 0.5f); + + for (auto testZoomFactor : {2.0f, 1.5f, 0.5f}) { + m_client->triggerZoom(testZoomFactor); + verifyZoomFactor(m_process, baseZoomFactor * testZoomFactor); + } + m_client->triggerZoom(-1.0f); verifyZoomFactor(m_process, baseZoomFactor); m_process->stop(); @@ -338,7 +338,7 @@ void tst_QQmlPreview::fps() QVERIFY(m_client); m_client->triggerLoad(testFileUrl(file)); if (QGuiApplication::platformName() != "offscreen") { - QTRY_VERIFY(m_frameStats.numSyncs > 10); + QTRY_VERIFY_WITH_TIMEOUT(m_frameStats.numSyncs > 10, 10000); QVERIFY(m_frameStats.minSync <= m_frameStats.maxSync); QVERIFY(m_frameStats.totalSync / m_frameStats.numSyncs >= m_frameStats.minSync - 1); QVERIFY(m_frameStats.totalSync / m_frameStats.numSyncs <= m_frameStats.maxSync); diff --git a/tests/auto/qml/debugger/qv4debugger/tst_qv4debugger.cpp b/tests/auto/qml/debugger/qv4debugger/tst_qv4debugger.cpp index b75fb6b895..d9f64f3899 100644 --- a/tests/auto/qml/debugger/qv4debugger/tst_qv4debugger.cpp +++ b/tests/auto/qml/debugger/qv4debugger/tst_qv4debugger.cpp @@ -36,7 +36,6 @@ #include <QQmlComponent> #include <private/qv4engine_p.h> #include <private/qv4debugging_p.h> -#include <private/qv8engine_p.h> #include <private/qv4objectiterator_p.h> #include <private/qv4string_p.h> #include <private/qqmlbuiltinfunctions_p.h> diff --git a/tests/auto/qml/qjsengine/tst_qjsengine.cpp b/tests/auto/qml/qjsengine/tst_qjsengine.cpp index 01b9465f58..9c3316e39f 100644 --- a/tests/auto/qml/qjsengine/tst_qjsengine.cpp +++ b/tests/auto/qml/qjsengine/tst_qjsengine.cpp @@ -242,6 +242,9 @@ private slots: void importModuleWithLexicallyScopedVars(); void importExportErrors(); + void equality(); + void aggressiveGc(); + public: Q_INVOKABLE QJSValue throwingCppMethod1(); Q_INVOKABLE void throwingCppMethod2(); @@ -1579,13 +1582,13 @@ void tst_QJSEngine::valueConversion_QVariant() QCOMPARE(val.toString(), str); } { - QJSValue val = eng.toScriptValue(qVariantFromValue((QObject*)this)); + QJSValue val = eng.toScriptValue(QVariant::fromValue((QObject*)this)); QVERIFY(!val.isVariant()); QVERIFY(val.isQObject()); QCOMPARE(val.toQObject(), (QObject*)this); } { - QVariant var = qVariantFromValue(QPoint(123, 456)); + QVariant var = QVariant::fromValue(QPoint(123, 456)); QJSValue val = eng.toScriptValue(var); QVERIFY(!val.isVariant()); QCOMPARE(val.toVariant(), var); @@ -4590,6 +4593,34 @@ void tst_QJSEngine::stringReplace() val = engine.evaluate("'x'.replace(/()()()()()()()()()(x)/, '$10')"); QVERIFY(val.isString()); QCOMPARE(val.toString(), QString("x")); + + val = engine.evaluate("'123'.replace(/\\.0*$|(\\.\\d*[1-9])(0+)$/, '$1')"); + QVERIFY(val.isString()); + QCOMPARE(val.toString(), QString("123")); + + val = engine.evaluate("'123.00'.replace(/\\.0*$|(\\.\\d*[1-9])(0+)$/, '$1')"); + QVERIFY(val.isString()); + QCOMPARE(val.toString(), QString("123")); + + val = engine.evaluate("'123.0'.replace(/\\.0*$|(\\.\\d*[1-9])(0+)$/, '$1')"); + QVERIFY(val.isString()); + QCOMPARE(val.toString(), QString("123")); + + val = engine.evaluate("'123.'.replace(/\\.0*$|(\\.\\d*[1-9])(0+)$/, '$1')"); + QVERIFY(val.isString()); + QCOMPARE(val.toString(), QString("123")); + + val = engine.evaluate("'123.50'.replace(/\\.0*$|(\\.\\d*[1-9])(0+)$/, '$1')"); + QVERIFY(val.isString()); + QCOMPARE(val.toString(), QString("123.5")); + + val = engine.evaluate("'123.05'.replace(/\\.0*$|(\\.\\d*[1-9])(0+)$/, '$1')"); + QVERIFY(val.isString()); + QCOMPARE(val.toString(), QString("123.05")); + + val = engine.evaluate("'0.050'.replace(/\\.0*$|(\\.\\d*[1-9])(0+)$/, '$1')"); + QVERIFY(val.isString()); + QCOMPARE(val.toString(), QString("0.05")); } void tst_QJSEngine::protoChanges_QTBUG68369() @@ -4788,6 +4819,26 @@ void tst_QJSEngine::importExportErrors() } } +void tst_QJSEngine::equality() +{ + QJSEngine engine; + QJSValue ok = engine.evaluate("(0 < 0) ? 'ko' : 'ok'"); + QVERIFY(ok.isString()); + QCOMPARE(ok.toString(), QString("ok")); +} + +void tst_QJSEngine::aggressiveGc() +{ + const QByteArray origAggressiveGc = qgetenv("QV4_MM_AGGRESSIVE_GC"); + qputenv("QV4_MM_AGGRESSIVE_GC", "true"); + { + QJSEngine engine; // ctor crashes if core allocation methods don't properly scope things. + QJSValue obj = engine.newObject(); + QVERIFY(obj.isObject()); + } + qputenv("QV4_MM_AGGRESSIVE_GC", origAggressiveGc); +} + QTEST_MAIN(tst_QJSEngine) #include "tst_qjsengine.moc" diff --git a/tests/auto/qml/qjsvalue/tst_qjsvalue.cpp b/tests/auto/qml/qjsvalue/tst_qjsvalue.cpp index 2b80970559..a57cd3113c 100644 --- a/tests/auto/qml/qjsvalue/tst_qjsvalue.cpp +++ b/tests/auto/qml/qjsvalue/tst_qjsvalue.cpp @@ -1121,7 +1121,7 @@ void tst_QJSValue::toQObject_nonQObject_data() QTest::newRow("array") << engine->newArray(); QTest::newRow("date") << engine->evaluate("new Date(124)"); QTest::newRow("variant(12345)") << engine->toScriptValue(QVariant(12345)); - QTest::newRow("variant((QObject*)0)") << engine->toScriptValue(qVariantFromValue((QObject*)nullptr)); + QTest::newRow("variant((QObject*)0)") << engine->toScriptValue(QVariant::fromValue((QObject*)nullptr)); QTest::newRow("newQObject(0)") << engine->newQObject(nullptr); } @@ -2327,7 +2327,7 @@ void tst_QJSValue::castToPointer() QBrush *bp = qjsvalue_cast<QBrush*>(v); QVERIFY(!bp); - QJSValue v2 = eng.toScriptValue(qVariantFromValue(cp)); + QJSValue v2 = eng.toScriptValue(QVariant::fromValue(cp)); QCOMPARE(qjsvalue_cast<QColor*>(v2), cp); } } diff --git a/tests/auto/qml/qmlcachegen/Enums.qml b/tests/auto/qml/qmlcachegen/data/Enums.qml index 830babb73e..830babb73e 100644 --- a/tests/auto/qml/qmlcachegen/Enums.qml +++ b/tests/auto/qml/qmlcachegen/data/Enums.qml diff --git a/tests/auto/qml/qmlcachegen/Retain.qml b/tests/auto/qml/qmlcachegen/data/Retain.qml index 0e69012662..0e69012662 100644 --- a/tests/auto/qml/qmlcachegen/Retain.qml +++ b/tests/auto/qml/qmlcachegen/data/Retain.qml diff --git a/tests/auto/qml/qmlcachegen/data/componentInItem.qml b/tests/auto/qml/qmlcachegen/data/componentInItem.qml new file mode 100644 index 0000000000..820b9fddcd --- /dev/null +++ b/tests/auto/qml/qmlcachegen/data/componentInItem.qml @@ -0,0 +1,15 @@ +import QtQuick 2.12 + +Item { + Component { + Rectangle { + id: xxx + Text { + text: qsTr("&Undo") + } + Text { + text: qsTr("&Redo") + } + } + } +} diff --git a/tests/auto/qml/qmlcachegen/jsimport.qml b/tests/auto/qml/qmlcachegen/data/jsimport.qml index 9c40878e60..9c40878e60 100644 --- a/tests/auto/qml/qmlcachegen/jsimport.qml +++ b/tests/auto/qml/qmlcachegen/data/jsimport.qml diff --git a/tests/auto/qml/qmlcachegen/jsmoduleimport.qml b/tests/auto/qml/qmlcachegen/data/jsmoduleimport.qml index c1fad7fee2..c1fad7fee2 100644 --- a/tests/auto/qml/qmlcachegen/jsmoduleimport.qml +++ b/tests/auto/qml/qmlcachegen/data/jsmoduleimport.qml diff --git a/tests/auto/qml/qmlcachegen/library.js b/tests/auto/qml/qmlcachegen/data/library.js index 51fb41dc23..51fb41dc23 100644 --- a/tests/auto/qml/qmlcachegen/library.js +++ b/tests/auto/qml/qmlcachegen/data/library.js diff --git a/tests/auto/qml/qmlcachegen/script.js b/tests/auto/qml/qmlcachegen/data/script.js index fa55f9069e..fa55f9069e 100644 --- a/tests/auto/qml/qmlcachegen/script.js +++ b/tests/auto/qml/qmlcachegen/data/script.js diff --git a/tests/auto/qml/qmlcachegen/script.mjs b/tests/auto/qml/qmlcachegen/data/script.mjs index 459c336125..459c336125 100644 --- a/tests/auto/qml/qmlcachegen/script.mjs +++ b/tests/auto/qml/qmlcachegen/data/script.mjs diff --git a/tests/auto/qml/qmlcachegen/trickypaths.qml b/tests/auto/qml/qmlcachegen/data/trickypaths.qml index 0836808dc2..0836808dc2 100644 --- a/tests/auto/qml/qmlcachegen/trickypaths.qml +++ b/tests/auto/qml/qmlcachegen/data/trickypaths.qml diff --git a/tests/auto/qml/qmlcachegen/umlaut.qml b/tests/auto/qml/qmlcachegen/data/umlaut.qml index 0836808dc2..0836808dc2 100644 --- a/tests/auto/qml/qmlcachegen/umlaut.qml +++ b/tests/auto/qml/qmlcachegen/data/umlaut.qml diff --git a/tests/auto/qml/qmlcachegen/versionStyleSuffix-1.2-core-yc.qml b/tests/auto/qml/qmlcachegen/data/versionStyleSuffix-1.2-core-yc.qml index 0836808dc2..0836808dc2 100644 --- a/tests/auto/qml/qmlcachegen/versionStyleSuffix-1.2-core-yc.qml +++ b/tests/auto/qml/qmlcachegen/data/versionStyleSuffix-1.2-core-yc.qml diff --git a/tests/auto/qml/qmlcachegen/versionStyleSuffix-1.2-more.qml b/tests/auto/qml/qmlcachegen/data/versionStyleSuffix-1.2-more.qml index 0836808dc2..0836808dc2 100644 --- a/tests/auto/qml/qmlcachegen/versionStyleSuffix-1.2-more.qml +++ b/tests/auto/qml/qmlcachegen/data/versionStyleSuffix-1.2-more.qml diff --git a/tests/auto/qml/qmlcachegen/versionchecks.qml b/tests/auto/qml/qmlcachegen/data/versionchecks.qml index 77d67e7da4..77d67e7da4 100644 --- a/tests/auto/qml/qmlcachegen/versionchecks.qml +++ b/tests/auto/qml/qmlcachegen/data/versionchecks.qml diff --git a/tests/auto/qml/qmlcachegen/worker.js b/tests/auto/qml/qmlcachegen/data/worker.js index dd2d0b843d..dd2d0b843d 100644 --- a/tests/auto/qml/qmlcachegen/worker.js +++ b/tests/auto/qml/qmlcachegen/data/worker.js diff --git a/tests/auto/qml/qmlcachegen/worker.qml b/tests/auto/qml/qmlcachegen/data/worker.qml index 1f1c9d1ac7..1f1c9d1ac7 100644 --- a/tests/auto/qml/qmlcachegen/worker.qml +++ b/tests/auto/qml/qmlcachegen/data/worker.qml diff --git a/tests/auto/qml/qmlcachegen/qmlcachegen.pro b/tests/auto/qml/qmlcachegen/qmlcachegen.pro index c7820ac1cd..7bd4414302 100644 --- a/tests/auto/qml/qmlcachegen/qmlcachegen.pro +++ b/tests/auto/qml/qmlcachegen/qmlcachegen.pro @@ -2,26 +2,34 @@ CONFIG += testcase qtquickcompiler TARGET = tst_qmlcachegen macos:CONFIG -= app_bundle +include (../../shared/util.pri) +TESTDATA = data/* + SOURCES += tst_qmlcachegen.cpp -workerscripts_test.files = worker.js worker.qml +RESOURCES += \ + data/versionchecks.qml \ + data/jsimport.qml \ + data/script.js \ + data/library.js \ + data/Enums.qml \ + data/componentInItem.qml \ + data/jsmoduleimport.qml \ + data/script.mjs + +workerscripts_test.files = \ + data/worker.js \ + data/worker.qml workerscripts_test.prefix = /workerscripts -RESOURCES += workerscripts_test - -RESOURCES += versionchecks.qml - -RESOURCES += trickypaths.qrc -RESOURCES += jsimport.qml script.js library.js - -RESOURCES += Enums.qml +RESOURCES += \ + workerscripts_test \ + trickypaths.qrc \ + retain.qrc # QTBUG-46375 !win32: RESOURCES += trickypaths_umlaut.qrc -RESOURCES += jsmoduleimport.qml script.mjs - -RESOURCES += retain.qrc QTQUICK_COMPILER_RETAINED_RESOURCES += retain.qrc QT += core-private qml-private testlib diff --git a/tests/auto/qml/qmlcachegen/retain.qrc b/tests/auto/qml/qmlcachegen/retain.qrc index af042b25d8..e5eed9b12f 100644 --- a/tests/auto/qml/qmlcachegen/retain.qrc +++ b/tests/auto/qml/qmlcachegen/retain.qrc @@ -1,5 +1,5 @@ <RCC> <qresource prefix="/"> - <file>Retain.qml</file> + <file alias="Retain.qml">data/Retain.qml</file> </qresource> </RCC> diff --git a/tests/auto/qml/qmlcachegen/trickypaths.qrc b/tests/auto/qml/qmlcachegen/trickypaths.qrc index 57977ccf6d..b0c3bcf209 100644 --- a/tests/auto/qml/qmlcachegen/trickypaths.qrc +++ b/tests/auto/qml/qmlcachegen/trickypaths.qrc @@ -1,7 +1,7 @@ <!DOCTYPE RCC><RCC version="1.0"> <qresource prefix="/directory with spaces"> -<file alias="file name with spaces.qml">trickypaths.qml</file> -<file>versionStyleSuffix-1.2-core-yc.qml</file> -<file>versionStyleSuffix-1.2-more.qml</file> +<file alias="file name with spaces.qml">data/trickypaths.qml</file> +<file alias="versionStyleSuffix-1.2-core-yc.qml">data/versionStyleSuffix-1.2-core-yc.qml</file> +<file alias="versionStyleSuffix-1.2-more.qml">data/versionStyleSuffix-1.2-more.qml</file> </qresource> </RCC> diff --git a/tests/auto/qml/qmlcachegen/trickypaths_umlaut.qrc b/tests/auto/qml/qmlcachegen/trickypaths_umlaut.qrc index 9ca889d692..17aa30473f 100644 --- a/tests/auto/qml/qmlcachegen/trickypaths_umlaut.qrc +++ b/tests/auto/qml/qmlcachegen/trickypaths_umlaut.qrc @@ -1,5 +1,5 @@ <!DOCTYPE RCC><RCC version="1.0"> <qresource prefix="/"> -<file alias="Bäh.qml">umlaut.qml</file> +<file alias="Bäh.qml">data/umlaut.qml</file> </qresource> </RCC> diff --git a/tests/auto/qml/qmlcachegen/tst_qmlcachegen.cpp b/tests/auto/qml/qmlcachegen/tst_qmlcachegen.cpp index 8cfa4cb6af..5462e6c8ae 100644 --- a/tests/auto/qml/qmlcachegen/tst_qmlcachegen.cpp +++ b/tests/auto/qml/qmlcachegen/tst_qmlcachegen.cpp @@ -38,7 +38,9 @@ #include <private/qqmlcomponent_p.h> #include <qtranslator.h> -class tst_qmlcachegen: public QObject +#include "../../shared/util.h" + +class tst_qmlcachegen: public QQmlDataTest { Q_OBJECT @@ -66,6 +68,9 @@ private slots: void enums(); void sourceFileIndices(); + + void reproducibleCache_data(); + void reproducibleCache(); }; // A wrapper around QQmlComponent to ensure the temporary reference counts @@ -353,12 +358,13 @@ static QQmlPrivate::CachedQmlUnit *temporaryModifiedCachedUnit = nullptr; void tst_qmlcachegen::versionChecksForAheadOfTimeUnits() { - QVERIFY(QFile::exists(":/versionchecks.qml")); - QCOMPARE(QFileInfo(":/versionchecks.qml").size(), 0); + QVERIFY(QFile::exists(":/data/versionchecks.qml")); + QCOMPARE(QFileInfo(":/data/versionchecks.qml").size(), 0); Q_ASSERT(!temporaryModifiedCachedUnit); QQmlMetaType::CachedUnitLookupError error = QQmlMetaType::CachedUnitLookupError::NoError; - const QV4::CompiledData::Unit *originalUnit = QQmlMetaType::findCachedCompilationUnit(QUrl("qrc:/versionchecks.qml"), &error); + const QV4::CompiledData::Unit *originalUnit = QQmlMetaType::findCachedCompilationUnit( + QUrl("qrc:/data/versionchecks.qml"), &error); QVERIFY(originalUnit); QV4::CompiledData::Unit *tweakedUnit = (QV4::CompiledData::Unit *)malloc(originalUnit->unitSize); memcpy(reinterpret_cast<void *>(tweakedUnit), reinterpret_cast<const void *>(originalUnit), originalUnit->unitSize); @@ -366,7 +372,7 @@ void tst_qmlcachegen::versionChecksForAheadOfTimeUnits() temporaryModifiedCachedUnit = new QQmlPrivate::CachedQmlUnit{tweakedUnit, nullptr, nullptr}; auto testHandler = [](const QUrl &url) -> const QQmlPrivate::CachedQmlUnit * { - if (url == QUrl("qrc:/versionchecks.qml")) + if (url == QUrl("qrc:/data/versionchecks.qml")) return temporaryModifiedCachedUnit; return nullptr; }; @@ -374,15 +380,18 @@ void tst_qmlcachegen::versionChecksForAheadOfTimeUnits() { QQmlMetaType::CachedUnitLookupError error = QQmlMetaType::CachedUnitLookupError::NoError; - QVERIFY(!QQmlMetaType::findCachedCompilationUnit(QUrl("qrc:/versionchecks.qml"), &error)); + QVERIFY(!QQmlMetaType::findCachedCompilationUnit(QUrl("qrc:/data/versionchecks.qml"), &error)); QCOMPARE(error, QQmlMetaType::CachedUnitLookupError::VersionMismatch); } { QQmlEngine engine; - QQmlComponent component(&engine, QUrl("qrc:/versionchecks.qml")); + QQmlComponent component(&engine, QUrl("qrc:/data/versionchecks.qml")); QCOMPARE(component.status(), QQmlComponent::Error); - QCOMPARE(component.errorString(), QString("qrc:/versionchecks.qml:-1 File was compiled ahead of time with an incompatible version of Qt and the original file cannot be found. Please recompile\n")); + QCOMPARE(component.errorString(), + QString("qrc:/data/versionchecks.qml:-1 File was compiled ahead of time with an " + "incompatible version of Qt and the original file cannot be found. Please " + "recompile\n")); } Q_ASSERT(temporaryModifiedCachedUnit); @@ -402,12 +411,12 @@ void tst_qmlcachegen::retainedResources() void tst_qmlcachegen::workerScripts() { - QVERIFY(QFile::exists(":/workerscripts/worker.js")); - QVERIFY(QFile::exists(":/workerscripts/worker.qml")); - QCOMPARE(QFileInfo(":/workerscripts/worker.js").size(), 0); + QVERIFY(QFile::exists(":/workerscripts/data/worker.js")); + QVERIFY(QFile::exists(":/workerscripts/data/worker.qml")); + QCOMPARE(QFileInfo(":/workerscripts/data/worker.js").size(), 0); QQmlEngine engine; - CleanlyLoadingComponent component(&engine, QUrl("qrc:///workerscripts/worker.qml")); + CleanlyLoadingComponent component(&engine, QUrl("qrc:///workerscripts/data/worker.qml")); QScopedPointer<QObject> obj(component.create()); QVERIFY(!obj.isNull()); QTRY_VERIFY(obj->property("success").toBool()); @@ -504,7 +513,7 @@ void tst_qmlcachegen::trickyPaths() void tst_qmlcachegen::qrcScriptImport() { QQmlEngine engine; - CleanlyLoadingComponent component(&engine, QUrl("qrc:///jsimport.qml")); + CleanlyLoadingComponent component(&engine, QUrl("qrc:///data/jsimport.qml")); QScopedPointer<QObject> obj(component.create()); QVERIFY(!obj.isNull()); QTRY_COMPARE(obj->property("value").toInt(), 42); @@ -567,14 +576,14 @@ void tst_qmlcachegen::fsScriptImport() void tst_qmlcachegen::moduleScriptImport() { QQmlEngine engine; - CleanlyLoadingComponent component(&engine, QUrl("qrc:///jsmoduleimport.qml")); + CleanlyLoadingComponent component(&engine, QUrl("qrc:///data/jsmoduleimport.qml")); QVERIFY2(!component.isError(), qPrintable(component.errorString())); QScopedPointer<QObject> obj(component.create()); QVERIFY(!obj.isNull()); QTRY_VERIFY(obj->property("ok").toBool()); - QVERIFY(QFile::exists(":/script.mjs")); - QCOMPARE(QFileInfo(":/script.mjs").size(), 0); + QVERIFY(QFile::exists(":/data/script.mjs")); + QCOMPARE(QFileInfo(":/data/script.mjs").size(), 0); { auto componentPrivate = QQmlComponentPrivate::get(&component); @@ -587,7 +596,8 @@ void tst_qmlcachegen::moduleScriptImport() QVERIFY(unitData->flags & QV4::CompiledData::Unit::IsESModule); QQmlMetaType::CachedUnitLookupError error = QQmlMetaType::CachedUnitLookupError::NoError; - const QV4::CompiledData::Unit *unitFromResources = QQmlMetaType::findCachedCompilationUnit(QUrl("qrc:/script.mjs"), &error); + const QV4::CompiledData::Unit *unitFromResources = QQmlMetaType::findCachedCompilationUnit( + QUrl("qrc:/data/script.mjs"), &error); QVERIFY(unitFromResources); QCOMPARE(unitFromResources, compilationUnit->unitData()); @@ -597,7 +607,7 @@ void tst_qmlcachegen::moduleScriptImport() void tst_qmlcachegen::enums() { QQmlEngine engine; - CleanlyLoadingComponent component(&engine, QUrl("qrc:///Enums.qml")); + CleanlyLoadingComponent component(&engine, QUrl("qrc:///data/Enums.qml")); QScopedPointer<QObject> obj(component.create()); QVERIFY(!obj.isNull()); QTRY_COMPARE(obj->property("value").toInt(), 200); @@ -605,16 +615,50 @@ void tst_qmlcachegen::enums() void tst_qmlcachegen::sourceFileIndices() { - QVERIFY(QFile::exists(":/versionchecks.qml")); - QCOMPARE(QFileInfo(":/versionchecks.qml").size(), 0); + QVERIFY(QFile::exists(":/data/versionchecks.qml")); + QCOMPARE(QFileInfo(":/data/versionchecks.qml").size(), 0); QQmlMetaType::CachedUnitLookupError error = QQmlMetaType::CachedUnitLookupError::NoError; - const QV4::CompiledData::Unit *unitFromResources = QQmlMetaType::findCachedCompilationUnit(QUrl("qrc:/versionchecks.qml"), &error); + const QV4::CompiledData::Unit *unitFromResources = QQmlMetaType::findCachedCompilationUnit( + QUrl("qrc:/data/versionchecks.qml"), &error); QVERIFY(unitFromResources); QVERIFY(unitFromResources->flags & QV4::CompiledData::Unit::PendingTypeCompilation); QCOMPARE(uint(unitFromResources->sourceFileIndex), uint(0)); } +void tst_qmlcachegen::reproducibleCache_data() +{ + QTest::addColumn<QString>("filePath"); + + QDir dir(dataDirectory()); + for (const QString &entry : dir.entryList(QDir::Files)) { + QVERIFY(entry.endsWith(".qml") || entry.endsWith(".js") || entry.endsWith(".mjs")); + QTest::newRow(entry.toUtf8().constData()) << dir.filePath(entry); + } +} + +void tst_qmlcachegen::reproducibleCache() +{ + QFETCH(QString, filePath); + + QFile file(filePath); + QVERIFY(file.exists()); + + auto generate = [](const QString &path) { + if (!generateCache(path)) + return QByteArray(); + QFile generated(path + 'c'); + [&](){ QVERIFY(generated.open(QIODevice::ReadOnly)); }(); + const QByteArray result = generated.readAll(); + generated.remove(); + return result; + }; + + const QByteArray contents1 = generate(file.fileName()); + const QByteArray contents2 = generate(file.fileName()); + QCOMPARE(contents1, contents2); +} + QTEST_GUILESS_MAIN(tst_qmlcachegen) #include "tst_qmlcachegen.moc" diff --git a/tests/auto/qml/qmldiskcache/tst_qmldiskcache.cpp b/tests/auto/qml/qmldiskcache/tst_qmldiskcache.cpp index 70a5a73e0f..e86b7bf5fe 100644 --- a/tests/auto/qml/qmldiskcache/tst_qmldiskcache.cpp +++ b/tests/auto/qml/qmldiskcache/tst_qmldiskcache.cpp @@ -30,7 +30,6 @@ #include <private/qv4compileddata_p.h> #include <private/qv4compiler_p.h> -#include <private/qv8engine_p.h> #include <private/qv4engine_p.h> #include <private/qv4codegen_p.h> #include <private/qqmlcomponent_p.h> diff --git a/tests/auto/qml/qmlmin/tst_qmlmin.cpp b/tests/auto/qml/qmlmin/tst_qmlmin.cpp index c393149f59..d1e74aecef 100644 --- a/tests/auto/qml/qmlmin/tst_qmlmin.cpp +++ b/tests/auto/qml/qmlmin/tst_qmlmin.cpp @@ -128,6 +128,7 @@ void tst_qmlmin::initTestCase() invalidFiles << "tests/auto/qml/parserstress/tests/ecma_3/FunExpr/fe-001.js"; invalidFiles << "tests/auto/qml/qjsengine/script/com/trolltech/syntaxerror/__init__.js"; invalidFiles << "tests/auto/qml/debugger/qqmlpreview/data/broken.qml"; + invalidFiles << "tests/auto/qml/qqmllanguage/data/fuzzed.2.qml"; } QStringList tst_qmlmin::findFiles(const QDir &d) diff --git a/tests/auto/qml/qqmlcomponent/tst_qqmlcomponent.cpp b/tests/auto/qml/qqmlcomponent/tst_qqmlcomponent.cpp index 7c7c7d3bd0..98ae86d248 100644 --- a/tests/auto/qml/qqmlcomponent/tst_qqmlcomponent.cpp +++ b/tests/auto/qml/qqmlcomponent/tst_qqmlcomponent.cpp @@ -35,7 +35,6 @@ #include <QtQuick> #include <QtQuick/private/qquickrectangle_p.h> #include <QtQuick/private/qquickmousearea_p.h> -#include <private/qv8engine_p.h> #include <private/qqmlcontext_p.h> #include <private/qv4qmlcontext_p.h> #include <private/qv4scopedvalue_p.h> diff --git a/tests/auto/qml/qqmlecmascript/data/signalHandlers.qml b/tests/auto/qml/qqmlecmascript/data/signalHandlers.qml index 14326bb9e6..a924519f0f 100644 --- a/tests/auto/qml/qqmlecmascript/data/signalHandlers.qml +++ b/tests/auto/qml/qqmlecmascript/data/signalHandlers.qml @@ -8,6 +8,8 @@ QtObject { signal testSignal onTestSignal: count++ + readonly property string scopeObjectAsString: this.toString() + property int funcCount: 0 function testFunction() { funcCount++; diff --git a/tests/auto/qml/qqmlecmascript/testtypes.h b/tests/auto/qml/qqmlecmascript/testtypes.h index 32120ee5b7..730dc7cab8 100644 --- a/tests/auto/qml/qqmlecmascript/testtypes.h +++ b/tests/auto/qml/qqmlecmascript/testtypes.h @@ -50,7 +50,6 @@ #include <QtQml/qqmlcomponent.h> #include <private/qqmlengine_p.h> -#include <private/qv8engine_p.h> #include <private/qv4qobjectwrapper_p.h> class MyQmlAttachedObject : public QObject @@ -797,11 +796,11 @@ public: Q_INVOKABLE void method_real(qreal a) { invoke(10); m_actuals << a; } Q_INVOKABLE void method_QString(QString a) { invoke(11); m_actuals << a; } Q_INVOKABLE void method_QPointF(QPointF a) { invoke(12); m_actuals << a; } - Q_INVOKABLE void method_QObject(QObject *a) { invoke(13); m_actuals << qVariantFromValue(a); } - Q_INVOKABLE void method_QScriptValue(QJSValue a) { invoke(14); m_actuals << qVariantFromValue(a); } - Q_INVOKABLE void method_intQScriptValue(int a, QJSValue b) { invoke(15); m_actuals << a << qVariantFromValue(b); } + Q_INVOKABLE void method_QObject(QObject *a) { invoke(13); m_actuals << QVariant::fromValue(a); } + Q_INVOKABLE void method_QScriptValue(QJSValue a) { invoke(14); m_actuals << QVariant::fromValue(a); } + Q_INVOKABLE void method_intQScriptValue(int a, QJSValue b) { invoke(15); m_actuals << a << QVariant::fromValue(b); } Q_INVOKABLE void method_QByteArray(QByteArray value) { invoke(29); m_actuals << value; } - Q_INVOKABLE QJSValue method_intQJSValue(int a, QJSValue b) { invoke(30); m_actuals << a << qVariantFromValue(b); return b.call(); } + Q_INVOKABLE QJSValue method_intQJSValue(int a, QJSValue b) { invoke(30); m_actuals << a << QVariant::fromValue(b); return b.call(); } Q_INVOKABLE QJSValue method_intQJSValue(int a, int b) { m_actuals << a << b; return QJSValue();} // Should never be called. Q_INVOKABLE void method_overload(int a) { invoke(16); m_actuals << a; } diff --git a/tests/auto/qml/qqmlecmascript/tst_qqmlecmascript.cpp b/tests/auto/qml/qqmlecmascript/tst_qqmlecmascript.cpp index b4349f79ca..98f9bfe3ef 100644 --- a/tests/auto/qml/qqmlecmascript/tst_qqmlecmascript.cpp +++ b/tests/auto/qml/qqmlecmascript/tst_qqmlecmascript.cpp @@ -364,6 +364,9 @@ private slots: void arrayAndException(); void numberToStringWithRadix(); void tailCallWithArguments(); + void deleteSparseInIteration(); + void saveAccumulatorBeforeToInt32(); + void intMinDividedByMinusOne(); private: // static void propertyVarWeakRefCallback(v8::Persistent<v8::Value> object, void* parameter); @@ -1607,7 +1610,7 @@ void tst_qqmlecmascript::aliasPropertyReset() // test that a manual write (of undefined) to a non-resettable property fails properly QUrl url = testFileUrl("aliasreset/aliasPropertyReset.error.1.qml"); - QString warning1 = url.toString() + QLatin1String(": Error: Cannot assign [undefined] to int"); + QString warning1 = url.toString() + QLatin1String(":15: Error: Cannot assign [undefined] to int"); QQmlComponent e1(&engine, url); object = e1.create(); QVERIFY(object != nullptr); @@ -2830,35 +2833,35 @@ void tst_qqmlecmascript::callQtInvokables() QCOMPARE(o->error(), false); QCOMPARE(o->invoked(), 13); QCOMPARE(o->actuals().count(), 1); - QCOMPARE(o->actuals().at(0), qVariantFromValue((QObject *)nullptr)); + QCOMPARE(o->actuals().at(0), QVariant::fromValue((QObject *)nullptr)); o->reset(); QVERIFY(EVALUATE_VALUE("object.method_QObject(\"Hello world\")", QV4::Primitive::undefinedValue())); QCOMPARE(o->error(), false); QCOMPARE(o->invoked(), 13); QCOMPARE(o->actuals().count(), 1); - QCOMPARE(o->actuals().at(0), qVariantFromValue((QObject *)nullptr)); + QCOMPARE(o->actuals().at(0), QVariant::fromValue((QObject *)nullptr)); o->reset(); QVERIFY(EVALUATE_VALUE("object.method_QObject(null)", QV4::Primitive::undefinedValue())); QCOMPARE(o->error(), false); QCOMPARE(o->invoked(), 13); QCOMPARE(o->actuals().count(), 1); - QCOMPARE(o->actuals().at(0), qVariantFromValue((QObject *)nullptr)); + QCOMPARE(o->actuals().at(0), QVariant::fromValue((QObject *)nullptr)); o->reset(); QVERIFY(EVALUATE_VALUE("object.method_QObject(undefined)", QV4::Primitive::undefinedValue())); QCOMPARE(o->error(), false); QCOMPARE(o->invoked(), 13); QCOMPARE(o->actuals().count(), 1); - QCOMPARE(o->actuals().at(0), qVariantFromValue((QObject *)nullptr)); + QCOMPARE(o->actuals().at(0), QVariant::fromValue((QObject *)nullptr)); o->reset(); QVERIFY(EVALUATE_VALUE("object.method_QObject(object)", QV4::Primitive::undefinedValue())); QCOMPARE(o->error(), false); QCOMPARE(o->invoked(), 13); QCOMPARE(o->actuals().count(), 1); - QCOMPARE(o->actuals().at(0), qVariantFromValue((QObject *)o)); + QCOMPARE(o->actuals().at(0), QVariant::fromValue((QObject *)o)); o->reset(); QVERIFY(EVALUATE_VALUE("object.method_QScriptValue(null)", QV4::Primitive::undefinedValue())); @@ -6492,7 +6495,8 @@ void tst_qqmlecmascript::signalHandlers() QMetaObject::invokeMethod(o.data(), "testSignalHandlerCall"); QCOMPARE(o->property("count").toInt(), 1); - QCOMPARE(o->property("errorString").toString(), QLatin1String("TypeError: Property 'onTestSignal' of object [object Object] is not a function")); + QString scopeObjectAsString = o->property("scopeObjectAsString").toString(); + QCOMPARE(o->property("errorString").toString(), QString("TypeError: Property 'onTestSignal' of object %1 is not a function").arg(scopeObjectAsString)); QCOMPARE(o->property("funcCount").toInt(), 0); QMetaObject::invokeMethod(o.data(), "testSignalConnection"); @@ -8187,12 +8191,11 @@ void tst_qqmlecmascript::stackLimits() void tst_qqmlecmascript::idsAsLValues() { QQmlEngine engine; - QString err = QString(QLatin1String("%1:5 left-hand side of assignment operator is not an lvalue\n")).arg(testFileUrl("idAsLValue.qml").toString()); + QString err = QString(QLatin1String("%1:5: Error: left-hand side of assignment operator is not an lvalue")).arg(testFileUrl("idAsLValue.qml").toString()); QQmlComponent component(&engine, testFileUrl("idAsLValue.qml")); - QTest::ignoreMessage(QtWarningMsg, "QQmlComponent: Component is not ready"); + QTest::ignoreMessage(QtWarningMsg, qPrintable(err)); MyQmlObject *object = qobject_cast<MyQmlObject*>(component.create()); QVERIFY(!object); - QCOMPARE(component.errorString(), err); } void tst_qqmlecmascript::qtbug_34792() @@ -8933,6 +8936,54 @@ void tst_qqmlecmascript::tailCallWithArguments() QCOMPARE(value.toInt(), 1); } +void tst_qqmlecmascript::deleteSparseInIteration() +{ + QJSEngine engine; + const QJSValue value = engine.evaluate( + "(function() {\n" + " var obj = { 1: null, 2: null, 4096: null };\n" + " var iterated = [];\n" + " for (var t in obj) {\n" + " if (t == 2)\n" + " delete obj[t];\n" + " iterated.push(t);\n" + " }\n" + " return iterated;" + "})()"); + QVERIFY(value.isArray()); + QCOMPARE(value.property("length").toInt(), 3); + QCOMPARE(value.property("0").toInt(), 1); + QCOMPARE(value.property("1").toInt(), 2); + QCOMPARE(value.property("2").toInt(), 4096); +} + +void tst_qqmlecmascript::saveAccumulatorBeforeToInt32() +{ + QJSEngine engine; + + // Infinite recursion produces a range error, but should not crash. + // Also, any GC runs in between should not trash the temporary results of "a+a". + const QJSValue value = engine.evaluate("function a(){a(a&a+a)}a()"); + QVERIFY(value.isError()); + QCOMPARE(value.toString(), QLatin1String("RangeError: Maximum call stack size exceeded.")); +} + +void tst_qqmlecmascript::intMinDividedByMinusOne() +{ + QQmlEngine engine; + QQmlComponent component(&engine); + component.setData(QByteArray("import QtQml 2.2\n" + "QtObject {\n" + " property int intMin: -2147483648\n" + " property int minusOne: -1\n" + " property double doesNotFitInInt: intMin / minusOne\n" + "}"), QUrl()); + QVERIFY(component.isReady()); + QScopedPointer<QObject> object(component.create()); + QVERIFY(!object.isNull()); + QCOMPARE(object->property("doesNotFitInInt").toUInt(), 2147483648u); +} + QTEST_MAIN(tst_qqmlecmascript) #include "tst_qqmlecmascript.moc" diff --git a/tests/auto/qml/qqmlengine/tst_qqmlengine.cpp b/tests/auto/qml/qqmlengine/tst_qqmlengine.cpp index f58ae38264..b9cb6b70d2 100644 --- a/tests/auto/qml/qqmlengine/tst_qqmlengine.cpp +++ b/tests/auto/qml/qqmlengine/tst_qqmlengine.cpp @@ -80,6 +80,7 @@ private slots: void qrcUrls(); void cppSignalAndEval(); void singletonInstance(); + void aggressiveGc(); public slots: QObject *createAQObjectForOwnershipTest () @@ -1043,6 +1044,18 @@ void tst_qqmlengine::singletonInstance() } } +void tst_qqmlengine::aggressiveGc() +{ + const QByteArray origAggressiveGc = qgetenv("QV4_MM_AGGRESSIVE_GC"); + qputenv("QV4_MM_AGGRESSIVE_GC", "true"); + { + QQmlEngine engine; // freezing should not run into infinite recursion + QJSValue obj = engine.newObject(); + QVERIFY(obj.isObject()); + } + qputenv("QV4_MM_AGGRESSIVE_GC", origAggressiveGc); +} + QTEST_MAIN(tst_qqmlengine) #include "tst_qqmlengine.moc" diff --git a/tests/auto/qml/qqmlimport/data/interceptQmldir.qml b/tests/auto/qml/qqmlimport/data/interceptQmldir.qml new file mode 100644 index 0000000000..bf485b2282 --- /dev/null +++ b/tests/auto/qml/qqmlimport/data/interceptQmldir.qml @@ -0,0 +1,7 @@ +import QtQml 2.2 + +import "$(INTERCEPT)" as Intercepted + +QtObject { + property QtObject view: Intercepted.View {} +} diff --git a/tests/auto/qml/qqmlimport/data/intercepted/View.qml b/tests/auto/qml/qqmlimport/data/intercepted/View.qml new file mode 100644 index 0000000000..92aa3af95a --- /dev/null +++ b/tests/auto/qml/qqmlimport/data/intercepted/View.qml @@ -0,0 +1,5 @@ +import QtQml 2.2 + +QtObject { + property int foo: 12 +} diff --git a/tests/auto/qml/qqmlimport/data/intercepted/qmldir b/tests/auto/qml/qqmlimport/data/intercepted/qmldir new file mode 100644 index 0000000000..ab31de73d8 --- /dev/null +++ b/tests/auto/qml/qqmlimport/data/intercepted/qmldir @@ -0,0 +1,2 @@ +module SomeModule +View 1.0 View.qml diff --git a/tests/auto/qml/qqmlimport/tst_qqmlimport.cpp b/tests/auto/qml/qqmlimport/tst_qqmlimport.cpp index 70aaa9678e..a3cb68fdcb 100644 --- a/tests/auto/qml/qqmlimport/tst_qqmlimport.cpp +++ b/tests/auto/qml/qqmlimport/tst_qqmlimport.cpp @@ -28,6 +28,7 @@ #include <QtTest/QtTest> #include <QQmlApplicationEngine> +#include <QQmlAbstractUrlInterceptor> #include <QtQuick/qquickview.h> #include <QtQuick/qquickitem.h> #include <private/qqmlimport_p.h> @@ -43,6 +44,7 @@ private slots: void uiFormatLoading(); void completeQmldirPaths_data(); void completeQmldirPaths(); + void interceptQmldir(); void cleanup(); }; @@ -185,6 +187,32 @@ void tst_QQmlImport::completeQmldirPaths() QCOMPARE(QQmlImports::completeQmldirPaths(uri, basePaths, majorVersion, minorVersion), expectedPaths); } +class QmldirUrlInterceptor : public QQmlAbstractUrlInterceptor { +public: + QUrl intercept(const QUrl &url, DataType type) override + { + if (type != UrlString && !url.isEmpty() && url.isValid()) { + QString str = url.toString(QUrl::None); + return str.replace(QStringLiteral("$(INTERCEPT)"), QStringLiteral("intercepted")); + } + return url; + } +}; + +void tst_QQmlImport::interceptQmldir() +{ + QQmlEngine engine; + QmldirUrlInterceptor interceptor; + engine.setUrlInterceptor(&interceptor); + + QQmlComponent component(&engine); + component.loadUrl(testFileUrl("interceptQmldir.qml")); + QVERIFY(component.isReady()); + QScopedPointer<QObject> obj(component.create()); + QVERIFY(!obj.isNull()); +} + + QTEST_MAIN(tst_QQmlImport) #include "tst_qqmlimport.moc" diff --git a/tests/auto/qml/qqmllanguage/data/EdgeObject.qml b/tests/auto/qml/qqmllanguage/data/EdgeObject.qml new file mode 100644 index 0000000000..b25dc29c49 --- /dev/null +++ b/tests/auto/qml/qqmllanguage/data/EdgeObject.qml @@ -0,0 +1,20 @@ +import QtQuick 2.0 + +Item { + property int edgeWidth: bg.width + + Rectangle { + id: bg + } + + states: [ + State { + when: 1 === 1 + PropertyChanges { + target: bg + anchors.left: parent.left + anchors.right: parent.right + } + } + ] +} diff --git a/tests/auto/qml/qqmllanguage/data/anchorsToParentInPropertyChagnes.qml b/tests/auto/qml/qqmllanguage/data/anchorsToParentInPropertyChagnes.qml new file mode 100644 index 0000000000..8b1682da92 --- /dev/null +++ b/tests/auto/qml/qqmllanguage/data/anchorsToParentInPropertyChagnes.qml @@ -0,0 +1,10 @@ +import QtQuick 2.9 + +Item { + width: 200 + property int edgeWidth: edge.edgeWidth + EdgeObject { + id: edge + anchors.fill: parent + } +} diff --git a/tests/auto/qml/qqmllanguage/data/cyclicAlias.errors.txt b/tests/auto/qml/qqmllanguage/data/cyclicAlias.errors.txt new file mode 100644 index 0000000000..46951ef69f --- /dev/null +++ b/tests/auto/qml/qqmllanguage/data/cyclicAlias.errors.txt @@ -0,0 +1 @@ +4:5:Cyclic alias diff --git a/tests/auto/qml/qqmllanguage/data/cyclicAlias.qml b/tests/auto/qml/qqmllanguage/data/cyclicAlias.qml new file mode 100644 index 0000000000..23129e210d --- /dev/null +++ b/tests/auto/qml/qqmllanguage/data/cyclicAlias.qml @@ -0,0 +1,5 @@ +import QtQml 2.2 +QtObject { + id: o + property alias t: o.t +} diff --git a/tests/auto/qml/qqmllanguage/data/fuzzed.1.errors.txt b/tests/auto/qml/qqmllanguage/data/fuzzed.1.errors.txt new file mode 100644 index 0000000000..e399799fe9 --- /dev/null +++ b/tests/auto/qml/qqmllanguage/data/fuzzed.1.errors.txt @@ -0,0 +1,2 @@ +2:8:Cannot assign to non-existent property "_G" + diff --git a/tests/auto/qml/qqmllanguage/data/fuzzed.1.qml b/tests/auto/qml/qqmllanguage/data/fuzzed.1.qml new file mode 100644 index 0000000000..f80b9c3a2d --- /dev/null +++ b/tests/auto/qml/qqmllanguage/data/fuzzed.1.qml @@ -0,0 +1,2 @@ +import QtQuick 2.4 +Item { _G.G.G:G } diff --git a/tests/auto/qml/qqmllanguage/data/fuzzed.2.errors.txt b/tests/auto/qml/qqmllanguage/data/fuzzed.2.errors.txt new file mode 100644 index 0000000000..92ce4c649f --- /dev/null +++ b/tests/auto/qml/qqmllanguage/data/fuzzed.2.errors.txt @@ -0,0 +1,2 @@ +5:1:TetZ$ is not a type +-1:-1:Invalid QML type name "TetZ$" diff --git a/tests/auto/qml/qqmllanguage/data/fuzzed.2.qml b/tests/auto/qml/qqmllanguage/data/fuzzed.2.qml Binary files differnew file mode 100644 index 0000000000..e726f6783c --- /dev/null +++ b/tests/auto/qml/qqmllanguage/data/fuzzed.2.qml diff --git a/tests/auto/qml/qqmllanguage/data/objectValueTypeProperty.errors.txt b/tests/auto/qml/qqmllanguage/data/objectValueTypeProperty.errors.txt index cefd62f9d4..945dacf8ab 100644 --- a/tests/auto/qml/qqmllanguage/data/objectValueTypeProperty.errors.txt +++ b/tests/auto/qml/qqmllanguage/data/objectValueTypeProperty.errors.txt @@ -1 +1 @@ -4:18:Unexpected object assignment for property "x" +4:18:Can not assign value of type "int" to property "x", expecting an object diff --git a/tests/auto/qml/qqmllanguage/data/thisInQmlScope.qml b/tests/auto/qml/qqmllanguage/data/thisInQmlScope.qml index e3c99e70e1..9ff758c33f 100644 --- a/tests/auto/qml/qqmllanguage/data/thisInQmlScope.qml +++ b/tests/auto/qml/qqmllanguage/data/thisInQmlScope.qml @@ -6,5 +6,18 @@ QtObject { y = this.x; } property var f: g + Component.onCompleted: f() + + property int a: 42 + property int b: 0 + function g_subobj(){ + b = this.a; + } + property var f_subobj: g_subobj + + property QtObject subObject: QtObject { + property int a: 100 + Component.onCompleted: f_subobj() + } } diff --git a/tests/auto/qml/qqmllanguage/tst_qqmllanguage.cpp b/tests/auto/qml/qqmllanguage/tst_qqmllanguage.cpp index 32bab2954d..1b4ff71beb 100644 --- a/tests/auto/qml/qqmllanguage/tst_qqmllanguage.cpp +++ b/tests/auto/qml/qqmllanguage/tst_qqmllanguage.cpp @@ -299,6 +299,7 @@ private slots: void retrieveQmlTypeId(); void polymorphicFunctionLookup(); + void anchorsToParentInPropertyChanges(); private: QQmlEngine engine; @@ -360,7 +361,7 @@ private: } \ file.close(); \ } else { \ - QCOMPARE(expected, actual); \ + QCOMPARE(actual, expected); \ } \ } @@ -613,6 +614,10 @@ void tst_qqmllanguage::errors_data() QTest::newRow("badCompositeRegistration.2") << "badCompositeRegistration.2.qml" << "badCompositeRegistration.2.errors.txt" << false; QTest::newRow("assignComponentToWrongType") << "assignComponentToWrongType.qml" << "assignComponentToWrongType.errors.txt" << false; + QTest::newRow("cyclicAlias") << "cyclicAlias.qml" << "cyclicAlias.errors.txt" << false; + + QTest::newRow("fuzzed.1") << "fuzzed.1.qml" << "fuzzed.1.errors.txt" << false; + QTest::newRow("fuzzed.2") << "fuzzed.2.qml" << "fuzzed.2.errors.txt" << false; } @@ -623,6 +628,7 @@ void tst_qqmllanguage::errors() QFETCH(bool, create); QQmlComponent component(&engine, testFileUrl(file)); + QTRY_VERIFY(!component.isLoading()); QScopedPointer<QObject> object; @@ -1450,8 +1456,8 @@ void tst_qqmllanguage::dynamicObjectProperties() QScopedPointer<QObject> object(component.create()); QVERIFY(object != nullptr); - QCOMPARE(object->property("objectProperty"), qVariantFromValue((QObject*)nullptr)); - QVERIFY(object->property("objectProperty2") != qVariantFromValue((QObject*)nullptr)); + QCOMPARE(object->property("objectProperty"), QVariant::fromValue((QObject*)nullptr)); + QVERIFY(object->property("objectProperty2") != QVariant::fromValue((QObject*)nullptr)); } { QQmlComponent component(&engine, testFileUrl("dynamicObjectProperties.2.qml")); @@ -1459,7 +1465,7 @@ void tst_qqmllanguage::dynamicObjectProperties() QScopedPointer<QObject> object(component.create()); QVERIFY(object != nullptr); - QVERIFY(object->property("objectProperty") != qVariantFromValue((QObject*)nullptr)); + QVERIFY(object->property("objectProperty") != QVariant::fromValue((QObject*)nullptr)); } } @@ -1728,7 +1734,7 @@ void tst_qqmllanguage::aliasProperties() // Write through alias MyQmlObject *v2 = new MyQmlObject(); v2->setParent(object.data()); - object->setProperty("aliasObject", qVariantFromValue(v2)); + object->setProperty("aliasObject", QVariant::fromValue(v2)); MyQmlObject *v3 = qvariant_cast<MyQmlObject *>(object->property("aliasObject")); QVERIFY(v3 != nullptr); @@ -5022,6 +5028,8 @@ void tst_qqmllanguage::thisInQmlScope() QVERIFY(!o.isNull()); QCOMPARE(o->property("x"), QVariant(42)); QCOMPARE(o->property("y"), QVariant(42)); + QCOMPARE(o->property("a"), QVariant(42)); + QCOMPARE(o->property("b"), QVariant(42)); } void tst_qqmllanguage::valueTypeGroupPropertiesInBehavior() @@ -5069,6 +5077,16 @@ void tst_qqmllanguage::polymorphicFunctionLookup() QVERIFY(o->property("ok").toBool()); } +void tst_qqmllanguage::anchorsToParentInPropertyChanges() +{ + QQmlEngine engine; + QQmlComponent component(&engine, testFileUrl("anchorsToParentInPropertyChagnes.qml")); + VERIFY_ERRORS(0); + QScopedPointer<QObject> o(component.create()); + QVERIFY(!o.isNull()); + QTRY_COMPARE(o->property("edgeWidth").toInt(), 200); +} + QTEST_MAIN(tst_qqmllanguage) #include "tst_qqmllanguage.moc" diff --git a/tests/auto/qml/qqmllistmodel/tst_qqmllistmodel.cpp b/tests/auto/qml/qqmllistmodel/tst_qqmllistmodel.cpp index 771f3e5c4e..2022a0d892 100644 --- a/tests/auto/qml/qqmllistmodel/tst_qqmllistmodel.cpp +++ b/tests/auto/qml/qqmllistmodel/tst_qqmllistmodel.cpp @@ -760,11 +760,11 @@ void tst_qqmllistmodel::set() RUNEXPR("model.set(0, {test:true})"); QCOMPARE(RUNEXPR("model.get(0).test").toBool(), true); // triggers creation of model cache - QCOMPARE(model.data(0, 0), qVariantFromValue(true)); + QCOMPARE(model.data(0, 0), QVariant::fromValue(true)); RUNEXPR("model.set(0, {test:false})"); QCOMPARE(RUNEXPR("model.get(0).test").toBool(), false); // tests model cache is updated - QCOMPARE(model.data(0, 0), qVariantFromValue(false)); + QCOMPARE(model.data(0, 0), QVariant::fromValue(false)); QString warning = QString::fromLatin1("<Unknown File>: Can't create role for unsupported data type"); if (isValidErrorMessage(warning, dynamicRoles)) diff --git a/tests/auto/qml/qqmllistmodelworkerscript/tst_qqmllistmodelworkerscript.cpp b/tests/auto/qml/qqmllistmodelworkerscript/tst_qqmllistmodelworkerscript.cpp index 21b0508e4d..236a13a6f8 100644 --- a/tests/auto/qml/qqmllistmodelworkerscript/tst_qqmllistmodelworkerscript.cpp +++ b/tests/auto/qml/qqmllistmodelworkerscript/tst_qqmllistmodelworkerscript.cpp @@ -162,7 +162,7 @@ QQuickItem *tst_qqmllistmodelworkerscript::createWorkerTest(QQmlEngine *eng, QQm QQuickItem *item = qobject_cast<QQuickItem*>(component->create()); QQmlEngine::setContextForObject(model, eng->rootContext()); if (item) - item->setProperty("model", qVariantFromValue(model)); + item->setProperty("model", QVariant::fromValue(model)); return item; } diff --git a/tests/auto/qml/qqmltablemodel/data/builtInRoles.qml b/tests/auto/qml/qqmlmetatype/data/Components/App.qml index d9882e4dea..3792ca665e 100644 --- a/tests/auto/qml/qqmltablemodel/data/builtInRoles.qml +++ b/tests/auto/qml/qqmlmetatype/data/Components/App.qml @@ -26,22 +26,32 @@ ** ****************************************************************************/ -import Qt.labs.qmlmodels 1.0 +import QtQml 2.0 -import "TestUtils.js" as TestUtils +import Components 1.0 -TableModel { - id: testModel - objectName: "testModel" - roleDataProvider: TestUtils.testModelRoleDataProvider - rows: [ - [ - { name: "John", someOtherRole1: "foo" }, // column 0 - { age: 22, someOtherRole2: "foo" } // column 1 - ], - [ - { name: "Oliver", someOtherRole1: "foo" }, // column 0 - { age: 33, someOtherRole2: "foo" } // column 1 - ] - ] +QtObject { + id: mainRect + + property int appState: App.AppState.Blue + property string color: "blue" + + enum AppState { + Red, + Green, + Blue + } + + onAppStateChanged: { + if (appState === App.AppState.Green) + mainRect.color = "green" + else if (appState === App.AppState.Red) + mainRect.color = "red" + } + + property Timer timer: Timer { + onTriggered: appState = App.AppState.Green + running: true + interval: 100 + } } diff --git a/tests/auto/qml/qqmlmetatype/data/Components/qmldir b/tests/auto/qml/qqmlmetatype/data/Components/qmldir new file mode 100644 index 0000000000..3f6db4ed2d --- /dev/null +++ b/tests/auto/qml/qqmlmetatype/data/Components/qmldir @@ -0,0 +1,3 @@ +module Components + +App 1.0 App.qml diff --git a/tests/auto/qml/qqmlmetatype/data/enumsInRecursiveImport.qml b/tests/auto/qml/qqmlmetatype/data/enumsInRecursiveImport.qml new file mode 100644 index 0000000000..eef6abc6e5 --- /dev/null +++ b/tests/auto/qml/qqmlmetatype/data/enumsInRecursiveImport.qml @@ -0,0 +1,11 @@ +import QtQml 2.0 + +import Components 1.0 + +QtObject { + property App app: App { + appState: 0 + } + + property string color: app.color +} diff --git a/tests/auto/qml/qqmlmetatype/qqmlmetatype.pro b/tests/auto/qml/qqmlmetatype/qqmlmetatype.pro index 345bc59615..109de7d212 100644 --- a/tests/auto/qml/qqmlmetatype/qqmlmetatype.pro +++ b/tests/auto/qml/qqmlmetatype/qqmlmetatype.pro @@ -10,4 +10,11 @@ qmlfiles.files = data/CompositeType.qml qmlfiles.prefix = /tstqqmlmetatype RESOURCES += qmlfiles +qmldirresource.files = \ + data/Components/App.qml \ + data/Components/qmldir \ + data/enumsInRecursiveImport.qml +qmldirresource.prefix = / +RESOURCES += qmldirresource + QT += core-private gui-private qml-private testlib diff --git a/tests/auto/qml/qqmlmetatype/tst_qqmlmetatype.cpp b/tests/auto/qml/qqmlmetatype/tst_qqmlmetatype.cpp index ac75eeab26..1878cccd39 100644 --- a/tests/auto/qml/qqmlmetatype/tst_qqmlmetatype.cpp +++ b/tests/auto/qml/qqmlmetatype/tst_qqmlmetatype.cpp @@ -66,6 +66,9 @@ private slots: void normalizeUrls(); void unregisterAttachedProperties(); void revisionedGroupedProperties(); + + void enumsInRecursiveImport_data(); + void enumsInRecursiveImport(); }; class TestType : public QObject @@ -628,6 +631,35 @@ void tst_qqmlmetatype::revisionedGroupedProperties() } } +void tst_qqmlmetatype::enumsInRecursiveImport_data() +{ + QTest::addColumn<QString>("importPath"); + QTest::addColumn<QUrl>("componentUrl"); + + QTest::addRow("data directory") << dataDirectory() + << testFileUrl("enumsInRecursiveImport.qml"); + + // The qrc case behaves differently because we failed to detect the recursion in type loading + // due to varying numbers of slashes after the "qrc:" in the URLs. + QTest::addRow("resources") << QStringLiteral("qrc:/data") + << QUrl("qrc:/data/enumsInRecursiveImport.qml"); +} + +void tst_qqmlmetatype::enumsInRecursiveImport() +{ + QFETCH(QString, importPath); + QFETCH(QUrl, componentUrl); + + qmlClearTypeRegistrations(); + QQmlEngine engine; + engine.addImportPath(importPath); + QQmlComponent c(&engine, componentUrl); + QVERIFY(c.isReady()); + QScopedPointer<QObject> obj(c.create()); + QVERIFY(!obj.isNull()); + QTRY_COMPARE(obj->property("color").toString(), QString("green")); +} + QTEST_MAIN(tst_qqmlmetatype) #include "tst_qqmlmetatype.moc" diff --git a/tests/auto/qml/qqmlnotifier/tst_qqmlnotifier.cpp b/tests/auto/qml/qqmlnotifier/tst_qqmlnotifier.cpp index 6e831eacc1..a5332c8860 100644 --- a/tests/auto/qml/qqmlnotifier/tst_qqmlnotifier.cpp +++ b/tests/auto/qml/qqmlnotifier/tst_qqmlnotifier.cpp @@ -349,7 +349,7 @@ void tst_qqmlnotifier::deleteFromHandler() QQmlEngine engine; QQmlComponent component(&engine, testFileUrl("objectRenamer.qml")); QPointer<QObject> mess = component.create(); - QObject::connect(mess, &QObject::objectNameChanged, [&]() { delete mess; }); + QObject::connect(mess.data(), &QObject::objectNameChanged, [&]() { delete mess; }); QTRY_VERIFY(mess.isNull()); // BANG! } else { QProcess process; diff --git a/tests/auto/qml/qqmlparser/tst_qqmlparser.cpp b/tests/auto/qml/qqmlparser/tst_qqmlparser.cpp index c2c73935c0..fead8c4ebc 100644 --- a/tests/auto/qml/qqmlparser/tst_qqmlparser.cpp +++ b/tests/auto/qml/qqmlparser/tst_qqmlparser.cpp @@ -105,6 +105,11 @@ public: { nodeStack.removeLast(); } + + void throwRecursionDepthError() final + { + QFAIL("Maximum statement or expression depth exceeded"); + } }; } @@ -229,8 +234,8 @@ void tst_qqmlparser::stringLiteral() auto *literal = QQmlJS::AST::cast<QQmlJS::AST::StringLiteral *>(expression); QVERIFY(literal); QCOMPARE(literal->value, "hello string"); - QCOMPARE(literal->firstSourceLocation().begin(), 0); - QCOMPARE(literal->lastSourceLocation().end(), code.size()); + QCOMPARE(literal->firstSourceLocation().begin(), 0u); + QCOMPARE(literal->lastSourceLocation().end(), quint32(code.size())); } void tst_qqmlparser::noSubstitutionTemplateLiteral() @@ -250,8 +255,8 @@ void tst_qqmlparser::noSubstitutionTemplateLiteral() QVERIFY(literal); QCOMPARE(literal->value, "hello template"); - QCOMPARE(literal->firstSourceLocation().begin(), 0); - QCOMPARE(literal->lastSourceLocation().end(), code.size()); + QCOMPARE(literal->firstSourceLocation().begin(), 0u); + QCOMPARE(literal->lastSourceLocation().end(), quint32(code.size())); } void tst_qqmlparser::templateLiteral() @@ -270,7 +275,7 @@ void tst_qqmlparser::templateLiteral() auto *templateLiteral = QQmlJS::AST::cast<QQmlJS::AST::TemplateLiteral *>(expression); QVERIFY(templateLiteral); - QCOMPARE(templateLiteral->firstSourceLocation().begin(), 0); + QCOMPARE(templateLiteral->firstSourceLocation().begin(), 0u); auto *e = templateLiteral->expression; QVERIFY(e); } diff --git a/tests/auto/qml/qqmlproperty/tst_qqmlproperty.cpp b/tests/auto/qml/qqmlproperty/tst_qqmlproperty.cpp index 27e06c6f67..04c61ec11b 100644 --- a/tests/auto/qml/qqmlproperty/tst_qqmlproperty.cpp +++ b/tests/auto/qml/qqmlproperty/tst_qqmlproperty.cpp @@ -1624,7 +1624,7 @@ void tst_qqmlproperty::writeObjectToList() MyQmlObject *object = new MyQmlObject; QQmlProperty prop(container, "children"); - prop.write(qVariantFromValue(object)); + prop.write(QVariant::fromValue(object)); QCOMPARE(list.count(), 1); QCOMPARE(list.at(0), qobject_cast<QObject*>(object)); } @@ -1641,13 +1641,13 @@ void tst_qqmlproperty::writeListToList() QList<QObject*> objList; objList << new MyQmlObject() << new MyQmlObject() << new MyQmlObject() << new MyQmlObject(); QQmlProperty prop(container, "children"); - prop.write(qVariantFromValue(objList)); + prop.write(QVariant::fromValue(objList)); QCOMPARE(list.count(), 4); //XXX need to try this with read/write prop (for read-only it correctly doesn't write) /*QList<MyQmlObject*> typedObjList; typedObjList << new MyQmlObject(); - prop.write(qVariantFromValue(&typedObjList)); + prop.write(QVariant::fromValue(&typedObjList)); QCOMPARE(container->children()->size(), 1);*/ } diff --git a/tests/auto/qml/qqmlpropertycache/tst_qqmlpropertycache.cpp b/tests/auto/qml/qqmlpropertycache/tst_qqmlpropertycache.cpp index 02b5302a45..9a1e4667dd 100644 --- a/tests/auto/qml/qqmlpropertycache/tst_qqmlpropertycache.cpp +++ b/tests/auto/qml/qqmlpropertycache/tst_qqmlpropertycache.cpp @@ -31,7 +31,6 @@ #include <QtQml/qqmlengine.h> #include <QtQml/qqmlcontext.h> #include <QtQml/qqmlcomponent.h> -#include <private/qv8engine_p.h> #include <private/qmetaobjectbuilder_p.h> #include <QCryptographicHash> #include "../../shared/util.h" diff --git a/tests/auto/qml/qqmltablemodel/data/TestModel.qml b/tests/auto/qml/qqmltablemodel/data/TestModel.qml index 7aeb5d03f4..00e1fa65a7 100644 --- a/tests/auto/qml/qqmltablemodel/data/TestModel.qml +++ b/tests/auto/qml/qqmltablemodel/data/TestModel.qml @@ -33,15 +33,18 @@ import "TestUtils.js" as TestUtils TableModel { id: testModel objectName: "testModel" - roleDataProvider: TestUtils.testModelRoleDataProvider + + TableModelColumn { display: "name" } + TableModelColumn { display: "age" } + rows: [ - [ - { name: "John" }, - { age: 22 } - ], - [ - { name: "Oliver" }, - { age: 33 } - ] + { + name: "John", + age: 22 + }, + { + name: "Oliver", + age: 33 + } ] } diff --git a/tests/auto/qml/qqmltablemodel/data/common.qml b/tests/auto/qml/qqmltablemodel/data/common.qml index aec796bd4f..2f8b0c072b 100644 --- a/tests/auto/qml/qqmltablemodel/data/common.qml +++ b/tests/auto/qml/qqmltablemodel/data/common.qml @@ -26,7 +26,7 @@ ** ****************************************************************************/ -import QtQuick 2.12 +import QtQuick 2.13 import Qt.labs.qmlmodels 1.0 Item { @@ -38,80 +38,101 @@ Item { property alias tableView: tableView function appendRow(personName, personAge) { - testModel.appendRow([ - { name: personName }, - { age: personAge } - ]) + testModel.appendRow({ + name: personName, + age: personAge + }) + } + + function appendRowExtraData() { + testModel.appendRow({ + name: "Foo", + age: 99, + nonExistentRole: 123 + }) } function appendRowInvalid1() { - testModel.appendRow([ - { name: "Foo" }, - { age: 99 }, - { nonExistentRole: 123 } - ]) + testModel.appendRow(123) } function appendRowInvalid2() { - testModel.appendRow(123) + testModel.appendRow({ + name: "Foo", + age: [] + }) } function appendRowInvalid3() { testModel.appendRow([ - { name: "Foo" }, - { age: [] } + { name: "Bar" }, + { age: "111" } ]) } function insertRow(personName, personAge, rowIndex) { - testModel.insertRow(rowIndex, [ - { name: personName }, - { age: personAge }] - ) + testModel.insertRow(rowIndex, { + name: personName, + age: personAge + }) + } + + function insertRowExtraData() { + testModel.insertRow(0, { + name: "Foo", + age: 99, + nonExistentRole: 123 + }) } function insertRowInvalid1() { - testModel.insertRow(0, [ - { name: "Foo" }, - { age: 99 }, - { nonExistentRole: 123 } - ]) + testModel.insertRow(0, 123) } function insertRowInvalid2() { - testModel.insertRow(0, 123) + testModel.insertRow(0, { + name: "Foo", + age: [] + }) } function insertRowInvalid3() { testModel.insertRow(0, [ - { name: "Foo" }, - { age: [] } + { name: "Bar" }, + { age: "111" } ]) } function setRow(rowIndex, personName, personAge) { - testModel.setRow(rowIndex, [ - { name: personName }, - { age: personAge }] - ) + testModel.setRow(rowIndex, { + name: personName, + age: personAge + }) + } + + function setRowExtraData() { + testModel.setRow(0, { + name: "Foo", + age: 99, + nonExistentRole: 123 + }) } function setRowInvalid1() { - testModel.setRow(0, [ - { name: "Foo" }, - { age: 99 }, - { nonExistentRole: 123 } - ]) + testModel.setRow(0, 123) } function setRowInvalid2() { - testModel.setRow(0, 123) + testModel.setRow(0, { + name: "Foo", + age: [] + }) } function setRowInvalid3() { testModel.setRow(0, [ - { name: "Foo" }, - { age: [] } + { name: "Bar" }, + { age: "111" } ]) } diff --git a/tests/auto/qml/qqmltablemodel/data/roleDataProvider.qml b/tests/auto/qml/qqmltablemodel/data/complex.qml index 2706ea54fd..dbf53bac7e 100644 --- a/tests/auto/qml/qqmltablemodel/data/roleDataProvider.qml +++ b/tests/auto/qml/qqmltablemodel/data/complex.qml @@ -26,40 +26,43 @@ ** ****************************************************************************/ -import QtQuick 2.12 +import QtQuick 2.13 import Qt.labs.qmlmodels 1.0 -Item { - id: root - width: 200 - height: 200 +TableView { + width: 100 + height: 100 + delegate: Item { + implicitWidth: 50 + implicitHeight: 50 - property alias testModel: testModel - - TableModel { + Text { + text: model.display + anchors.centerIn: parent + } + } + model: TableModel { id: testModel objectName: "testModel" - rows: [ - [ { name: "Rex" }, { age: 3 } ], - [ { name: "Buster" }, { age: 5 } ] - ] - roleDataProvider: function(index, role, cellData) { - if (role === "display") { - // Age will now be in dog years - if (cellData.hasOwnProperty("age")) - return (cellData.age * 7); - else if (index.column === 0) - return (cellData.name); - } - return cellData; + + TableModelColumn { + display: function(modelIndex) { return testModel.rows[modelIndex.row][0].name } + setDisplay: function(modelIndex, cellData) { testModel.rows[modelIndex.row][0].name = cellData } } - } - TableView { - anchors.fill: parent - model: testModel - delegate: Text { - id: textItem - text: model.display + TableModelColumn { + display: function(modelIndex) { return testModel.rows[modelIndex.row][1].age } + setDisplay: function(modelIndex, cellData) { testModel.rows[modelIndex.row][1].age = cellData } } + + rows: [ + [ + { name: "John" }, + { age: 22 } + ], + [ + { name: "Oliver" }, + { age: 33 } + ] + ] } } diff --git a/tests/auto/qml/qqmltablemodel/data/dataAndSetData.qml b/tests/auto/qml/qqmltablemodel/data/dataAndSetData.qml index d61c50ba2c..d3f726bfa1 100644 --- a/tests/auto/qml/qqmltablemodel/data/dataAndSetData.qml +++ b/tests/auto/qml/qqmltablemodel/data/dataAndSetData.qml @@ -31,36 +31,25 @@ import Qt.labs.qmlmodels 1.0 TableView { width: 200; height: 200 - model: TableModel { + model: TestModel { id: testModel - objectName: "testModel" - rows: [ - [ - { name: "John", someOtherRole1: "foo" }, // column 0 - { age: 22, someOtherRole2: "foo" } // column 1 - ], - [ - { name: "Oliver", someOtherRole1: "foo" }, // column 0 - { age: 33, someOtherRole2: "foo" } // column 1 - ] - ] // This is silly: in real life, store the birthdate instead of the age, // and let the delegate calculate the age, so it won't need updating function happyBirthday(dude) { var row = -1; for (var r = 0; row < 0 && r < testModel.rowCount; ++r) - if (testModel.data(testModel.index(r, 0), "name") === dude) + if (testModel.data(testModel.index(r, 0), "display") === dude) row = r; var index = testModel.index(row, 1) - testModel.setData(index, "age", testModel.data(index, "age") + 1) + testModel.setData(index, "display", testModel.data(index, "display") + 1) } } delegate: Text { id: textItem text: model.display TapHandler { - onTapped: testModel.happyBirthday(testModel.data(testModel.index(row, 0), "name")) + onTapped: testModel.happyBirthday(testModel.data(testModel.index(row, 0), "display")) } } } diff --git a/tests/auto/qml/qqmltablemodel/data/empty.qml b/tests/auto/qml/qqmltablemodel/data/empty.qml index 6e66b99145..f5afbd1d27 100644 --- a/tests/auto/qml/qqmltablemodel/data/empty.qml +++ b/tests/auto/qml/qqmltablemodel/data/empty.qml @@ -29,8 +29,6 @@ import QtQuick 2.12 import Qt.labs.qmlmodels 1.0 -import "TestUtils.js" as TestUtils - Item { id: root width: 200 @@ -41,21 +39,37 @@ Item { function setRows() { testModel.rows = [ - [ - { name: "John" }, - { age: 22 } - ], - [ - { name: "Oliver" }, - { age: 33 } - ] + { + name: "John", + age: 22 + }, + { + name: "Oliver", + age: 33 + } ] } + function appendJohn() { + testModel.appendRow({ + name: "John", + age: 22 + }) + } + + function appendOliver() { + testModel.appendRow({ + name: "Oliver", + age: 33 + }) + } + TableModel { id: testModel objectName: "testModel" - roleDataProvider: TestUtils.testModelRoleDataProvider + + TableModelColumn { display: "name" } + TableModelColumn { display: "age" } } TableView { id: tableView diff --git a/tests/auto/qml/qqmltablemodel/data/explicitDisplayRole.qml b/tests/auto/qml/qqmltablemodel/data/omitTableModelColumnIndex.qml index 510a62e74b..86bcb08fa2 100644 --- a/tests/auto/qml/qqmltablemodel/data/explicitDisplayRole.qml +++ b/tests/auto/qml/qqmltablemodel/data/omitTableModelColumnIndex.qml @@ -28,14 +28,20 @@ import Qt.labs.qmlmodels 1.0 -import "TestUtils.js" as TestUtils - TableModel { - id: testModel + objectName: "testModel" + + TableModelColumn { display: "name" } + TableModelColumn { display: "age" } + rows: [ - [ - { name: "John", display: "foo" }, - { age: 22, display: "bar" } - ] + { + name: "John", + age: 22 + }, + { + name: "Oliver", + age: 33 + } ] } diff --git a/tests/auto/qml/qqmltablemodel/data/setDataThroughDelegate.qml b/tests/auto/qml/qqmltablemodel/data/setDataThroughDelegate.qml index 5f849c3350..ebfe4ed930 100644 --- a/tests/auto/qml/qqmltablemodel/data/setDataThroughDelegate.qml +++ b/tests/auto/qml/qqmltablemodel/data/setDataThroughDelegate.qml @@ -41,11 +41,11 @@ Item { signal shouldModifyInvalidType() function modify() { - shouldModify(); + shouldModify() } function modifyInvalidRole() { - shouldModifyInvalidRole(); + shouldModifyInvalidRole() } function modifyInvalidType() { @@ -54,37 +54,24 @@ Item { TableView { anchors.fill: parent - model: TableModel { + model: TestModel { id: testModel - objectName: "testModel" - rows: [ - [ - { name: "John" }, - { age: 22 } - ], - [ - { name: "Oliver" }, - { age: 33 } - ] - ] } delegate: Text { id: textItem - // TODO: this is currently random when no roleDataProvider handles it - // we should allow roleDataProvider to be used to handle specific roles only text: model.display Connections { target: root enabled: column === 1 - onShouldModify: model.age = 18 + onShouldModify: model.display = 18 } Connections { target: root enabled: column === 0 - // Invalid: should be "name". + // Invalid: should be "display". onShouldModifyInvalidRole: model.age = 100 } @@ -92,7 +79,7 @@ Item { target: root enabled: column === 1 // Invalid: should be string. - onShouldModifyInvalidType: model.age = "Whoops" + onShouldModifyInvalidType: model.display = "Whoops" } } } diff --git a/tests/auto/qml/qqmltablemodel/data/setRowsMultipleTimes.qml b/tests/auto/qml/qqmltablemodel/data/setRowsMultipleTimes.qml index 6aaf79f2d4..01ec40270c 100644 --- a/tests/auto/qml/qqmltablemodel/data/setRowsMultipleTimes.qml +++ b/tests/auto/qml/qqmltablemodel/data/setRowsMultipleTimes.qml @@ -39,35 +39,35 @@ Item { function setRowsValid() { testModel.rows = [ - [ - { name: "Max" }, - { age: 20 } - ], - [ - { name: "Imum" }, - { age: 41 } - ], - [ - { name: "Power" }, - { age: 89 } - ] + { + name: "Max", + age: 20 + }, + { + name: "Imum", + age: 41 + }, + { + name: "Power", + age: 89 + } ] } function setRowsInvalid() { testModel.rows = [ - [ - { nope: "Nope" }, - { age: 20 } - ], - [ - { nope: "Nah" }, - { age: 41 } - ], - [ - { nope: "No" }, - { age: 89 } - ] + { + nope: "Nope", + age: 20 + }, + { + nope: "Nah", + age: 41 + }, + { + nope: "No", + age: 89 + } ] } diff --git a/tests/auto/qml/qqmltablemodel/tst_qqmltablemodel.cpp b/tests/auto/qml/qqmltablemodel/tst_qqmltablemodel.cpp index 059ce082d9..113a27494d 100644 --- a/tests/auto/qml/qqmltablemodel/tst_qqmltablemodel.cpp +++ b/tests/auto/qml/qqmltablemodel/tst_qqmltablemodel.cpp @@ -47,6 +47,7 @@ public: private slots: void appendRemoveRow(); + void appendRowToEmptyModel(); void clear(); void getRow(); void insertRow(); @@ -55,15 +56,11 @@ private slots: void setDataThroughDelegate(); void setRowsImperatively(); void setRowsMultipleTimes(); - void builtInRoles_data(); - void builtInRoles(); - void explicitDisplayRole(); - void roleDataProvider(); void dataAndEditing(); + void omitTableModelColumnIndex(); + void complexRow(); }; -static const int builtInRoleCount = 6; - void tst_QQmlTableModel::appendRemoveRow() { QQuickView view(testFileUrl("common.qml")); @@ -81,22 +78,15 @@ void tst_QQmlTableModel::appendRemoveRow() QSignalSpy rowCountSpy(model, SIGNAL(rowCountChanged())); QVERIFY(rowCountSpy.isValid()); - int heightSignalEmissions = 0; + int rowCountSignalEmissions = 0; const QHash<int, QByteArray> roleNames = model->roleNames(); - QCOMPARE(roleNames.size(), 2 + builtInRoleCount); - QVERIFY(roleNames.values().contains("name")); - QVERIFY(roleNames.values().contains("age")); + QCOMPARE(roleNames.size(), 1); QVERIFY(roleNames.values().contains("display")); - QVERIFY(roleNames.values().contains("decoration")); - QVERIFY(roleNames.values().contains("edit")); - QVERIFY(roleNames.values().contains("toolTip")); - QVERIFY(roleNames.values().contains("statusTip")); - QVERIFY(roleNames.values().contains("whatsThis")); - QCOMPARE(model->data(model->index(0, 0, QModelIndex()), roleNames.key("name")).toString(), QLatin1String("John")); - QCOMPARE(model->data(model->index(0, 1, QModelIndex()), roleNames.key("age")).toInt(), 22); - QCOMPARE(model->data(model->index(1, 0, QModelIndex()), roleNames.key("name")).toString(), QLatin1String("Oliver")); - QCOMPARE(model->data(model->index(1, 1, QModelIndex()), roleNames.key("age")).toInt(), 33); + QCOMPARE(model->data(model->index(0, 0, QModelIndex()), roleNames.key("display")).toString(), QLatin1String("John")); + QCOMPARE(model->data(model->index(0, 1, QModelIndex()), roleNames.key("display")).toInt(), 22); + QCOMPARE(model->data(model->index(1, 0, QModelIndex()), roleNames.key("display")).toString(), QLatin1String("Oliver")); + QCOMPARE(model->data(model->index(1, 1, QModelIndex()), roleNames.key("display")).toInt(), 33); // Call remove() with a negative rowIndex. QTest::ignoreMessage(QtWarningMsg, QRegularExpression(".*removeRow\\(\\): \"rowIndex\" cannot be negative")); @@ -104,7 +94,7 @@ void tst_QQmlTableModel::appendRemoveRow() QCOMPARE(model->rowCount(), 2); QCOMPARE(model->columnCount(), 2); QCOMPARE(columnCountSpy.count(), 0); - QCOMPARE(rowCountSpy.count(), heightSignalEmissions); + QCOMPARE(rowCountSpy.count(), rowCountSignalEmissions); // Call remove() with an rowIndex that is too large. QTest::ignoreMessage(QtWarningMsg, QRegularExpression( @@ -113,7 +103,7 @@ void tst_QQmlTableModel::appendRemoveRow() QCOMPARE(model->rowCount(), 2); QCOMPARE(model->columnCount(), 2); QCOMPARE(columnCountSpy.count(), 0); - QCOMPARE(rowCountSpy.count(), heightSignalEmissions); + QCOMPARE(rowCountSpy.count(), rowCountSignalEmissions); // Call remove() with a valid rowIndex but negative rows. QTest::ignoreMessage(QtWarningMsg, QRegularExpression(".*removeRow\\(\\): \"rows\" is less than or equal to zero")); @@ -121,7 +111,7 @@ void tst_QQmlTableModel::appendRemoveRow() QCOMPARE(model->rowCount(), 2); QCOMPARE(model->columnCount(), 2); QCOMPARE(columnCountSpy.count(), 0); - QCOMPARE(rowCountSpy.count(), heightSignalEmissions); + QCOMPARE(rowCountSpy.count(), rowCountSignalEmissions); // Call remove() with a valid rowIndex but excessive rows. QTest::ignoreMessage(QtWarningMsg, QRegularExpression( @@ -130,71 +120,125 @@ void tst_QQmlTableModel::appendRemoveRow() QCOMPARE(model->rowCount(), 2); QCOMPARE(model->columnCount(), 2); QCOMPARE(columnCountSpy.count(), 0); - QCOMPARE(rowCountSpy.count(), heightSignalEmissions); + QCOMPARE(rowCountSpy.count(), rowCountSignalEmissions); // Call remove() without specifying the number of rows to remove; it should remove one row. QVERIFY(QMetaObject::invokeMethod(model, "removeRow", Q_ARG(int, 0))); QCOMPARE(model->rowCount(), 1); QCOMPARE(model->columnCount(), 2); - QCOMPARE(model->data(model->index(0, 0, QModelIndex()), roleNames.key("name")).toString(), QLatin1String("Oliver")); - QCOMPARE(model->data(model->index(0, 1, QModelIndex()), roleNames.key("age")).toInt(), 33); + QCOMPARE(model->data(model->index(0, 0, QModelIndex()), roleNames.key("display")).toString(), QLatin1String("Oliver")); + QCOMPARE(model->data(model->index(0, 1, QModelIndex()), roleNames.key("display")).toInt(), 33); QCOMPARE(columnCountSpy.count(), 0); - QCOMPARE(rowCountSpy.count(), ++heightSignalEmissions); + QCOMPARE(rowCountSpy.count(), ++rowCountSignalEmissions); - // Call append() with a row that has a new (and hence unexpected) role. - QTest::ignoreMessage(QtWarningMsg, QRegularExpression(".*appendRow\\(\\): expected 2 columns, but got 3")); + // Call append() with a row that has an unexpected role; the row should be added and the extra data ignored. + QVERIFY(QMetaObject::invokeMethod(view.rootObject(), "appendRowExtraData")); + // Nothing should change. + QCOMPARE(model->rowCount(), 2); + QCOMPARE(model->columnCount(), 2); + QCOMPARE(model->data(model->index(0, 0, QModelIndex()), roleNames.key("display")).toString(), QLatin1String("Oliver")); + QCOMPARE(model->data(model->index(0, 1, QModelIndex()), roleNames.key("display")).toInt(), 33); + QCOMPARE(model->data(model->index(1, 0, QModelIndex()), roleNames.key("display")).toString(), QLatin1String("Foo")); + QCOMPARE(model->data(model->index(1, 1, QModelIndex()), roleNames.key("display")).toInt(), 99); + QCOMPARE(columnCountSpy.count(), 0); + QCOMPARE(rowCountSpy.count(), ++rowCountSignalEmissions); + + // Call append() with a row that is an int. + QTest::ignoreMessage(QtWarningMsg, QRegularExpression( + ".*appendRow\\(\\): expected \"row\" argument to be a QJSValue, but got int instead:\nQVariant\\(int, 123\\)")); QVERIFY(QMetaObject::invokeMethod(view.rootObject(), "appendRowInvalid1")); // Nothing should change. - QCOMPARE(model->rowCount(), 1); + QCOMPARE(model->rowCount(), 2); QCOMPARE(model->columnCount(), 2); - QCOMPARE(model->data(model->index(0, 0, QModelIndex()), roleNames.key("name")).toString(), QLatin1String("Oliver")); - QCOMPARE(model->data(model->index(0, 1, QModelIndex()), roleNames.key("age")).toInt(), 33); + QCOMPARE(model->data(model->index(0, 0, QModelIndex()), roleNames.key("display")).toString(), QLatin1String("Oliver")); + QCOMPARE(model->data(model->index(0, 1, QModelIndex()), roleNames.key("display")).toInt(), 33); + QCOMPARE(model->data(model->index(1, 0, QModelIndex()), roleNames.key("display")).toString(), QLatin1String("Foo")); + QCOMPARE(model->data(model->index(1, 1, QModelIndex()), roleNames.key("display")).toInt(), 99); QCOMPARE(columnCountSpy.count(), 0); - QCOMPARE(rowCountSpy.count(), heightSignalEmissions); + QCOMPARE(rowCountSpy.count(), rowCountSignalEmissions); - // Call append() with a row that is not an array. + // Call append() with a row with a role of the wrong type. QTest::ignoreMessage(QtWarningMsg, QRegularExpression( - ".*appendRow\\(\\): expected \"row\" argument to be an array, but got int instead")); + ".*appendRow\\(\\): expected the property named \"age\" to be of type \"int\", but got \"QVariantList\" instead")); QVERIFY(QMetaObject::invokeMethod(view.rootObject(), "appendRowInvalid2")); // Nothing should change. - QCOMPARE(model->rowCount(), 1); + QCOMPARE(model->rowCount(), 2); QCOMPARE(model->columnCount(), 2); - QCOMPARE(model->data(model->index(0, 0, QModelIndex()), roleNames.key("name")).toString(), QLatin1String("Oliver")); - QCOMPARE(model->data(model->index(0, 1, QModelIndex()), roleNames.key("age")).toInt(), 33); + QCOMPARE(model->data(model->index(0, 0, QModelIndex()), roleNames.key("display")).toString(), QLatin1String("Oliver")); + QCOMPARE(model->data(model->index(0, 1, QModelIndex()), roleNames.key("display")).toInt(), 33); + QCOMPARE(model->data(model->index(1, 0, QModelIndex()), roleNames.key("display")).toString(), QLatin1String("Foo")); + QCOMPARE(model->data(model->index(1, 1, QModelIndex()), roleNames.key("display")).toInt(), 99); QCOMPARE(columnCountSpy.count(), 0); - QCOMPARE(rowCountSpy.count(), heightSignalEmissions); + QCOMPARE(rowCountSpy.count(), rowCountSignalEmissions); - // Call append() with a row with a role that is of the wrong type. + // Call append() with a row that is an array instead of a simple object. QTest::ignoreMessage(QtWarningMsg, QRegularExpression( - ".*appendRow\\(\\): expected property with type int at column index 1, but got QVariantList instead")); + ".*appendRow\\(\\): row manipulation functions do not support complex rows \\(row index: -1\\)")); QVERIFY(QMetaObject::invokeMethod(view.rootObject(), "appendRowInvalid3")); // Nothing should change. - QCOMPARE(model->rowCount(), 1); + QCOMPARE(model->rowCount(), 2); QCOMPARE(model->columnCount(), 2); - QCOMPARE(model->data(model->index(0, 0, QModelIndex()), roleNames.key("name")).toString(), QLatin1String("Oliver")); - QCOMPARE(model->data(model->index(0, 1, QModelIndex()), roleNames.key("age")).toInt(), 33); + QCOMPARE(model->data(model->index(0, 0, QModelIndex()), roleNames.key("display")).toString(), QLatin1String("Oliver")); + QCOMPARE(model->data(model->index(0, 1, QModelIndex()), roleNames.key("display")).toInt(), 33); QCOMPARE(columnCountSpy.count(), 0); - QCOMPARE(rowCountSpy.count(), heightSignalEmissions); + QCOMPARE(rowCountSpy.count(), rowCountSignalEmissions); // Call append() to insert one row. QVERIFY(QMetaObject::invokeMethod(view.rootObject(), "appendRow", Q_ARG(QVariant, QLatin1String("Max")), Q_ARG(QVariant, 40))); - QCOMPARE(model->rowCount(), 2); + QCOMPARE(model->rowCount(), 3); QCOMPARE(model->columnCount(), 2); - QCOMPARE(model->data(model->index(0, 0, QModelIndex()), roleNames.key("name")).toString(), QLatin1String("Oliver")); - QCOMPARE(model->data(model->index(0, 1, QModelIndex()), roleNames.key("age")).toInt(), 33); - QCOMPARE(model->data(model->index(1, 0, QModelIndex()), roleNames.key("name")).toString(), QLatin1String("Max")); - QCOMPARE(model->data(model->index(1, 1, QModelIndex()), roleNames.key("age")).toInt(), 40); + QCOMPARE(model->data(model->index(0, 0, QModelIndex()), roleNames.key("display")).toString(), QLatin1String("Oliver")); + QCOMPARE(model->data(model->index(0, 1, QModelIndex()), roleNames.key("display")).toInt(), 33); + QCOMPARE(model->data(model->index(1, 0, QModelIndex()), roleNames.key("display")).toString(), QLatin1String("Foo")); + QCOMPARE(model->data(model->index(1, 1, QModelIndex()), roleNames.key("display")).toInt(), 99); + QCOMPARE(model->data(model->index(2, 0, QModelIndex()), roleNames.key("display")).toString(), QLatin1String("Max")); + QCOMPARE(model->data(model->index(2, 1, QModelIndex()), roleNames.key("display")).toInt(), 40); QCOMPARE(columnCountSpy.count(), 0); - QCOMPARE(rowCountSpy.count(), ++heightSignalEmissions); + QCOMPARE(rowCountSpy.count(), ++rowCountSignalEmissions); // Call remove() and specify rowIndex and rows, removing all remaining rows. - QVERIFY(QMetaObject::invokeMethod(model, "removeRow", Q_ARG(int, 0), Q_ARG(int, 2))); + QVERIFY(QMetaObject::invokeMethod(model, "removeRow", Q_ARG(int, 0), Q_ARG(int, 3))); QCOMPARE(model->rowCount(), 0); QCOMPARE(model->columnCount(), 2); - QCOMPARE(model->data(model->index(0, 0, QModelIndex()), roleNames.key("name")), QVariant()); - QCOMPARE(model->data(model->index(0, 1, QModelIndex()), roleNames.key("age")), QVariant()); + QCOMPARE(model->data(model->index(0, 0, QModelIndex()), roleNames.key("display")), QVariant()); + QCOMPARE(model->data(model->index(0, 1, QModelIndex()), roleNames.key("display")), QVariant()); QCOMPARE(columnCountSpy.count(), 0); - QCOMPARE(rowCountSpy.count(), ++heightSignalEmissions); + QCOMPARE(rowCountSpy.count(), ++rowCountSignalEmissions); +} + +void tst_QQmlTableModel::appendRowToEmptyModel() +{ + QQuickView view(testFileUrl("empty.qml")); + QCOMPARE(view.status(), QQuickView::Ready); + view.show(); + QVERIFY(QTest::qWaitForWindowActive(&view)); + + QQmlTableModel *model = view.rootObject()->property("testModel").value<QQmlTableModel*>(); + QVERIFY(model); + QCOMPARE(model->rowCount(), 0); + QCOMPARE(model->columnCount(), 2); + + QSignalSpy columnCountSpy(model, SIGNAL(columnCountChanged())); + QVERIFY(columnCountSpy.isValid()); + + QSignalSpy rowCountSpy(model, SIGNAL(rowCountChanged())); + QVERIFY(rowCountSpy.isValid()); + + QQuickTableView *tableView = view.rootObject()->property("tableView").value<QQuickTableView*>(); + QVERIFY(tableView); + QCOMPARE(tableView->rows(), 0); + QCOMPARE(tableView->columns(), 2); + + QVERIFY(QMetaObject::invokeMethod(view.rootObject(), "appendJohn")); + QCOMPARE(model->rowCount(), 1); + QCOMPARE(model->columnCount(), 2); + const QHash<int, QByteArray> roleNames = model->roleNames(); + QCOMPARE(model->data(model->index(0, 0, QModelIndex()), roleNames.key("display")).toString(), QLatin1String("John")); + QCOMPARE(model->data(model->index(0, 1, QModelIndex()), roleNames.key("display")).toInt(), 22); + QCOMPARE(columnCountSpy.count(), 0); + QCOMPARE(rowCountSpy.count(), 1); + QTRY_COMPARE(tableView->rows(), 1); + QCOMPARE(tableView->columns(), 2); } void tst_QQmlTableModel::clear() @@ -216,9 +260,8 @@ void tst_QQmlTableModel::clear() QVERIFY(rowCountSpy.isValid()); const QHash<int, QByteArray> roleNames = model->roleNames(); - QVERIFY(roleNames.values().contains("name")); - QVERIFY(roleNames.values().contains("age")); - QCOMPARE(roleNames.size(), 2 + builtInRoleCount); + QVERIFY(roleNames.values().contains("display")); + QCOMPARE(roleNames.size(), 1); QQuickTableView *tableView = view.rootObject()->property("tableView").value<QQuickTableView*>(); QVERIFY(tableView); @@ -263,9 +306,9 @@ void tst_QQmlTableModel::getRow() // Call get() with a valid row index. QVERIFY(QMetaObject::invokeMethod(model, "getRow", Q_RETURN_ARG(QVariant, returnValue), Q_ARG(int, 0))); - const QVariantList rowAsVariantList = returnValue.toList(); - QCOMPARE(rowAsVariantList.at(0).toMap().value(QLatin1String("name")), QLatin1String("John")); - QCOMPARE(rowAsVariantList.at(1).toMap().value(QLatin1String("age")), 22); + const QVariantMap rowAsVariantMap = returnValue.toMap(); + QCOMPARE(rowAsVariantMap.value(QLatin1String("name")).toString(), QLatin1String("John")); + QCOMPARE(rowAsVariantMap.value(QLatin1String("age")).toInt(), 22); } void tst_QQmlTableModel::insertRow() @@ -285,7 +328,7 @@ void tst_QQmlTableModel::insertRow() QSignalSpy rowCountSpy(model, SIGNAL(rowCountChanged())); QVERIFY(rowCountSpy.isValid()); - int heightSignalEmissions = 0; + int rowCountSignalEmissions = 0; QQuickTableView *tableView = view.rootObject()->property("tableView").value<QQuickTableView*>(); QVERIFY(tableView); @@ -300,12 +343,12 @@ void tst_QQmlTableModel::insertRow() QCOMPARE(model->columnCount(), 2); QCOMPARE(model->rowCount(), 2); const QHash<int, QByteArray> roleNames = model->roleNames(); - QCOMPARE(model->data(model->index(0, 0, QModelIndex()), roleNames.key("name")).toString(), QLatin1String("John")); - QCOMPARE(model->data(model->index(0, 1, QModelIndex()), roleNames.key("age")).toInt(), 22); - QCOMPARE(model->data(model->index(1, 0, QModelIndex()), roleNames.key("name")).toString(), QLatin1String("Oliver")); - QCOMPARE(model->data(model->index(1, 1, QModelIndex()), roleNames.key("age")).toInt(), 33); + QCOMPARE(model->data(model->index(0, 0, QModelIndex()), roleNames.key("display")).toString(), QLatin1String("John")); + QCOMPARE(model->data(model->index(0, 1, QModelIndex()), roleNames.key("display")).toInt(), 22); + QCOMPARE(model->data(model->index(1, 0, QModelIndex()), roleNames.key("display")).toString(), QLatin1String("Oliver")); + QCOMPARE(model->data(model->index(1, 1, QModelIndex()), roleNames.key("display")).toInt(), 33); QCOMPARE(columnCountSpy.count(), 0); - QCOMPARE(rowCountSpy.count(), heightSignalEmissions); + QCOMPARE(rowCountSpy.count(), rowCountSignalEmissions); QCOMPARE(tableView->rows(), 2); QCOMPARE(tableView->columns(), 2); @@ -316,92 +359,112 @@ void tst_QQmlTableModel::insertRow() Q_ARG(QVariant, QLatin1String("Max")), Q_ARG(QVariant, 40), Q_ARG(QVariant, 3))); QCOMPARE(model->rowCount(), 2); QCOMPARE(model->columnCount(), 2); - QCOMPARE(model->data(model->index(0, 0, QModelIndex()), roleNames.key("name")).toString(), QLatin1String("John")); - QCOMPARE(model->data(model->index(0, 1, QModelIndex()), roleNames.key("age")).toInt(), 22); - QCOMPARE(model->data(model->index(1, 0, QModelIndex()), roleNames.key("name")).toString(), QLatin1String("Oliver")); - QCOMPARE(model->data(model->index(1, 1, QModelIndex()), roleNames.key("age")).toInt(), 33); + QCOMPARE(model->data(model->index(0, 0, QModelIndex()), roleNames.key("display")).toString(), QLatin1String("John")); + QCOMPARE(model->data(model->index(0, 1, QModelIndex()), roleNames.key("display")).toInt(), 22); + QCOMPARE(model->data(model->index(1, 0, QModelIndex()), roleNames.key("display")).toString(), QLatin1String("Oliver")); + QCOMPARE(model->data(model->index(1, 1, QModelIndex()), roleNames.key("display")).toInt(), 33); QCOMPARE(columnCountSpy.count(), 0); - QCOMPARE(rowCountSpy.count(), heightSignalEmissions); + QCOMPARE(rowCountSpy.count(), rowCountSignalEmissions); QCOMPARE(tableView->rows(), 2); QCOMPARE(tableView->columns(), 2); - // Try to insert a row that has a new (and hence unexpected) role. - QTest::ignoreMessage(QtWarningMsg, QRegularExpression(".*insertRow\\(\\): expected 2 columns, but got 3")); + // Call insert() with a row that is an int. + QTest::ignoreMessage(QtWarningMsg, QRegularExpression( + ".*insertRow\\(\\): expected \"row\" argument to be a QJSValue, but got int instead:\nQVariant\\(int, 123\\)")); QVERIFY(QMetaObject::invokeMethod(view.rootObject(), "insertRowInvalid1")); - QCOMPARE(model->columnCount(), 2); QCOMPARE(model->rowCount(), 2); - QCOMPARE(model->data(model->index(0, 0, QModelIndex()), roleNames.key("name")).toString(), QLatin1String("John")); - QCOMPARE(model->data(model->index(0, 1, QModelIndex()), roleNames.key("age")).toInt(), 22); - QCOMPARE(model->data(model->index(1, 0, QModelIndex()), roleNames.key("name")).toString(), QLatin1String("Oliver")); - QCOMPARE(model->data(model->index(1, 1, QModelIndex()), roleNames.key("age")).toInt(), 33); + QCOMPARE(model->columnCount(), 2); + QCOMPARE(model->data(model->index(0, 0, QModelIndex()), roleNames.key("display")).toString(), QLatin1String("John")); + QCOMPARE(model->data(model->index(0, 1, QModelIndex()), roleNames.key("display")).toInt(), 22); + QCOMPARE(model->data(model->index(1, 0, QModelIndex()), roleNames.key("display")).toString(), QLatin1String("Oliver")); + QCOMPARE(model->data(model->index(1, 1, QModelIndex()), roleNames.key("display")).toInt(), 33); QCOMPARE(columnCountSpy.count(), 0); - QCOMPARE(rowCountSpy.count(), heightSignalEmissions); + QCOMPARE(rowCountSpy.count(), rowCountSignalEmissions); QCOMPARE(tableView->rows(), 2); QCOMPARE(tableView->columns(), 2); - // Try to insert a row that is not an array. + // Try to insert a row with a role of the wrong type. QTest::ignoreMessage(QtWarningMsg, QRegularExpression( - ".*insertRow\\(\\): expected \"row\" argument to be an array, but got int instead")); + ".*insertRow\\(\\): expected the property named \"age\" to be of type \"int\", but got \"QVariantList\" instead")); QVERIFY(QMetaObject::invokeMethod(view.rootObject(), "insertRowInvalid2")); QCOMPARE(model->rowCount(), 2); QCOMPARE(model->columnCount(), 2); - QCOMPARE(model->data(model->index(0, 0, QModelIndex()), roleNames.key("name")).toString(), QLatin1String("John")); - QCOMPARE(model->data(model->index(0, 1, QModelIndex()), roleNames.key("age")).toInt(), 22); - QCOMPARE(model->data(model->index(1, 0, QModelIndex()), roleNames.key("name")).toString(), QLatin1String("Oliver")); - QCOMPARE(model->data(model->index(1, 1, QModelIndex()), roleNames.key("age")).toInt(), 33); + QCOMPARE(model->data(model->index(0, 0, QModelIndex()), roleNames.key("display")).toString(), QLatin1String("John")); + QCOMPARE(model->data(model->index(0, 1, QModelIndex()), roleNames.key("display")).toInt(), 22); + QCOMPARE(model->data(model->index(1, 0, QModelIndex()), roleNames.key("display")).toString(), QLatin1String("Oliver")); + QCOMPARE(model->data(model->index(1, 1, QModelIndex()), roleNames.key("display")).toInt(), 33); QCOMPARE(columnCountSpy.count(), 0); - QCOMPARE(rowCountSpy.count(), heightSignalEmissions); + QCOMPARE(rowCountSpy.count(), rowCountSignalEmissions); QCOMPARE(tableView->rows(), 2); QCOMPARE(tableView->columns(), 2); - // Try to insert a row with a role that is of the wrong type. + // Try to insert a row that is an array instead of a simple object. QTest::ignoreMessage(QtWarningMsg, QRegularExpression( - ".*insertRow\\(\\): expected property with type int at column index 1, but got QVariantList instead")); + ".*insertRow\\(\\): row manipulation functions do not support complex rows \\(row index: 0\\)")); QVERIFY(QMetaObject::invokeMethod(view.rootObject(), "insertRowInvalid3")); QCOMPARE(model->rowCount(), 2); QCOMPARE(model->columnCount(), 2); - QCOMPARE(model->data(model->index(0, 0, QModelIndex()), roleNames.key("name")).toString(), QLatin1String("John")); - QCOMPARE(model->data(model->index(0, 1, QModelIndex()), roleNames.key("age")).toInt(), 22); - QCOMPARE(model->data(model->index(1, 0, QModelIndex()), roleNames.key("name")).toString(), QLatin1String("Oliver")); - QCOMPARE(model->data(model->index(1, 1, QModelIndex()), roleNames.key("age")).toInt(), 33); + QCOMPARE(model->data(model->index(0, 0, QModelIndex()), roleNames.key("display")).toString(), QLatin1String("John")); + QCOMPARE(model->data(model->index(0, 1, QModelIndex()), roleNames.key("display")).toInt(), 22); + QCOMPARE(model->data(model->index(1, 0, QModelIndex()), roleNames.key("display")).toString(), QLatin1String("Oliver")); + QCOMPARE(model->data(model->index(1, 1, QModelIndex()), roleNames.key("display")).toInt(), 33); QCOMPARE(columnCountSpy.count(), 0); - QCOMPARE(rowCountSpy.count(), heightSignalEmissions); + QCOMPARE(rowCountSpy.count(), rowCountSignalEmissions); QCOMPARE(tableView->rows(), 2); QCOMPARE(tableView->columns(), 2); - // Insert a row at the bottom of the table. - QVERIFY(QMetaObject::invokeMethod(view.rootObject(), "insertRow", - Q_ARG(QVariant, QLatin1String("Max")), Q_ARG(QVariant, 40), Q_ARG(QVariant, 2))); + // Try to insert a row has an unexpected role; the row should be added and the extra data ignored. + QVERIFY(QMetaObject::invokeMethod(view.rootObject(), "insertRowExtraData")); QCOMPARE(model->rowCount(), 3); QCOMPARE(model->columnCount(), 2); - QCOMPARE(model->data(model->index(0, 0, QModelIndex()), roleNames.key("name")).toString(), QLatin1String("John")); - QCOMPARE(model->data(model->index(0, 1, QModelIndex()), roleNames.key("age")).toInt(), 22); - QCOMPARE(model->data(model->index(1, 0, QModelIndex()), roleNames.key("name")).toString(), QLatin1String("Oliver")); - QCOMPARE(model->data(model->index(1, 1, QModelIndex()), roleNames.key("age")).toInt(), 33); - QCOMPARE(model->data(model->index(2, 0, QModelIndex()), roleNames.key("name")).toString(), QLatin1String("Max")); - QCOMPARE(model->data(model->index(2, 1, QModelIndex()), roleNames.key("age")).toInt(), 40); + QCOMPARE(model->data(model->index(0, 0, QModelIndex()), roleNames.key("display")).toString(), QLatin1String("Foo")); + QCOMPARE(model->data(model->index(0, 1, QModelIndex()), roleNames.key("display")).toInt(), 99); + QCOMPARE(model->data(model->index(1, 0, QModelIndex()), roleNames.key("display")).toString(), QLatin1String("John")); + QCOMPARE(model->data(model->index(1, 1, QModelIndex()), roleNames.key("display")).toInt(), 22); + QCOMPARE(model->data(model->index(2, 0, QModelIndex()), roleNames.key("display")).toString(), QLatin1String("Oliver")); + QCOMPARE(model->data(model->index(2, 1, QModelIndex()), roleNames.key("display")).toInt(), 33); QCOMPARE(columnCountSpy.count(), 0); - QCOMPARE(rowCountSpy.count(), ++heightSignalEmissions); + QCOMPARE(rowCountSpy.count(), ++rowCountSignalEmissions); QTRY_COMPARE(tableView->rows(), 3); QCOMPARE(tableView->columns(), 2); - // Insert a row in the middle of the table. + // Insert a row at the bottom of the table. QVERIFY(QMetaObject::invokeMethod(view.rootObject(), "insertRow", - Q_ARG(QVariant, QLatin1String("Daisy")), Q_ARG(QVariant, 30), Q_ARG(QVariant, 1))); + Q_ARG(QVariant, QLatin1String("Max")), Q_ARG(QVariant, 40), Q_ARG(QVariant, 3))); QCOMPARE(model->rowCount(), 4); QCOMPARE(model->columnCount(), 2); - QCOMPARE(model->data(model->index(0, 0, QModelIndex()), roleNames.key("name")).toString(), QLatin1String("John")); - QCOMPARE(model->data(model->index(0, 1, QModelIndex()), roleNames.key("age")).toInt(), 22); - QCOMPARE(model->data(model->index(1, 0, QModelIndex()), roleNames.key("name")).toString(), QLatin1String("Daisy")); - QCOMPARE(model->data(model->index(1, 1, QModelIndex()), roleNames.key("age")).toInt(), 30); - QCOMPARE(model->data(model->index(2, 0, QModelIndex()), roleNames.key("name")).toString(), QLatin1String("Oliver")); - QCOMPARE(model->data(model->index(2, 1, QModelIndex()), roleNames.key("age")).toInt(), 33); - QCOMPARE(model->data(model->index(3, 0, QModelIndex()), roleNames.key("name")).toString(), QLatin1String("Max")); - QCOMPARE(model->data(model->index(3, 1, QModelIndex()), roleNames.key("age")).toInt(), 40); + QCOMPARE(model->data(model->index(0, 0, QModelIndex()), roleNames.key("display")).toString(), QLatin1String("Foo")); + QCOMPARE(model->data(model->index(0, 1, QModelIndex()), roleNames.key("display")).toInt(), 99); + QCOMPARE(model->data(model->index(1, 0, QModelIndex()), roleNames.key("display")).toString(), QLatin1String("John")); + QCOMPARE(model->data(model->index(1, 1, QModelIndex()), roleNames.key("display")).toInt(), 22); + QCOMPARE(model->data(model->index(2, 0, QModelIndex()), roleNames.key("display")).toString(), QLatin1String("Oliver")); + QCOMPARE(model->data(model->index(2, 1, QModelIndex()), roleNames.key("display")).toInt(), 33); + QCOMPARE(model->data(model->index(3, 0, QModelIndex()), roleNames.key("display")).toString(), QLatin1String("Max")); + QCOMPARE(model->data(model->index(3, 1, QModelIndex()), roleNames.key("display")).toInt(), 40); QCOMPARE(columnCountSpy.count(), 0); - QCOMPARE(rowCountSpy.count(), ++heightSignalEmissions); + QCOMPARE(rowCountSpy.count(), ++rowCountSignalEmissions); QTRY_COMPARE(tableView->rows(), 4); QCOMPARE(tableView->columns(), 2); + + // Insert a row in the middle of the table. + QVERIFY(QMetaObject::invokeMethod(view.rootObject(), "insertRow", + Q_ARG(QVariant, QLatin1String("Daisy")), Q_ARG(QVariant, 30), Q_ARG(QVariant, 2))); + QCOMPARE(model->rowCount(), 5); + QCOMPARE(model->columnCount(), 2); + QCOMPARE(model->data(model->index(0, 0, QModelIndex()), roleNames.key("display")).toString(), QLatin1String("Foo")); + QCOMPARE(model->data(model->index(0, 1, QModelIndex()), roleNames.key("display")).toInt(), 99); + QCOMPARE(model->data(model->index(1, 0, QModelIndex()), roleNames.key("display")).toString(), QLatin1String("John")); + QCOMPARE(model->data(model->index(1, 1, QModelIndex()), roleNames.key("display")).toInt(), 22); + QCOMPARE(model->data(model->index(2, 0, QModelIndex()), roleNames.key("display")).toString(), QLatin1String("Daisy")); + QCOMPARE(model->data(model->index(2, 1, QModelIndex()), roleNames.key("display")).toInt(), 30); + QCOMPARE(model->data(model->index(3, 0, QModelIndex()), roleNames.key("display")).toString(), QLatin1String("Oliver")); + QCOMPARE(model->data(model->index(3, 1, QModelIndex()), roleNames.key("display")).toInt(), 33); + QCOMPARE(model->data(model->index(4, 0, QModelIndex()), roleNames.key("display")).toString(), QLatin1String("Max")); + QCOMPARE(model->data(model->index(4, 1, QModelIndex()), roleNames.key("display")).toInt(), 40); + QCOMPARE(columnCountSpy.count(), 0); + QCOMPARE(rowCountSpy.count(), ++rowCountSignalEmissions); + QTRY_COMPARE(tableView->rows(), 5); + QCOMPARE(tableView->columns(), 2); } void tst_QQmlTableModel::moveRow() @@ -421,7 +484,7 @@ void tst_QQmlTableModel::moveRow() QSignalSpy rowCountSpy(model, SIGNAL(rowCountChanged())); QVERIFY(rowCountSpy.isValid()); - int heightSignalEmissions = 0; + int rowCountSignalEmissions = 0; const QHash<int, QByteArray> roleNames = model->roleNames(); @@ -431,105 +494,105 @@ void tst_QQmlTableModel::moveRow() QVERIFY(QMetaObject::invokeMethod(view.rootObject(), "appendRow", Q_ARG(QVariant, QLatin1String("Trev")), Q_ARG(QVariant, 48))); QCOMPARE(model->rowCount(), 5); QCOMPARE(model->columnCount(), 2); - QCOMPARE(model->data(model->index(0, 0, QModelIndex()), roleNames.key("name")).toString(), QLatin1String("John")); - QCOMPARE(model->data(model->index(0, 1, QModelIndex()), roleNames.key("age")).toInt(), 22); - QCOMPARE(model->data(model->index(1, 0, QModelIndex()), roleNames.key("name")).toString(), QLatin1String("Oliver")); - QCOMPARE(model->data(model->index(1, 1, QModelIndex()), roleNames.key("age")).toInt(), 33); - QCOMPARE(model->data(model->index(2, 0, QModelIndex()), roleNames.key("name")).toString(), QLatin1String("Max")); - QCOMPARE(model->data(model->index(2, 1, QModelIndex()), roleNames.key("age")).toInt(), 40); - QCOMPARE(model->data(model->index(3, 0, QModelIndex()), roleNames.key("name")).toString(), QLatin1String("Daisy")); - QCOMPARE(model->data(model->index(3, 1, QModelIndex()), roleNames.key("age")).toInt(), 30); - QCOMPARE(model->data(model->index(4, 0, QModelIndex()), roleNames.key("name")).toString(), QLatin1String("Trev")); - QCOMPARE(model->data(model->index(4, 1, QModelIndex()), roleNames.key("age")).toInt(), 48); - heightSignalEmissions = 3; + QCOMPARE(model->data(model->index(0, 0, QModelIndex()), roleNames.key("display")).toString(), QLatin1String("John")); + QCOMPARE(model->data(model->index(0, 1, QModelIndex()), roleNames.key("display")).toInt(), 22); + QCOMPARE(model->data(model->index(1, 0, QModelIndex()), roleNames.key("display")).toString(), QLatin1String("Oliver")); + QCOMPARE(model->data(model->index(1, 1, QModelIndex()), roleNames.key("display")).toInt(), 33); + QCOMPARE(model->data(model->index(2, 0, QModelIndex()), roleNames.key("display")).toString(), QLatin1String("Max")); + QCOMPARE(model->data(model->index(2, 1, QModelIndex()), roleNames.key("display")).toInt(), 40); + QCOMPARE(model->data(model->index(3, 0, QModelIndex()), roleNames.key("display")).toString(), QLatin1String("Daisy")); + QCOMPARE(model->data(model->index(3, 1, QModelIndex()), roleNames.key("display")).toInt(), 30); + QCOMPARE(model->data(model->index(4, 0, QModelIndex()), roleNames.key("display")).toString(), QLatin1String("Trev")); + QCOMPARE(model->data(model->index(4, 1, QModelIndex()), roleNames.key("display")).toInt(), 48); + rowCountSignalEmissions = 3; QCOMPARE(columnCountSpy.count(), 0); - QCOMPARE(rowCountSpy.count(), heightSignalEmissions); + QCOMPARE(rowCountSpy.count(), rowCountSignalEmissions); // Try to move with a fromRowIndex that is negative. QTest::ignoreMessage(QtWarningMsg, QRegularExpression(".*moveRow\\(\\): \"fromRowIndex\" cannot be negative")); QVERIFY(QMetaObject::invokeMethod(model, "moveRow", Q_ARG(int, -1), Q_ARG(int, 1))); // Shouldn't have changed. - QCOMPARE(model->data(model->index(4, 0, QModelIndex()), roleNames.key("name")).toString(), QLatin1String("Trev")); - QCOMPARE(model->data(model->index(4, 1, QModelIndex()), roleNames.key("age")).toInt(), 48); + QCOMPARE(model->data(model->index(4, 0, QModelIndex()), roleNames.key("display")).toString(), QLatin1String("Trev")); + QCOMPARE(model->data(model->index(4, 1, QModelIndex()), roleNames.key("display")).toInt(), 48); QCOMPARE(columnCountSpy.count(), 0); - QCOMPARE(rowCountSpy.count(), heightSignalEmissions); + QCOMPARE(rowCountSpy.count(), rowCountSignalEmissions); // Try to move with a fromRowIndex that is too large. QTest::ignoreMessage(QtWarningMsg, QRegularExpression(".*moveRow\\(\\): \"fromRowIndex\" 5 is greater than or equal to rowCount\\(\\)")); QVERIFY(QMetaObject::invokeMethod(model, "moveRow", Q_ARG(int, 5), Q_ARG(int, 1))); - QCOMPARE(model->data(model->index(4, 0, QModelIndex()), roleNames.key("name")).toString(), QLatin1String("Trev")); - QCOMPARE(model->data(model->index(4, 1, QModelIndex()), roleNames.key("age")).toInt(), 48); + QCOMPARE(model->data(model->index(4, 0, QModelIndex()), roleNames.key("display")).toString(), QLatin1String("Trev")); + QCOMPARE(model->data(model->index(4, 1, QModelIndex()), roleNames.key("display")).toInt(), 48); QCOMPARE(columnCountSpy.count(), 0); - QCOMPARE(rowCountSpy.count(), heightSignalEmissions); + QCOMPARE(rowCountSpy.count(), rowCountSignalEmissions); // Try to move with a toRowIndex that is negative. QTest::ignoreMessage(QtWarningMsg, QRegularExpression(".*moveRow\\(\\): \"toRowIndex\" cannot be negative")); QVERIFY(QMetaObject::invokeMethod(model, "moveRow", Q_ARG(int, 0), Q_ARG(int, -1))); // Shouldn't have changed. - QCOMPARE(model->data(model->index(4, 0, QModelIndex()), roleNames.key("name")).toString(), QLatin1String("Trev")); - QCOMPARE(model->data(model->index(4, 1, QModelIndex()), roleNames.key("age")).toInt(), 48); + QCOMPARE(model->data(model->index(4, 0, QModelIndex()), roleNames.key("display")).toString(), QLatin1String("Trev")); + QCOMPARE(model->data(model->index(4, 1, QModelIndex()), roleNames.key("display")).toInt(), 48); QCOMPARE(columnCountSpy.count(), 0); - QCOMPARE(rowCountSpy.count(), heightSignalEmissions); + QCOMPARE(rowCountSpy.count(), rowCountSignalEmissions); // Try to move with a toRowIndex that is too large. QTest::ignoreMessage(QtWarningMsg, QRegularExpression(".*moveRow\\(\\): \"toRowIndex\" 5 is greater than or equal to rowCount\\(\\)")); QVERIFY(QMetaObject::invokeMethod(model, "moveRow", Q_ARG(int, 0), Q_ARG(int, 5))); - QCOMPARE(model->data(model->index(4, 0, QModelIndex()), roleNames.key("name")).toString(), QLatin1String("Trev")); - QCOMPARE(model->data(model->index(4, 1, QModelIndex()), roleNames.key("age")).toInt(), 48); + QCOMPARE(model->data(model->index(4, 0, QModelIndex()), roleNames.key("display")).toString(), QLatin1String("Trev")); + QCOMPARE(model->data(model->index(4, 1, QModelIndex()), roleNames.key("display")).toInt(), 48); QCOMPARE(columnCountSpy.count(), 0); - QCOMPARE(rowCountSpy.count(), heightSignalEmissions); + QCOMPARE(rowCountSpy.count(), rowCountSignalEmissions); // Move the first row to the end. QVERIFY(QMetaObject::invokeMethod(model, "moveRow", Q_ARG(int, 0), Q_ARG(int, 4))); // The counts shouldn't have changed. QCOMPARE(model->rowCount(), 5); QCOMPARE(model->columnCount(), 2); - QCOMPARE(model->data(model->index(0, 0, QModelIndex()), roleNames.key("name")).toString(), QLatin1String("Oliver")); - QCOMPARE(model->data(model->index(0, 1, QModelIndex()), roleNames.key("age")).toInt(), 33); - QCOMPARE(model->data(model->index(1, 0, QModelIndex()), roleNames.key("name")).toString(), QLatin1String("Max")); - QCOMPARE(model->data(model->index(1, 1, QModelIndex()), roleNames.key("age")).toInt(), 40); - QCOMPARE(model->data(model->index(2, 0, QModelIndex()), roleNames.key("name")).toString(), QLatin1String("Daisy")); - QCOMPARE(model->data(model->index(2, 1, QModelIndex()), roleNames.key("age")).toInt(), 30); - QCOMPARE(model->data(model->index(3, 0, QModelIndex()), roleNames.key("name")).toString(), QLatin1String("Trev")); - QCOMPARE(model->data(model->index(3, 1, QModelIndex()), roleNames.key("age")).toInt(), 48); - QCOMPARE(model->data(model->index(4, 0, QModelIndex()), roleNames.key("name")).toString(), QLatin1String("John")); - QCOMPARE(model->data(model->index(4, 1, QModelIndex()), roleNames.key("age")).toInt(), 22); + QCOMPARE(model->data(model->index(0, 0, QModelIndex()), roleNames.key("display")).toString(), QLatin1String("Oliver")); + QCOMPARE(model->data(model->index(0, 1, QModelIndex()), roleNames.key("display")).toInt(), 33); + QCOMPARE(model->data(model->index(1, 0, QModelIndex()), roleNames.key("display")).toString(), QLatin1String("Max")); + QCOMPARE(model->data(model->index(1, 1, QModelIndex()), roleNames.key("display")).toInt(), 40); + QCOMPARE(model->data(model->index(2, 0, QModelIndex()), roleNames.key("display")).toString(), QLatin1String("Daisy")); + QCOMPARE(model->data(model->index(2, 1, QModelIndex()), roleNames.key("display")).toInt(), 30); + QCOMPARE(model->data(model->index(3, 0, QModelIndex()), roleNames.key("display")).toString(), QLatin1String("Trev")); + QCOMPARE(model->data(model->index(3, 1, QModelIndex()), roleNames.key("display")).toInt(), 48); + QCOMPARE(model->data(model->index(4, 0, QModelIndex()), roleNames.key("display")).toString(), QLatin1String("John")); + QCOMPARE(model->data(model->index(4, 1, QModelIndex()), roleNames.key("display")).toInt(), 22); QCOMPARE(columnCountSpy.count(), 0); - QCOMPARE(rowCountSpy.count(), heightSignalEmissions); + QCOMPARE(rowCountSpy.count(), rowCountSignalEmissions); // Move it back again. QVERIFY(QMetaObject::invokeMethod(model, "moveRow", Q_ARG(int, 4), Q_ARG(int, 0))); QCOMPARE(model->rowCount(), 5); QCOMPARE(model->columnCount(), 2); - QCOMPARE(model->data(model->index(0, 0, QModelIndex()), roleNames.key("name")).toString(), QLatin1String("John")); - QCOMPARE(model->data(model->index(0, 1, QModelIndex()), roleNames.key("age")).toInt(), 22); - QCOMPARE(model->data(model->index(1, 0, QModelIndex()), roleNames.key("name")).toString(), QLatin1String("Oliver")); - QCOMPARE(model->data(model->index(1, 1, QModelIndex()), roleNames.key("age")).toInt(), 33); - QCOMPARE(model->data(model->index(2, 0, QModelIndex()), roleNames.key("name")).toString(), QLatin1String("Max")); - QCOMPARE(model->data(model->index(2, 1, QModelIndex()), roleNames.key("age")).toInt(), 40); - QCOMPARE(model->data(model->index(3, 0, QModelIndex()), roleNames.key("name")).toString(), QLatin1String("Daisy")); - QCOMPARE(model->data(model->index(3, 1, QModelIndex()), roleNames.key("age")).toInt(), 30); - QCOMPARE(model->data(model->index(4, 0, QModelIndex()), roleNames.key("name")).toString(), QLatin1String("Trev")); - QCOMPARE(model->data(model->index(4, 1, QModelIndex()), roleNames.key("age")).toInt(), 48); + QCOMPARE(model->data(model->index(0, 0, QModelIndex()), roleNames.key("display")).toString(), QLatin1String("John")); + QCOMPARE(model->data(model->index(0, 1, QModelIndex()), roleNames.key("display")).toInt(), 22); + QCOMPARE(model->data(model->index(1, 0, QModelIndex()), roleNames.key("display")).toString(), QLatin1String("Oliver")); + QCOMPARE(model->data(model->index(1, 1, QModelIndex()), roleNames.key("display")).toInt(), 33); + QCOMPARE(model->data(model->index(2, 0, QModelIndex()), roleNames.key("display")).toString(), QLatin1String("Max")); + QCOMPARE(model->data(model->index(2, 1, QModelIndex()), roleNames.key("display")).toInt(), 40); + QCOMPARE(model->data(model->index(3, 0, QModelIndex()), roleNames.key("display")).toString(), QLatin1String("Daisy")); + QCOMPARE(model->data(model->index(3, 1, QModelIndex()), roleNames.key("display")).toInt(), 30); + QCOMPARE(model->data(model->index(4, 0, QModelIndex()), roleNames.key("display")).toString(), QLatin1String("Trev")); + QCOMPARE(model->data(model->index(4, 1, QModelIndex()), roleNames.key("display")).toInt(), 48); QCOMPARE(columnCountSpy.count(), 0); - QCOMPARE(rowCountSpy.count(), heightSignalEmissions); + QCOMPARE(rowCountSpy.count(), rowCountSignalEmissions); // Move the first row down one by one row. QVERIFY(QMetaObject::invokeMethod(model, "moveRow", Q_ARG(int, 0), Q_ARG(int, 1))); QCOMPARE(model->rowCount(), 5); QCOMPARE(model->columnCount(), 2); - QCOMPARE(model->data(model->index(0, 0, QModelIndex()), roleNames.key("name")).toString(), QLatin1String("Oliver")); - QCOMPARE(model->data(model->index(0, 1, QModelIndex()), roleNames.key("age")).toInt(), 33); - QCOMPARE(model->data(model->index(1, 0, QModelIndex()), roleNames.key("name")).toString(), QLatin1String("John")); - QCOMPARE(model->data(model->index(1, 1, QModelIndex()), roleNames.key("age")).toInt(), 22); - QCOMPARE(model->data(model->index(2, 0, QModelIndex()), roleNames.key("name")).toString(), QLatin1String("Max")); - QCOMPARE(model->data(model->index(2, 1, QModelIndex()), roleNames.key("age")).toInt(), 40); - QCOMPARE(model->data(model->index(3, 0, QModelIndex()), roleNames.key("name")).toString(), QLatin1String("Daisy")); - QCOMPARE(model->data(model->index(3, 1, QModelIndex()), roleNames.key("age")).toInt(), 30); - QCOMPARE(model->data(model->index(4, 0, QModelIndex()), roleNames.key("name")).toString(), QLatin1String("Trev")); - QCOMPARE(model->data(model->index(4, 1, QModelIndex()), roleNames.key("age")).toInt(), 48); - QCOMPARE(columnCountSpy.count(), 0); - QCOMPARE(rowCountSpy.count(), heightSignalEmissions); + QCOMPARE(model->data(model->index(0, 0, QModelIndex()), roleNames.key("display")).toString(), QLatin1String("Oliver")); + QCOMPARE(model->data(model->index(0, 1, QModelIndex()), roleNames.key("display")).toInt(), 33); + QCOMPARE(model->data(model->index(1, 0, QModelIndex()), roleNames.key("display")).toString(), QLatin1String("John")); + QCOMPARE(model->data(model->index(1, 1, QModelIndex()), roleNames.key("display")).toInt(), 22); + QCOMPARE(model->data(model->index(2, 0, QModelIndex()), roleNames.key("display")).toString(), QLatin1String("Max")); + QCOMPARE(model->data(model->index(2, 1, QModelIndex()), roleNames.key("display")).toInt(), 40); + QCOMPARE(model->data(model->index(3, 0, QModelIndex()), roleNames.key("display")).toString(), QLatin1String("Daisy")); + QCOMPARE(model->data(model->index(3, 1, QModelIndex()), roleNames.key("display")).toInt(), 30); + QCOMPARE(model->data(model->index(4, 0, QModelIndex()), roleNames.key("display")).toString(), QLatin1String("Trev")); + QCOMPARE(model->data(model->index(4, 1, QModelIndex()), roleNames.key("display")).toInt(), 48); + QCOMPARE(columnCountSpy.count(), 0); + QCOMPARE(rowCountSpy.count(), rowCountSignalEmissions); } void tst_QQmlTableModel::setRow() @@ -549,14 +612,14 @@ void tst_QQmlTableModel::setRow() QSignalSpy rowCountSpy(model, SIGNAL(rowCountChanged())); QVERIFY(rowCountSpy.isValid()); - int heightSignalEmissions = 0; + int rowCountSignalEmissions = 0; QQuickTableView *tableView = view.rootObject()->property("tableView").value<QQuickTableView*>(); QVERIFY(tableView); QCOMPARE(tableView->rows(), 2); QCOMPARE(tableView->columns(), 2); - // Try to insert with a negative index. + // Try to set with a negative index. QTest::ignoreMessage(QtWarningMsg, QRegularExpression( ".*setRow\\(\\): \"rowIndex\" cannot be negative")); QVERIFY(QMetaObject::invokeMethod(view.rootObject(), "setRow", @@ -564,72 +627,86 @@ void tst_QQmlTableModel::setRow() QCOMPARE(model->rowCount(), 2); QCOMPARE(model->columnCount(), 2); const QHash<int, QByteArray> roleNames = model->roleNames(); - QCOMPARE(model->data(model->index(0, 0, QModelIndex()), roleNames.key("name")).toString(), QLatin1String("John")); - QCOMPARE(model->data(model->index(0, 1, QModelIndex()), roleNames.key("age")).toInt(), 22); - QCOMPARE(model->data(model->index(1, 0, QModelIndex()), roleNames.key("name")).toString(), QLatin1String("Oliver")); - QCOMPARE(model->data(model->index(1, 1, QModelIndex()), roleNames.key("age")).toInt(), 33); + QCOMPARE(model->data(model->index(0, 0, QModelIndex()), roleNames.key("display")).toString(), QLatin1String("John")); + QCOMPARE(model->data(model->index(0, 1, QModelIndex()), roleNames.key("display")).toInt(), 22); + QCOMPARE(model->data(model->index(1, 0, QModelIndex()), roleNames.key("display")).toString(), QLatin1String("Oliver")); + QCOMPARE(model->data(model->index(1, 1, QModelIndex()), roleNames.key("display")).toInt(), 33); QCOMPARE(columnCountSpy.count(), 0); - QCOMPARE(rowCountSpy.count(), heightSignalEmissions); + QCOMPARE(rowCountSpy.count(), rowCountSignalEmissions); QCOMPARE(tableView->rows(), 2); QCOMPARE(tableView->columns(), 2); - // Try to insert past the last allowed index. + // Try to set at an index past the last allowed index. QTest::ignoreMessage(QtWarningMsg, QRegularExpression( ".*setRow\\(\\): \"rowIndex\" 3 is greater than rowCount\\(\\) of 2")); QVERIFY(QMetaObject::invokeMethod(view.rootObject(), "setRow", Q_ARG(QVariant, 3), Q_ARG(QVariant, QLatin1String("Max")), Q_ARG(QVariant, 40))); QCOMPARE(model->rowCount(), 2); QCOMPARE(model->columnCount(), 2); - QCOMPARE(model->data(model->index(0, 0, QModelIndex()), roleNames.key("name")).toString(), QLatin1String("John")); - QCOMPARE(model->data(model->index(0, 1, QModelIndex()), roleNames.key("age")).toInt(), 22); - QCOMPARE(model->data(model->index(1, 0, QModelIndex()), roleNames.key("name")).toString(), QLatin1String("Oliver")); - QCOMPARE(model->data(model->index(1, 1, QModelIndex()), roleNames.key("age")).toInt(), 33); + QCOMPARE(model->data(model->index(0, 0, QModelIndex()), roleNames.key("display")).toString(), QLatin1String("John")); + QCOMPARE(model->data(model->index(0, 1, QModelIndex()), roleNames.key("display")).toInt(), 22); + QCOMPARE(model->data(model->index(1, 0, QModelIndex()), roleNames.key("display")).toString(), QLatin1String("Oliver")); + QCOMPARE(model->data(model->index(1, 1, QModelIndex()), roleNames.key("display")).toInt(), 33); QCOMPARE(columnCountSpy.count(), 0); - QCOMPARE(rowCountSpy.count(), heightSignalEmissions); + QCOMPARE(rowCountSpy.count(), rowCountSignalEmissions); QCOMPARE(tableView->rows(), 2); QCOMPARE(tableView->columns(), 2); - // Try to insert a row that has a new (and hence unexpected) role. - QTest::ignoreMessage(QtWarningMsg, QRegularExpression(".*setRow\\(\\): expected 2 columns, but got 3")); - QVERIFY(QMetaObject::invokeMethod(view.rootObject(), "setRowInvalid1")); + // Try to set a row that has an unexpected role; the row should be set and the extra data ignored. + QVERIFY(QMetaObject::invokeMethod(view.rootObject(), "setRowExtraData")); QCOMPARE(model->rowCount(), 2); QCOMPARE(model->columnCount(), 2); - QCOMPARE(model->data(model->index(0, 0, QModelIndex()), roleNames.key("name")).toString(), QLatin1String("John")); - QCOMPARE(model->data(model->index(0, 1, QModelIndex()), roleNames.key("age")).toInt(), 22); - QCOMPARE(model->data(model->index(1, 0, QModelIndex()), roleNames.key("name")).toString(), QLatin1String("Oliver")); - QCOMPARE(model->data(model->index(1, 1, QModelIndex()), roleNames.key("age")).toInt(), 33); + QCOMPARE(model->data(model->index(0, 0, QModelIndex()), roleNames.key("display")).toString(), QLatin1String("Foo")); + QCOMPARE(model->data(model->index(0, 1, QModelIndex()), roleNames.key("display")).toInt(), 99); + QCOMPARE(model->data(model->index(1, 0, QModelIndex()), roleNames.key("display")).toString(), QLatin1String("Oliver")); + QCOMPARE(model->data(model->index(1, 1, QModelIndex()), roleNames.key("display")).toInt(), 33); QCOMPARE(columnCountSpy.count(), 0); - QCOMPARE(rowCountSpy.count(), heightSignalEmissions); + QCOMPARE(rowCountSpy.count(), rowCountSignalEmissions); QCOMPARE(tableView->rows(), 2); QCOMPARE(tableView->columns(), 2); // Try to insert a row that is not an array. QTest::ignoreMessage(QtWarningMsg, QRegularExpression( - ".*setRow\\(\\): expected \"row\" argument to be an array, but got int instead")); - QVERIFY(QMetaObject::invokeMethod(view.rootObject(), "setRowInvalid2")); + ".*setRow\\(\\): expected \"row\" argument to be a QJSValue, but got int instead:\nQVariant\\(int, 123\\)")); + QVERIFY(QMetaObject::invokeMethod(view.rootObject(), "setRowInvalid1")); QCOMPARE(model->rowCount(), 2); QCOMPARE(model->columnCount(), 2); - QCOMPARE(model->data(model->index(0, 0, QModelIndex()), roleNames.key("name")).toString(), QLatin1String("John")); - QCOMPARE(model->data(model->index(0, 1, QModelIndex()), roleNames.key("age")).toInt(), 22); - QCOMPARE(model->data(model->index(1, 0, QModelIndex()), roleNames.key("name")).toString(), QLatin1String("Oliver")); - QCOMPARE(model->data(model->index(1, 1, QModelIndex()), roleNames.key("age")).toInt(), 33); + QCOMPARE(model->data(model->index(0, 0, QModelIndex()), roleNames.key("display")).toString(), QLatin1String("Foo")); + QCOMPARE(model->data(model->index(0, 1, QModelIndex()), roleNames.key("display")).toInt(), 99); + QCOMPARE(model->data(model->index(1, 0, QModelIndex()), roleNames.key("display")).toString(), QLatin1String("Oliver")); + QCOMPARE(model->data(model->index(1, 1, QModelIndex()), roleNames.key("display")).toInt(), 33); QCOMPARE(columnCountSpy.count(), 0); - QCOMPARE(rowCountSpy.count(), heightSignalEmissions); + QCOMPARE(rowCountSpy.count(), rowCountSignalEmissions); QCOMPARE(tableView->rows(), 2); QCOMPARE(tableView->columns(), 2); // Try to insert a row with a role that is of the wrong type. QTest::ignoreMessage(QtWarningMsg, QRegularExpression( - ".*setRow\\(\\): expected property with type int at column index 1, but got QVariantList instead")); + ".*setRow\\(\\): expected the property named \"age\" to be of type \"int\", but got \"QVariantList\" instead")); + QVERIFY(QMetaObject::invokeMethod(view.rootObject(), "setRowInvalid2")); + QCOMPARE(model->rowCount(), 2); + QCOMPARE(model->columnCount(), 2); + QCOMPARE(model->data(model->index(0, 0, QModelIndex()), roleNames.key("display")).toString(), QLatin1String("Foo")); + QCOMPARE(model->data(model->index(0, 1, QModelIndex()), roleNames.key("display")).toInt(), 99); + QCOMPARE(model->data(model->index(1, 0, QModelIndex()), roleNames.key("display")).toString(), QLatin1String("Oliver")); + QCOMPARE(model->data(model->index(1, 1, QModelIndex()), roleNames.key("display")).toInt(), 33); + QCOMPARE(columnCountSpy.count(), 0); + QCOMPARE(rowCountSpy.count(), rowCountSignalEmissions); + QCOMPARE(tableView->rows(), 2); + QCOMPARE(tableView->columns(), 2); + + // Try to insert a row that is an array instead of a simple object. + QTest::ignoreMessage(QtWarningMsg, QRegularExpression( + ".*setRow\\(\\): row manipulation functions do not support complex rows \\(row index: 0\\)")); QVERIFY(QMetaObject::invokeMethod(view.rootObject(), "setRowInvalid3")); QCOMPARE(model->rowCount(), 2); QCOMPARE(model->columnCount(), 2); - QCOMPARE(model->data(model->index(0, 0, QModelIndex()), roleNames.key("name")).toString(), QLatin1String("John")); - QCOMPARE(model->data(model->index(0, 1, QModelIndex()), roleNames.key("age")).toInt(), 22); - QCOMPARE(model->data(model->index(1, 0, QModelIndex()), roleNames.key("name")).toString(), QLatin1String("Oliver")); - QCOMPARE(model->data(model->index(1, 1, QModelIndex()), roleNames.key("age")).toInt(), 33); + QCOMPARE(model->data(model->index(0, 0, QModelIndex()), roleNames.key("display")).toString(), QLatin1String("Foo")); + QCOMPARE(model->data(model->index(0, 1, QModelIndex()), roleNames.key("display")).toInt(), 99); + QCOMPARE(model->data(model->index(1, 0, QModelIndex()), roleNames.key("display")).toString(), QLatin1String("Oliver")); + QCOMPARE(model->data(model->index(1, 1, QModelIndex()), roleNames.key("display")).toInt(), 33); QCOMPARE(columnCountSpy.count(), 0); - QCOMPARE(rowCountSpy.count(), heightSignalEmissions); + QCOMPARE(rowCountSpy.count(), rowCountSignalEmissions); QCOMPARE(tableView->rows(), 2); QCOMPARE(tableView->columns(), 2); @@ -638,12 +715,12 @@ void tst_QQmlTableModel::setRow() Q_ARG(QVariant, 0), Q_ARG(QVariant, QLatin1String("Max")), Q_ARG(QVariant, 40))); QCOMPARE(model->rowCount(), 2); QCOMPARE(model->columnCount(), 2); - QCOMPARE(model->data(model->index(0, 0, QModelIndex()), roleNames.key("name")).toString(), QLatin1String("Max")); - QCOMPARE(model->data(model->index(0, 1, QModelIndex()), roleNames.key("age")).toInt(), 40); - QCOMPARE(model->data(model->index(1, 0, QModelIndex()), roleNames.key("name")).toString(), QLatin1String("Oliver")); - QCOMPARE(model->data(model->index(1, 1, QModelIndex()), roleNames.key("age")).toInt(), 33); + QCOMPARE(model->data(model->index(0, 0, QModelIndex()), roleNames.key("display")).toString(), QLatin1String("Max")); + QCOMPARE(model->data(model->index(0, 1, QModelIndex()), roleNames.key("display")).toInt(), 40); + QCOMPARE(model->data(model->index(1, 0, QModelIndex()), roleNames.key("display")).toString(), QLatin1String("Oliver")); + QCOMPARE(model->data(model->index(1, 1, QModelIndex()), roleNames.key("display")).toInt(), 33); QCOMPARE(columnCountSpy.count(), 0); - QCOMPARE(rowCountSpy.count(), heightSignalEmissions); + QCOMPARE(rowCountSpy.count(), rowCountSignalEmissions); QCOMPARE(tableView->rows(), 2); QCOMPARE(tableView->columns(), 2); @@ -652,12 +729,12 @@ void tst_QQmlTableModel::setRow() Q_ARG(QVariant, 1), Q_ARG(QVariant, QLatin1String("Daisy")), Q_ARG(QVariant, 30))); QCOMPARE(model->rowCount(), 2); QCOMPARE(model->columnCount(), 2); - QCOMPARE(model->data(model->index(0, 0, QModelIndex()), roleNames.key("name")).toString(), QLatin1String("Max")); - QCOMPARE(model->data(model->index(0, 1, QModelIndex()), roleNames.key("age")).toInt(), 40); - QCOMPARE(model->data(model->index(1, 0, QModelIndex()), roleNames.key("name")).toString(), QLatin1String("Daisy")); - QCOMPARE(model->data(model->index(1, 1, QModelIndex()), roleNames.key("age")).toInt(), 30); + QCOMPARE(model->data(model->index(0, 0, QModelIndex()), roleNames.key("display")).toString(), QLatin1String("Max")); + QCOMPARE(model->data(model->index(0, 1, QModelIndex()), roleNames.key("display")).toInt(), 40); + QCOMPARE(model->data(model->index(1, 0, QModelIndex()), roleNames.key("display")).toString(), QLatin1String("Daisy")); + QCOMPARE(model->data(model->index(1, 1, QModelIndex()), roleNames.key("display")).toInt(), 30); QCOMPARE(columnCountSpy.count(), 0); - QCOMPARE(rowCountSpy.count(), heightSignalEmissions); + QCOMPARE(rowCountSpy.count(), rowCountSignalEmissions); QCOMPARE(tableView->rows(), 2); QCOMPARE(tableView->columns(), 2); @@ -666,14 +743,14 @@ void tst_QQmlTableModel::setRow() Q_ARG(QVariant, 2), Q_ARG(QVariant, QLatin1String("Wot")), Q_ARG(QVariant, 99))); QCOMPARE(model->rowCount(), 3); QCOMPARE(model->columnCount(), 2); - QCOMPARE(model->data(model->index(0, 0, QModelIndex()), roleNames.key("name")).toString(), QLatin1String("Max")); - QCOMPARE(model->data(model->index(0, 1, QModelIndex()), roleNames.key("age")).toInt(), 40); - QCOMPARE(model->data(model->index(1, 0, QModelIndex()), roleNames.key("name")).toString(), QLatin1String("Daisy")); - QCOMPARE(model->data(model->index(1, 1, QModelIndex()), roleNames.key("age")).toInt(), 30); - QCOMPARE(model->data(model->index(2, 0, QModelIndex()), roleNames.key("name")).toString(), QLatin1String("Wot")); - QCOMPARE(model->data(model->index(2, 1, QModelIndex()), roleNames.key("age")).toInt(), 99); + QCOMPARE(model->data(model->index(0, 0, QModelIndex()), roleNames.key("display")).toString(), QLatin1String("Max")); + QCOMPARE(model->data(model->index(0, 1, QModelIndex()), roleNames.key("display")).toInt(), 40); + QCOMPARE(model->data(model->index(1, 0, QModelIndex()), roleNames.key("display")).toString(), QLatin1String("Daisy")); + QCOMPARE(model->data(model->index(1, 1, QModelIndex()), roleNames.key("display")).toInt(), 30); + QCOMPARE(model->data(model->index(2, 0, QModelIndex()), roleNames.key("display")).toString(), QLatin1String("Wot")); + QCOMPARE(model->data(model->index(2, 1, QModelIndex()), roleNames.key("display")).toInt(), 99); QCOMPARE(columnCountSpy.count(), 0); - QCOMPARE(rowCountSpy.count(), ++heightSignalEmissions); + QCOMPARE(rowCountSpy.count(), ++rowCountSignalEmissions); QTRY_COMPARE(tableView->rows(), 3); QCOMPARE(tableView->columns(), 2); } @@ -697,56 +774,50 @@ void tst_QQmlTableModel::setDataThroughDelegate() QVERIFY(rowCountSpy.isValid()); const QHash<int, QByteArray> roleNames = model->roleNames(); - QCOMPARE(roleNames.size(), 2 + builtInRoleCount); - QVERIFY(roleNames.values().contains("name")); - QVERIFY(roleNames.values().contains("age")); - QCOMPARE(model->data(model->index(0, 0, QModelIndex()), roleNames.key("name")).toString(), QLatin1String("John")); - QCOMPARE(model->data(model->index(0, 1, QModelIndex()), roleNames.key("age")).toInt(), 22); - QCOMPARE(model->data(model->index(1, 0, QModelIndex()), roleNames.key("name")).toString(), QLatin1String("Oliver")); - QCOMPARE(model->data(model->index(1, 1, QModelIndex()), roleNames.key("age")).toInt(), 33); + QCOMPARE(roleNames.size(), 1); + QVERIFY(roleNames.values().contains("display")); + QCOMPARE(model->data(model->index(0, 0, QModelIndex()), roleNames.key("display")).toString(), QLatin1String("John")); + QCOMPARE(model->data(model->index(0, 1, QModelIndex()), roleNames.key("display")).toInt(), 22); + QCOMPARE(model->data(model->index(1, 0, QModelIndex()), roleNames.key("display")).toString(), QLatin1String("Oliver")); + QCOMPARE(model->data(model->index(1, 1, QModelIndex()), roleNames.key("display")).toInt(), 33); QCOMPARE(columnCountSpy.count(), 0); QCOMPARE(rowCountSpy.count(), 0); QVERIFY(QMetaObject::invokeMethod(view.rootObject(), "modify")); - QCOMPARE(model->data(model->index(0, 0, QModelIndex()), roleNames.key("name")).toString(), QLatin1String("John")); - QCOMPARE(model->data(model->index(0, 1, QModelIndex()), roleNames.key("age")).toInt(), 18); - QCOMPARE(model->data(model->index(1, 0, QModelIndex()), roleNames.key("name")).toString(), QLatin1String("Oliver")); - QCOMPARE(model->data(model->index(1, 1, QModelIndex()), roleNames.key("age")).toInt(), 18); + QCOMPARE(model->data(model->index(0, 0, QModelIndex()), roleNames.key("display")).toString(), QLatin1String("John")); + QCOMPARE(model->data(model->index(0, 1, QModelIndex()), roleNames.key("display")).toInt(), 18); + QCOMPARE(model->data(model->index(1, 0, QModelIndex()), roleNames.key("display")).toString(), QLatin1String("Oliver")); + QCOMPARE(model->data(model->index(1, 1, QModelIndex()), roleNames.key("display")).toInt(), 18); QCOMPARE(columnCountSpy.count(), 0); QCOMPARE(rowCountSpy.count(), 0); // Test setting a role that doesn't exist for a certain column. - const auto invalidRoleRegEx = QRegularExpression(".*setData\\(\\): no role named \"age\" at column index 0. " \ - "The available roles for that column are:[\r\n] - \"name\" \\(QString\\)"); - // There are two rows, so two delegates respond to the signal, which means we need to ignore two warnings. - QTest::ignoreMessage(QtWarningMsg, invalidRoleRegEx); - QTest::ignoreMessage(QtWarningMsg, invalidRoleRegEx); QVERIFY(QMetaObject::invokeMethod(view.rootObject(), "modifyInvalidRole")); // Should be unchanged. - QCOMPARE(model->data(model->index(0, 0, QModelIndex()), roleNames.key("name")).toString(), QLatin1String("John")); - QCOMPARE(model->data(model->index(0, 1, QModelIndex()), roleNames.key("age")).toInt(), 18); - QCOMPARE(model->data(model->index(1, 0, QModelIndex()), roleNames.key("name")).toString(), QLatin1String("Oliver")); - QCOMPARE(model->data(model->index(1, 1, QModelIndex()), roleNames.key("age")).toInt(), 18); + QCOMPARE(model->data(model->index(0, 0, QModelIndex()), roleNames.key("display")).toString(), QLatin1String("John")); + QCOMPARE(model->data(model->index(0, 1, QModelIndex()), roleNames.key("display")).toInt(), 18); + QCOMPARE(model->data(model->index(1, 0, QModelIndex()), roleNames.key("display")).toString(), QLatin1String("Oliver")); + QCOMPARE(model->data(model->index(1, 1, QModelIndex()), roleNames.key("display")).toInt(), 18); QCOMPARE(columnCountSpy.count(), 0); QCOMPARE(rowCountSpy.count(), 0); // Test setting a role with a value of the wrong type. // There are two rows, so two delegates respond to the signal, which means we need to ignore two warnings. QTest::ignoreMessage(QtWarningMsg, QRegularExpression(".*setData\\(\\): failed converting value QVariant\\(QString, \"Whoops\"\\) " \ - "set at row 0 column 1 with role \"age\" to \"int\"")); + "set at row 0 column 1 with role \"display\" to \"int\"")); QTest::ignoreMessage(QtWarningMsg, QRegularExpression(".*setData\\(\\): failed converting value QVariant\\(QString, \"Whoops\"\\) " \ - "set at row 1 column 1 with role \"age\" to \"int\"")); + "set at row 1 column 1 with role \"display\" to \"int\"")); QVERIFY(QMetaObject::invokeMethod(view.rootObject(), "modifyInvalidType")); // Should be unchanged. - QCOMPARE(model->data(model->index(0, 0, QModelIndex()), roleNames.key("name")).toString(), QLatin1String("John")); - QCOMPARE(model->data(model->index(0, 1, QModelIndex()), roleNames.key("age")).toInt(), 18); - QCOMPARE(model->data(model->index(1, 0, QModelIndex()), roleNames.key("name")).toString(), QLatin1String("Oliver")); - QCOMPARE(model->data(model->index(1, 1, QModelIndex()), roleNames.key("age")).toInt(), 18); + QCOMPARE(model->data(model->index(0, 0, QModelIndex()), roleNames.key("display")).toString(), QLatin1String("John")); + QCOMPARE(model->data(model->index(0, 1, QModelIndex()), roleNames.key("display")).toInt(), 18); + QCOMPARE(model->data(model->index(1, 0, QModelIndex()), roleNames.key("display")).toString(), QLatin1String("Oliver")); + QCOMPARE(model->data(model->index(1, 1, QModelIndex()), roleNames.key("display")).toInt(), 18); QCOMPARE(columnCountSpy.count(), 0); QCOMPARE(rowCountSpy.count(), 0); } -// Start off with empty rows and append to test widthChanged(). +// Start off with empty rows and then set them to test rowCountChanged(). void tst_QQmlTableModel::setRowsImperatively() { QQuickView view(testFileUrl("empty.qml")); @@ -756,8 +827,8 @@ void tst_QQmlTableModel::setRowsImperatively() QQmlTableModel *model = view.rootObject()->property("testModel").value<QQmlTableModel*>(); QVERIFY(model); - QCOMPARE(model->columnCount(), 0); QCOMPARE(model->rowCount(), 0); + QCOMPARE(model->columnCount(), 2); QSignalSpy columnCountSpy(model, SIGNAL(columnCountChanged())); QVERIFY(columnCountSpy.isValid()); @@ -768,17 +839,17 @@ void tst_QQmlTableModel::setRowsImperatively() QQuickTableView *tableView = view.rootObject()->property("tableView").value<QQuickTableView*>(); QVERIFY(tableView); QCOMPARE(tableView->rows(), 0); - QCOMPARE(tableView->columns(), 0); + QCOMPARE(tableView->columns(), 2); QVERIFY(QMetaObject::invokeMethod(view.rootObject(), "setRows")); QCOMPARE(model->rowCount(), 2); QCOMPARE(model->columnCount(), 2); const QHash<int, QByteArray> roleNames = model->roleNames(); - QCOMPARE(model->data(model->index(0, 0, QModelIndex()), roleNames.key("name")).toString(), QLatin1String("John")); - QCOMPARE(model->data(model->index(0, 1, QModelIndex()), roleNames.key("age")).toInt(), 22); - QCOMPARE(model->data(model->index(1, 0, QModelIndex()), roleNames.key("name")).toString(), QLatin1String("Oliver")); - QCOMPARE(model->data(model->index(1, 1, QModelIndex()), roleNames.key("age")).toInt(), 33); - QCOMPARE(columnCountSpy.count(), 1); + QCOMPARE(model->data(model->index(0, 0, QModelIndex()), roleNames.key("display")).toString(), QLatin1String("John")); + QCOMPARE(model->data(model->index(0, 1, QModelIndex()), roleNames.key("display")).toInt(), 22); + QCOMPARE(model->data(model->index(1, 0, QModelIndex()), roleNames.key("display")).toString(), QLatin1String("Oliver")); + QCOMPARE(model->data(model->index(1, 1, QModelIndex()), roleNames.key("display")).toInt(), 33); + QCOMPARE(columnCountSpy.count(), 0); QCOMPARE(rowCountSpy.count(), 1); QTRY_COMPARE(tableView->rows(), 2); QCOMPARE(tableView->columns(), 2); @@ -812,134 +883,96 @@ void tst_QQmlTableModel::setRowsMultipleTimes() QCOMPARE(model->rowCount(), 3); QCOMPARE(model->columnCount(), 2); const QHash<int, QByteArray> roleNames = model->roleNames(); - QCOMPARE(model->data(model->index(0, 0, QModelIndex()), roleNames.key("name")).toString(), QLatin1String("Max")); - QCOMPARE(model->data(model->index(0, 1, QModelIndex()), roleNames.key("age")).toInt(), 20); - QCOMPARE(model->data(model->index(1, 0, QModelIndex()), roleNames.key("name")).toString(), QLatin1String("Imum")); - QCOMPARE(model->data(model->index(1, 1, QModelIndex()), roleNames.key("age")).toInt(), 41); - QCOMPARE(model->data(model->index(2, 0, QModelIndex()), roleNames.key("name")).toString(), QLatin1String("Power")); - QCOMPARE(model->data(model->index(2, 1, QModelIndex()), roleNames.key("age")).toInt(), 89); + QCOMPARE(model->data(model->index(0, 0, QModelIndex()), roleNames.key("display")).toString(), QLatin1String("Max")); + QCOMPARE(model->data(model->index(0, 1, QModelIndex()), roleNames.key("display")).toInt(), 20); + QCOMPARE(model->data(model->index(1, 0, QModelIndex()), roleNames.key("display")).toString(), QLatin1String("Imum")); + QCOMPARE(model->data(model->index(1, 1, QModelIndex()), roleNames.key("display")).toInt(), 41); + QCOMPARE(model->data(model->index(2, 0, QModelIndex()), roleNames.key("display")).toString(), QLatin1String("Power")); + QCOMPARE(model->data(model->index(2, 1, QModelIndex()), roleNames.key("display")).toInt(), 89); QCOMPARE(columnCountSpy.count(), 0); QCOMPARE(rowCountSpy.count(), 1); QTRY_COMPARE(tableView->rows(), 3); QCOMPARE(tableView->columns(), 2); // Set invalid rows; we should get a warning and nothing should change. - // TODO: add quotes to the warning message QTest::ignoreMessage(QtWarningMsg, QRegularExpression( - ".*setRows\\(\\): expected property named name at column index 0, but got nope instead")); + ".*setRows\\(\\): expected a property named \"name\" in row at index 0, but couldn't find one")); QVERIFY(QMetaObject::invokeMethod(view.rootObject(), "setRowsInvalid")); QCOMPARE(model->rowCount(), 3); QCOMPARE(model->columnCount(), 2); - QCOMPARE(model->data(model->index(0, 0, QModelIndex()), roleNames.key("name")).toString(), QLatin1String("Max")); - QCOMPARE(model->data(model->index(0, 1, QModelIndex()), roleNames.key("age")).toInt(), 20); - QCOMPARE(model->data(model->index(1, 0, QModelIndex()), roleNames.key("name")).toString(), QLatin1String("Imum")); - QCOMPARE(model->data(model->index(1, 1, QModelIndex()), roleNames.key("age")).toInt(), 41); - QCOMPARE(model->data(model->index(2, 0, QModelIndex()), roleNames.key("name")).toString(), QLatin1String("Power")); - QCOMPARE(model->data(model->index(2, 1, QModelIndex()), roleNames.key("age")).toInt(), 89); + QCOMPARE(model->data(model->index(0, 0, QModelIndex()), roleNames.key("display")).toString(), QLatin1String("Max")); + QCOMPARE(model->data(model->index(0, 1, QModelIndex()), roleNames.key("display")).toInt(), 20); + QCOMPARE(model->data(model->index(1, 0, QModelIndex()), roleNames.key("display")).toString(), QLatin1String("Imum")); + QCOMPARE(model->data(model->index(1, 1, QModelIndex()), roleNames.key("display")).toInt(), 41); + QCOMPARE(model->data(model->index(2, 0, QModelIndex()), roleNames.key("display")).toString(), QLatin1String("Power")); + QCOMPARE(model->data(model->index(2, 1, QModelIndex()), roleNames.key("display")).toInt(), 89); QCOMPARE(columnCountSpy.count(), 0); QCOMPARE(rowCountSpy.count(), 1); QCOMPARE(tableView->rows(), 3); QCOMPARE(tableView->columns(), 2); } -void tst_QQmlTableModel::builtInRoles_data() -{ - QTest::addColumn<int>("row"); - QTest::addColumn<int>("column"); - QTest::addColumn<QByteArray>("roleName"); - QTest::addColumn<QVariant>("expectedValue"); - - const QByteArray displayRole = "display"; - - QTest::addRow("display(0,0)") << 0 << 0 << displayRole << QVariant(QLatin1String("John")); - QTest::addRow("display(0,1)") << 0 << 1 << displayRole << QVariant(QLatin1String("22")); - QTest::addRow("display(1,0)") << 1 << 0 << displayRole << QVariant(QLatin1String("Oliver")); - QTest::addRow("display(1,1)") << 1 << 1 << displayRole << QVariant(QLatin1String("33")); -} - -void tst_QQmlTableModel::builtInRoles() +void tst_QQmlTableModel::dataAndEditing() { - QFETCH(int, row); - QFETCH(int, column); - QFETCH(QByteArray, roleName); - QFETCH(QVariant, expectedValue); - - QQmlEngine engine; - QQmlComponent component(&engine, testFileUrl("builtInRoles.qml")); - QCOMPARE(component.status(), QQmlComponent::Ready); + QQuickView view(testFileUrl("dataAndSetData.qml")); + QCOMPARE(view.status(), QQuickView::Ready); + view.show(); + QVERIFY(QTest::qWaitForWindowActive(&view)); - QScopedPointer<QQmlTableModel> model(qobject_cast<QQmlTableModel*>(component.create())); + QQmlTableModel *model = view.rootObject()->property("model").value<QQmlTableModel*>(); QVERIFY(model); - QCOMPARE(model->rowCount(), 2); - QCOMPARE(model->columnCount(), 2); const QHash<int, QByteArray> roleNames = model->roleNames(); - QCOMPARE(roleNames.size(), 4 + builtInRoleCount); QVERIFY(roleNames.values().contains("display")); - QVERIFY(roleNames.values().contains("decoration")); - QVERIFY(roleNames.values().contains("edit")); - QVERIFY(roleNames.values().contains("toolTip")); - QVERIFY(roleNames.values().contains("statusTip")); - QVERIFY(roleNames.values().contains("whatsThis")); - QVERIFY(roleNames.values().contains("name")); - QVERIFY(roleNames.values().contains("age")); - QVERIFY(roleNames.values().contains("someOtherRole1")); - QVERIFY(roleNames.values().contains("someOtherRole2")); - QCOMPARE(model->data(model->index(row, column, QModelIndex()), roleNames.key(roleName)), expectedValue); + QCOMPARE(model->data(model->index(0, 1, QModelIndex()), roleNames.key("display")).toInt(), 22); + QCOMPARE(model->data(model->index(1, 1, QModelIndex()), roleNames.key("display")).toInt(), 33); + QVERIFY(QMetaObject::invokeMethod(model, "happyBirthday", Q_ARG(QVariant, QLatin1String("Oliver")))); + QCOMPARE(model->data(model->index(0, 0, QModelIndex()), roleNames.key("display")).toString(), QLatin1String("John")); + QCOMPARE(model->data(model->index(0, 1, QModelIndex()), roleNames.key("display")).toInt(), 22); + QCOMPARE(model->data(model->index(1, 0, QModelIndex()), roleNames.key("display")).toString(), QLatin1String("Oliver")); + QCOMPARE(model->data(model->index(1, 1, QModelIndex()), roleNames.key("display")).toInt(), 34); } -void tst_QQmlTableModel::explicitDisplayRole() +void tst_QQmlTableModel::omitTableModelColumnIndex() { QQmlEngine engine; - QQmlComponent component(&engine, testFileUrl("explicitDisplayRole.qml")); + QQmlComponent component(&engine, testFileUrl("omitTableModelColumnIndex.qml")); QCOMPARE(component.status(), QQmlComponent::Ready); QScopedPointer<QQmlTableModel> model(qobject_cast<QQmlTableModel*>(component.create())); QVERIFY(model); - QCOMPARE(model->rowCount(), 1); + QCOMPARE(model->rowCount(), 2); QCOMPARE(model->columnCount(), 2); - const QHash<int, QByteArray> roleNames = model->roleNames(); - QCOMPARE(model->data(model->index(0, 0, QModelIndex()), roleNames.key("display")).toString(), QLatin1String("foo")); - QCOMPARE(model->data(model->index(0, 1, QModelIndex()), roleNames.key("display")).toString(), QLatin1String("bar")); -} - -void tst_QQmlTableModel::roleDataProvider() -{ - QQuickView view(testFileUrl("roleDataProvider.qml")); - QCOMPARE(view.status(), QQuickView::Ready); - view.show(); - QVERIFY(QTest::qWaitForWindowActive(&view)); - - QQmlTableModel *model = view.rootObject()->property("testModel").value<QQmlTableModel*>(); - QVERIFY(model); const QHash<int, QByteArray> roleNames = model->roleNames(); - QVERIFY(roleNames.values().contains("display")); - QCOMPARE(model->data(model->index(0, 0, QModelIndex()), roleNames.key("display")).toString(), QLatin1String("Rex")); - QCOMPARE(model->data(model->index(0, 1, QModelIndex()), roleNames.key("display")).toInt(), 3 * 7); - QCOMPARE(model->data(model->index(1, 0, QModelIndex()), roleNames.key("display")).toString(), QLatin1String("Buster")); - QCOMPARE(model->data(model->index(1, 1, QModelIndex()), roleNames.key("display")).toInt(), 5 * 7); + QCOMPARE(model->data(model->index(0, 0, QModelIndex()), roleNames.key("display")).toString(), QLatin1String("John")); + QCOMPARE(model->data(model->index(0, 1, QModelIndex()), roleNames.key("display")).toInt(), 22); + QCOMPARE(model->data(model->index(1, 0, QModelIndex()), roleNames.key("display")).toString(), QLatin1String("Oliver")); + QCOMPARE(model->data(model->index(1, 1, QModelIndex()), roleNames.key("display")).toInt(), 33); } -void tst_QQmlTableModel::dataAndEditing() +void tst_QQmlTableModel::complexRow() { - QQuickView view(testFileUrl("dataAndSetData.qml")); + QQuickView view(testFileUrl("complex.qml")); QCOMPARE(view.status(), QQuickView::Ready); view.show(); QVERIFY(QTest::qWaitForWindowActive(&view)); - QQmlTableModel *model = view.rootObject()->property("model").value<QQmlTableModel*>(); + QQuickTableView *tableView = qobject_cast<QQuickTableView*>(view.rootObject()); + QVERIFY(tableView); + QCOMPARE(tableView->rows(), 2); + QCOMPARE(tableView->columns(), 2); + + QQmlTableModel *model = tableView->model().value<QQmlTableModel*>(); QVERIFY(model); + QCOMPARE(model->rowCount(), 2); + QCOMPARE(model->columnCount(), 2); const QHash<int, QByteArray> roleNames = model->roleNames(); - QVERIFY(roleNames.values().contains("display")); - QCOMPARE(model->data(model->index(0, 1, QModelIndex()), roleNames.key("display")).toInt(), 22); - QCOMPARE(model->data(model->index(1, 1, QModelIndex()), roleNames.key("display")).toInt(), 33); - QVERIFY(QMetaObject::invokeMethod(model, "happyBirthday", Q_ARG(QVariant, QLatin1String("Oliver")))); QCOMPARE(model->data(model->index(0, 0, QModelIndex()), roleNames.key("display")).toString(), QLatin1String("John")); QCOMPARE(model->data(model->index(0, 1, QModelIndex()), roleNames.key("display")).toInt(), 22); QCOMPARE(model->data(model->index(1, 0, QModelIndex()), roleNames.key("display")).toString(), QLatin1String("Oliver")); - QCOMPARE(model->data(model->index(1, 1, QModelIndex()), roleNames.key("display")).toInt(), 34); + QCOMPARE(model->data(model->index(1, 1, QModelIndex()), roleNames.key("display")).toInt(), 33); } QTEST_MAIN(tst_QQmlTableModel) diff --git a/tests/auto/qml/qqmlvaluetypes/tst_qqmlvaluetypes.cpp b/tests/auto/qml/qqmlvaluetypes/tst_qqmlvaluetypes.cpp index 8a01524b5b..83a37df797 100644 --- a/tests/auto/qml/qqmlvaluetypes/tst_qqmlvaluetypes.cpp +++ b/tests/auto/qml/qqmlvaluetypes/tst_qqmlvaluetypes.cpp @@ -33,6 +33,8 @@ #include <QJSValueIterator> #include <private/qquickvaluetypes_p.h> #include <private/qqmlglobal_p.h> +#include <private/qv4engine_p.h> +#include <private/qv4variantobject_p.h> #include "../../shared/util.h" #include "testtypes.h" @@ -94,6 +96,7 @@ private slots: void toStringConversion(); void enumerableProperties(); void enumProperties(); + void scarceTypes(); private: QQmlEngine engine; @@ -1809,6 +1812,26 @@ void tst_qqmlvaluetypes::enumProperties() QCOMPARE(enumValue.toInt(), int(g.enumProperty())); } +void tst_qqmlvaluetypes::scarceTypes() +{ + // These should not be treated as value types because we want the scarce resource + // mechanism to clear them when going out of scope. The scarce resource mechanism + // only works on QV4::VariantObject as that has an additional level of redirection. + QVERIFY(!QQmlValueTypeFactory::isValueType(qMetaTypeId<QImage>())); + QVERIFY(!QQmlValueTypeFactory::isValueType(qMetaTypeId<QPixmap>())); + + QV4::ExecutionEngine engine; + QV4::Scope scope(&engine); + + QImage img(20, 20, QImage::Format_ARGB32); + QV4::ScopedObject imgValue(scope, engine.fromVariant(QVariant::fromValue(img))); + QCOMPARE(QByteArray(imgValue->vtable()->className), QByteArray("VariantObject")); + + QPixmap pixmap; + QV4::ScopedObject pixmapValue(scope, engine.fromVariant(QVariant::fromValue(img))); + QCOMPARE(QByteArray(pixmapValue->vtable()->className), QByteArray("VariantObject")); +} + QTEST_MAIN(tst_qqmlvaluetypes) diff --git a/tests/auto/qml/qquickfolderlistmodel/BLACKLIST b/tests/auto/qml/qquickfolderlistmodel/BLACKLIST new file mode 100644 index 0000000000..642fdea741 --- /dev/null +++ b/tests/auto/qml/qquickfolderlistmodel/BLACKLIST @@ -0,0 +1,3 @@ +[nameFilters] +msvc-2015 +msvc-2017 diff --git a/tests/auto/qml/qquickworkerscript/tst_qquickworkerscript.cpp b/tests/auto/qml/qquickworkerscript/tst_qquickworkerscript.cpp index dfaeca67f1..bea9978f0b 100644 --- a/tests/auto/qml/qquickworkerscript/tst_qquickworkerscript.cpp +++ b/tests/auto/qml/qquickworkerscript/tst_qquickworkerscript.cpp @@ -92,14 +92,14 @@ void tst_QQuickWorkerScript::source() QCOMPARE(worker->source(), source); QVERIFY(QMetaObject::invokeMethod(worker.data(), "testSend", Q_ARG(QVariant, value))); waitForEchoMessage(worker.data()); - QCOMPARE(mo->property(mo->indexOfProperty("response")).read(worker.data()).value<QVariant>(), qVariantFromValue(QString("Hello_World"))); + QCOMPARE(mo->property(mo->indexOfProperty("response")).read(worker.data()).value<QVariant>(), QVariant::fromValue(QString("Hello_World"))); source = testFileUrl("script_module.mjs"); worker->setSource(source); QCOMPARE(worker->source(), source); QVERIFY(QMetaObject::invokeMethod(worker.data(), "testSend", Q_ARG(QVariant, value))); waitForEchoMessage(worker.data()); - QCOMPARE(mo->property(mo->indexOfProperty("response")).read(worker.data()).value<QVariant>(), qVariantFromValue(QString("Hello from the module"))); + QCOMPARE(mo->property(mo->indexOfProperty("response")).read(worker.data()).value<QVariant>(), QVariant::fromValue(QString("Hello from the module"))); qApp->processEvents(); } @@ -141,15 +141,15 @@ void tst_QQuickWorkerScript::messaging_data() QTest::addColumn<QVariant>("value"); QTest::newRow("invalid") << QVariant(); - QTest::newRow("bool") << qVariantFromValue(true); - QTest::newRow("int") << qVariantFromValue(1001); - QTest::newRow("real") << qVariantFromValue(10334.375); - QTest::newRow("string") << qVariantFromValue(QString("More cheeeese, Gromit!")); - QTest::newRow("variant list") << qVariantFromValue((QVariantList() << "a" << "b" << "c")); - QTest::newRow("date time") << qVariantFromValue(QDateTime::currentDateTime()); - QTest::newRow("regexp") << qVariantFromValue(QRegExp("^\\d\\d?$", Qt::CaseInsensitive, + QTest::newRow("bool") << QVariant::fromValue(true); + QTest::newRow("int") << QVariant::fromValue(1001); + QTest::newRow("real") << QVariant::fromValue(10334.375); + QTest::newRow("string") << QVariant::fromValue(QString("More cheeeese, Gromit!")); + QTest::newRow("variant list") << QVariant::fromValue((QVariantList() << "a" << "b" << "c")); + QTest::newRow("date time") << QVariant::fromValue(QDateTime::currentDateTime()); + QTest::newRow("regexp") << QVariant::fromValue(QRegExp("^\\d\\d?$", Qt::CaseInsensitive, QRegExp::RegExp2)); - QTest::newRow("regularexpression") << qVariantFromValue(QRegularExpression( + QTest::newRow("regularexpression") << QVariant::fromValue(QRegularExpression( "^\\d\\d?$", QRegularExpression::CaseInsensitiveOption)); } @@ -165,9 +165,9 @@ void tst_QQuickWorkerScript::messaging_sendQObjectList() QVariantList objects; for (int i=0; i<3; i++) - objects << qVariantFromValue(new QObject(this)); + objects << QVariant::fromValue(new QObject(this)); - QVERIFY(QMetaObject::invokeMethod(worker, "testSend", Q_ARG(QVariant, qVariantFromValue(objects)))); + QVERIFY(QMetaObject::invokeMethod(worker, "testSend", Q_ARG(QVariant, QVariant::fromValue(objects)))); waitForEchoMessage(worker); const QMetaObject *mo = worker->metaObject(); @@ -193,10 +193,10 @@ void tst_QQuickWorkerScript::messaging_sendJsObject() map.insert("name", "zyz"); map.insert("spell power", 3101); - QVERIFY(QMetaObject::invokeMethod(worker, "testSend", Q_ARG(QVariant, qVariantFromValue(map)))); + QVERIFY(QMetaObject::invokeMethod(worker, "testSend", Q_ARG(QVariant, QVariant::fromValue(map)))); waitForEchoMessage(worker); - QVariant result = qVariantFromValue(false); + QVariant result = QVariant::fromValue(false); QVERIFY(QMetaObject::invokeMethod(worker, "compareLiteralResponse", Qt::DirectConnection, Q_RETURN_ARG(QVariant, result), Q_ARG(QVariant, jsObject))); QVERIFY(result.toBool()); diff --git a/tests/auto/qml/qv4assembler/tst_qv4assembler.cpp b/tests/auto/qml/qv4assembler/tst_qv4assembler.cpp index 4916cb4cc0..fd50ff5020 100644 --- a/tests/auto/qml/qv4assembler/tst_qv4assembler.cpp +++ b/tests/auto/qml/qv4assembler/tst_qv4assembler.cpp @@ -34,6 +34,8 @@ #include <QtQml/qqml.h> #include <QtQml/qqmlapplicationengine.h> +#include <private/qv4global_p.h> + #ifdef Q_OS_WIN #include <windows.h> #endif @@ -46,6 +48,7 @@ private slots: void initTestCase() override; void perfMapFile(); void functionTable(); + void jitEnabled(); }; void tst_QV4Assembler::initTestCase() @@ -137,6 +140,26 @@ void tst_QV4Assembler::functionTable() #endif } +#ifdef V4_ENABLE_JIT +#define JIT_ENABLED 1 +#else +#define JIT_ENABLED 0 +#endif + +void tst_QV4Assembler::jitEnabled() +{ +#if defined(Q_OS_IOS) || defined(Q_OS_TVOS) + /* JIT should be disabled on iOS and tvOS. */ + QCOMPARE(JIT_ENABLED, 0); +#elif defined(Q_OS_WIN) && defined(Q_PROCESSOR_ARM) + /* JIT should be disabled Windows on ARM/ARM64 for now. */ + QCOMPARE(JIT_ENABLED, 0); +#else + /* JIT should be enabled on all other architectures/OSes tested in CI. */ + QCOMPARE(JIT_ENABLED, 1); +#endif +} + QTEST_MAIN(tst_QV4Assembler) #include "tst_qv4assembler.moc" diff --git a/tests/auto/qml/qv4identifiertable/tst_qv4identifiertable.cpp b/tests/auto/qml/qv4identifiertable/tst_qv4identifiertable.cpp index 095943cdc7..308fba9049 100644 --- a/tests/auto/qml/qv4identifiertable/tst_qv4identifiertable.cpp +++ b/tests/auto/qml/qv4identifiertable/tst_qv4identifiertable.cpp @@ -67,8 +67,8 @@ void tst_qv4identifiertable::sweepFirstEntryInBucket() table.asPropertyKey(entry2); table.asPropertyKey(entry3); - QCOMPARE(table.size, 3); - QCOMPARE(table.alloc, 5); + QCOMPARE(table.size, 3u); + QCOMPARE(table.alloc, 5u); QCOMPARE(table.entriesByHash[0], entry1); QCOMPARE(table.entriesByHash[1], entry2); diff --git a/tests/auto/qml/qv4mm/tst_qv4mm.cpp b/tests/auto/qml/qv4mm/tst_qv4mm.cpp index 578a47d5fa..1e34b79954 100644 --- a/tests/auto/qml/qv4mm/tst_qv4mm.cpp +++ b/tests/auto/qml/qv4mm/tst_qv4mm.cpp @@ -33,6 +33,7 @@ #include <private/qv4mm_p.h> #include <private/qv4qobjectwrapper_p.h> +#include <private/qjsvalue_p.h> #include "../../shared/util.h" @@ -46,6 +47,7 @@ private slots: void gcStats(); void multiWrappedQObjects(); void accessParentOnDestruction(); + void clearICParent(); }; void tst_qv4mm::gcStats() @@ -108,6 +110,44 @@ void tst_qv4mm::accessParentOnDestruction() QCOMPARE(obj->property("destructions").toInt(), 100); } +void tst_qv4mm::clearICParent() +{ + QV4::ExecutionEngine engine; + QV4::Scope scope(engine.rootContext()); + QV4::ScopedObject object(scope, engine.newObject()); + + // Keep identifiers in a separate array so that we don't have to allocate them in the loop that + // should test the GC on InternalClass allocations. + QV4::ScopedArrayObject identifiers(scope, engine.newArrayObject()); + for (uint i = 0; i < 16 * 1024; ++i) { + QV4::Scope scope(&engine); + QV4::ScopedString s(scope); + s = engine.newIdentifier(QString::fromLatin1("key%1").arg(i)); + identifiers->push_back(s); + + QV4::ScopedValue v(scope); + v->setDouble(i); + object->insertMember(s, v); + } + + // When allocating the InternalClass objects required for deleting properties, the GC should + // eventually run and remove all but the last two. + // If we ever manage to avoid allocating the InternalClasses in the first place we will need + // to change this test. + for (uint i = 0; i < 16 * 1024; ++i) { + QV4::Scope scope(&engine); + QV4::ScopedString s(scope, identifiers->getIndexed(i)); + QV4::Scoped<QV4::InternalClass> ic(scope, object->internalClass()); + QVERIFY(ic->d()->parent != nullptr); + object->deleteProperty(s->toPropertyKey()); + QVERIFY(object->internalClass() != ic->d()); + QCOMPARE(object->internalClass()->parent, ic->d()); + if (ic->d()->parent == nullptr) + return; + } + QFAIL("Garbage collector was not triggered by large amount of InternalClasses"); +} + QTEST_MAIN(tst_qv4mm) #include "tst_qv4mm.moc" diff --git a/tests/auto/qmltest/animatedimage/BLACKLIST b/tests/auto/qmltest/animatedimage/BLACKLIST new file mode 100644 index 0000000000..3a5ed393ea --- /dev/null +++ b/tests/auto/qmltest/animatedimage/BLACKLIST @@ -0,0 +1,2 @@ +[AnimatedImage::test_crashRaceCondition_replyFinished] +osx-10.13 diff --git a/tests/auto/quick/pointerhandlers/qquickdraghandler/data/dragMargin.qml b/tests/auto/quick/pointerhandlers/qquickdraghandler/data/dragMargin.qml new file mode 100644 index 0000000000..e5ca681bd5 --- /dev/null +++ b/tests/auto/quick/pointerhandlers/qquickdraghandler/data/dragMargin.qml @@ -0,0 +1,36 @@ +import QtQuick 2.12 + +Rectangle { + color: "#333" + width: 480; height: 480 + + Rectangle { + color: "#112" + width: 100 + height: 100 + x: 50; y: 50 + + DragHandler { + id: dragHandler + margin: 20 + } + + Rectangle { + id: rect + anchors.fill: parent + anchors.margins: -dragHandler.margin + color: "transparent" + border.color: "cyan" + border.width: 2 + radius: 10 + antialiasing: true + + Text { + color: "cyan" + text: "drag this margin area" + font.pixelSize: 10 + anchors.horizontalCenter: parent.horizontalCenter + } + } + } +} diff --git a/tests/auto/quick/pointerhandlers/qquickdraghandler/tst_qquickdraghandler.cpp b/tests/auto/quick/pointerhandlers/qquickdraghandler/tst_qquickdraghandler.cpp index eb210c2112..cc8c567e5c 100644 --- a/tests/auto/quick/pointerhandlers/qquickdraghandler/tst_qquickdraghandler.cpp +++ b/tests/auto/quick/pointerhandlers/qquickdraghandler/tst_qquickdraghandler.cpp @@ -55,6 +55,7 @@ private slots: void defaultPropertyValues(); void touchDrag(); void mouseDrag(); + void dragFromMargin(); void touchDragMulti(); void touchDragMultiSliders_data(); void touchDragMultiSliders(); @@ -251,6 +252,38 @@ void tst_DragHandler::mouseDrag() QCOMPARE(centroidChangedSpy.count(), 5); } +void tst_DragHandler::dragFromMargin() // QTBUG-74966 +{ + const int dragThreshold = QGuiApplication::styleHints()->startDragDistance(); + QScopedPointer<QQuickView> windowPtr; + createView(windowPtr, "dragMargin.qml"); + QQuickView * window = windowPtr.data(); + + QQuickItem *draggableItem = window->rootObject()->childItems().first(); + QVERIFY(draggableItem); + QQuickDragHandler *dragHandler = draggableItem->findChild<QQuickDragHandler*>(); + QVERIFY(dragHandler); + + QPointF originalPos = draggableItem->position(); + QPointF scenePressPos = originalPos - QPointF(10, 0); + QPoint p1 = scenePressPos.toPoint(); + QTest::mousePress(window, Qt::LeftButton, Qt::NoModifier, p1); + QVERIFY(!dragHandler->active()); + QCOMPARE(dragHandler->centroid().scenePosition(), scenePressPos); + QCOMPARE(dragHandler->centroid().scenePressPosition(), scenePressPos); + p1 += QPoint(dragThreshold * 2, 0); + QTest::mouseMove(window, p1); + QTRY_VERIFY(dragHandler->active()); + QCOMPARE(dragHandler->centroid().scenePressPosition(), scenePressPos); + QCOMPARE(dragHandler->centroid().sceneGrabPosition(), p1); + QCOMPARE(dragHandler->translation().x(), 0.0); // hmm that's odd + QCOMPARE(dragHandler->translation().y(), 0.0); + QCOMPARE(draggableItem->position(), originalPos + QPointF(dragThreshold * 2, 0)); + QTest::mouseRelease(window, Qt::LeftButton, Qt::NoModifier, p1); + QTRY_VERIFY(!dragHandler->active()); + QCOMPARE(dragHandler->centroid().pressedButtons(), Qt::NoButton); +} + void tst_DragHandler::touchDragMulti() { const int dragThreshold = QGuiApplication::styleHints()->startDragDistance(); diff --git a/tests/auto/quick/pointerhandlers/qquickhoverhandler/tst_qquickhoverhandler.cpp b/tests/auto/quick/pointerhandlers/qquickhoverhandler/tst_qquickhoverhandler.cpp index f141a2546c..575139f851 100644 --- a/tests/auto/quick/pointerhandlers/qquickhoverhandler/tst_qquickhoverhandler.cpp +++ b/tests/auto/quick/pointerhandlers/qquickhoverhandler/tst_qquickhoverhandler.cpp @@ -252,7 +252,7 @@ void tst_HoverHandler::movingItemWithHoverHandler() QTRY_COMPARE(window->isVisible(), false); QCursor::setPos(paddlePos); window->show(); - QTest::qWaitForWindowExposed(window); + QVERIFY(QTest::qWaitForWindowExposed(window)); QTRY_COMPARE(paddleHH->isHovered(), true); diff --git a/tests/auto/quick/qquickanchors/tst_qquickanchors.cpp b/tests/auto/quick/qquickanchors/tst_qquickanchors.cpp index 77fa1292c4..128a154492 100644 --- a/tests/auto/quick/qquickanchors/tst_qquickanchors.cpp +++ b/tests/auto/quick/qquickanchors/tst_qquickanchors.cpp @@ -364,7 +364,7 @@ void tst_qquickanchors::reset() const QMetaObject *meta = itemPrivate->anchors()->metaObject(); QMetaProperty p = meta->property(meta->indexOfProperty(side.toUtf8().constData())); - QVERIFY(p.write(itemPrivate->anchors(), qVariantFromValue(anchorLine))); + QVERIFY(p.write(itemPrivate->anchors(), QVariant::fromValue(anchorLine))); QCOMPARE(itemPrivate->anchors()->usedAnchors().testFlag(anchor), true); QVERIFY(p.reset(itemPrivate->anchors())); @@ -423,7 +423,7 @@ void tst_qquickanchors::nullItem() QMetaProperty p = meta->property(meta->indexOfProperty(side.toUtf8().constData())); QTest::ignoreMessage(QtWarningMsg, "<Unknown File>: QML Item: Cannot anchor to a null item."); - QVERIFY(p.write(itemPrivate->anchors(), qVariantFromValue(anchor))); + QVERIFY(p.write(itemPrivate->anchors(), QVariant::fromValue(anchor))); delete item; } diff --git a/tests/auto/quick/qquickgridview/tst_qquickgridview.cpp b/tests/auto/quick/qquickgridview/tst_qquickgridview.cpp index 3b704d7fa4..448096720c 100644 --- a/tests/auto/quick/qquickgridview/tst_qquickgridview.cpp +++ b/tests/auto/quick/qquickgridview/tst_qquickgridview.cpp @@ -6637,7 +6637,7 @@ void tst_QQuickGridView::contentHeightWithDelayRemove() QCOMPARE(qRound(gridview->contentHeight()), qRound(initialContentHeight)); QTRY_COMPARE(qRound(gridview->contentHeight()), eventualContentHeight); } else { - QCOMPARE(qRound(gridview->contentHeight()), eventualContentHeight); + QTRY_COMPARE(qRound(gridview->contentHeight()), eventualContentHeight); } delete window; diff --git a/tests/auto/quick/qquickitemlayer/tst_qquickitemlayer.cpp b/tests/auto/quick/qquickitemlayer/tst_qquickitemlayer.cpp index 1a289a2087..2f90632841 100644 --- a/tests/auto/quick/qquickitemlayer/tst_qquickitemlayer.cpp +++ b/tests/auto/quick/qquickitemlayer/tst_qquickitemlayer.cpp @@ -51,9 +51,8 @@ public: view.setSource(testFileUrl(fileName)); view.showNormal(); - QTest::qWaitForWindowExposed(&view); - - return view.grabWindow(); + return QTest::qWaitForWindowExposed(&view) + ? view.grabWindow() : QImage(); } private slots: @@ -153,6 +152,7 @@ void tst_QQuickItemLayer::layerSmooth() QSKIP("Skipping due to grabWindow not functional on offscreen/minimimal platforms"); QImage fb = runTest("Smooth.qml"); + QVERIFY(!fb.size().isEmpty()); QCOMPARE(fb.pixel(0, 0), qRgb(0xff, 0, 0)); QCOMPARE(fb.pixel(fb.width() - 1, 0), qRgb(0, 0, 0xff)); @@ -177,6 +177,7 @@ void tst_QQuickItemLayer::layerEnabled() QSKIP("Skipping due to grabWindow not functional on offscreen/minimimal platforms"); QImage fb = runTest("Enabled.qml"); + QVERIFY(!fb.size().isEmpty()); // Verify the banding QCOMPARE(fb.pixel(0, 0), fb.pixel(0, 1)); // Verify the gradient @@ -212,6 +213,7 @@ void tst_QQuickItemLayer::layerEffect() QSKIP("Skipping due to grabWindow not functional on offscreen/minimimal platforms"); QImage fb = runTest("Effect.qml"); + QVERIFY(!fb.size().isEmpty()); QCOMPARE(fb.pixel(0, 0), qRgb(0xff, 0, 0)); QCOMPARE(fb.pixel(fb.width() - 1, 0), qRgb(0, 0xff, 0)); } @@ -229,6 +231,7 @@ void tst_QQuickItemLayer::layerSourceRect() QSKIP("Only OpenGL Renderer supports GLSL ShaderEffects"); QImage fb = runTest("SourceRect.qml"); + QVERIFY(!fb.size().isEmpty()); // Check that the edges are converted to blue QCOMPARE(fb.pixel(0, 0), qRgb(0, 0, 0xff)); @@ -253,6 +256,7 @@ void tst_QQuickItemLayer::layerIsTextureProvider() QSKIP("Only OpenGL Renderer supports GLSL ShaderEffects"); QImage fb = runTest("TextureProvider.qml"); + QVERIFY(!fb.size().isEmpty()); QCOMPARE(fb.pixel(0, 0), qRgb(0xff, 0, 0)); QCOMPARE(fb.pixel(fb.width() - 1, 0), qRgb(0, 0xff, 0)); } @@ -448,6 +452,7 @@ void tst_QQuickItemLayer::changeSamplerName() QSKIP("Only OpenGL Renderer supports GLSL ShaderEffects"); QImage fb = runTest("SamplerNameChange.qml"); + QVERIFY(!fb.size().isEmpty()); QCOMPARE(fb.pixel(0, 0), qRgb(0, 0, 0xff)); } @@ -459,6 +464,7 @@ void tst_QQuickItemLayer::itemEffect() QSKIP("Only OpenGL Renderer supports GLSL ShaderEffects"); QImage fb = runTest("ItemEffect.qml"); + QVERIFY(!fb.size().isEmpty()); QCOMPARE(fb.pixel(0, 0), qRgb(0xff, 0, 0)); QCOMPARE(fb.pixel(199, 0), qRgb(0xff, 0, 0)); QCOMPARE(fb.pixel(0, 199), qRgb(0, 0, 0xff)); @@ -472,6 +478,7 @@ void tst_QQuickItemLayer::rectangleEffect() QSKIP("Skipping due to grabWindow not functional on offscreen/minimimal platforms"); QImage fb = runTest("RectangleEffect.qml"); + QVERIFY(!fb.size().isEmpty()); QCOMPARE(fb.pixel(0, 0), qRgb(0, 0xff, 0)); QCOMPARE(fb.pixel(199, 0), qRgb(0, 0xff, 0)); QCOMPARE(fb.pixel(0, 199), qRgb(0, 0xff, 0)); diff --git a/tests/auto/quick/qquicklistview/BLACKLIST b/tests/auto/quick/qquicklistview/BLACKLIST index e22d52294f..893f95dcea 100644 --- a/tests/auto/quick/qquicklistview/BLACKLIST +++ b/tests/auto/quick/qquicklistview/BLACKLIST @@ -1,6 +1,11 @@ [enforceRange_withoutHighlight] osx +opensuse-42.3 +opensuse-leap #QTBUG-53863 [populateTransitions] opensuse-42.1 #QTBUG-65964 + +[contentHeightWithDelayRemove] +osx-10.12 diff --git a/tests/auto/quick/qquicklistview/data/delegateWithMouseArea.qml b/tests/auto/quick/qquicklistview/data/delegateWithMouseArea.qml new file mode 100644 index 0000000000..e0b8222bfb --- /dev/null +++ b/tests/auto/quick/qquicklistview/data/delegateWithMouseArea.qml @@ -0,0 +1,29 @@ +import QtQuick 2.12 + +ListView { + id: root + objectName: "view" + width: 600 + height: 600 + model: 3 + snapMode: ListView.SnapOneItem + boundsBehavior: Flickable.StopAtBounds + highlightRangeMode: ListView.StrictlyEnforceRange + preferredHighlightBegin: 0 + preferredHighlightEnd: 0 + highlightMoveDuration: 100 + delegate: Rectangle { + id: delegateRect + width: 500 + height: 500 + color: Qt.rgba(Math.random(), Math.random(), Math.random(), 1) + Text { + text: index + font.pixelSize: 128 + anchors.centerIn: parent + } + MouseArea { + anchors.fill: parent + } + } +} diff --git a/tests/auto/quick/qquicklistview/tst_qquicklistview.cpp b/tests/auto/quick/qquicklistview/tst_qquicklistview.cpp index d96590bdae..2ea8a477a8 100644 --- a/tests/auto/quick/qquicklistview/tst_qquicklistview.cpp +++ b/tests/auto/quick/qquicklistview/tst_qquicklistview.cpp @@ -38,6 +38,7 @@ #include <QtQml/qqmlincubator.h> #include <QtQuick/private/qquickitemview_p_p.h> #include <QtQuick/private/qquicklistview_p.h> +#include <QtQuick/private/qquickmousearea_p.h> #include <QtQuick/private/qquicktext_p.h> #include <QtQml/private/qqmlobjectmodel_p.h> #include <QtQml/private/qqmllistmodel_p.h> @@ -275,6 +276,7 @@ private slots: void addOnCompleted(); void setPositionOnLayout(); + void touchCancel(); private: template <class T> void items(const QUrl &source); @@ -330,6 +332,7 @@ private: QQuickView *m_view; QString testForView; + QTouchDevice *touchDevice = QTest::createTouchDevice(); }; class TestObject : public QObject @@ -8968,6 +8971,37 @@ void tst_QQuickListView::useDelegateChooserWithoutDefault() window->show(); }; +void tst_QQuickListView::touchCancel() // QTBUG-74679 +{ + QScopedPointer<QQuickView> window(createView()); + window->setSource(testFileUrl("delegateWithMouseArea.qml")); + window->show(); + QVERIFY(QTest::qWaitForWindowExposed(window.data())); + + QQuickListView *listview = qobject_cast<QQuickListView *>(window->rootObject()); + QVERIFY(listview); + QQuickMouseArea *mouseArea = listview->currentItem()->findChild<QQuickMouseArea *>(); + QVERIFY(mouseArea); + + QPoint p1(300, 300); + QTest::touchEvent(window.data(), touchDevice).press(0, p1, window.data()); + QQuickTouchUtils::flush(window.data()); + QTRY_VERIFY(mouseArea->pressed()); + // and because Flickable filtered it, QQuickFlickablePrivate::pressed + // should be true, but it's not easily tested here + + QTouchEvent cancelEvent(QEvent::TouchCancel); + cancelEvent.setDevice(touchDevice); + QCoreApplication::sendEvent(window.data(), &cancelEvent); + // now QQuickWindowPrivate::sendUngrabEvent() will be called, Flickable will filter it, + // QQuickFlickablePrivate::pressed will be set to false, and that will allow setCurrentIndex() to make it move + QQuickTouchUtils::flush(window.data()); + + listview->setCurrentIndex(1); + // ensure that it actually moves (animates) to the second delegate + QTRY_COMPARE(listview->contentY(), 500.0); +} + QTEST_MAIN(tst_QQuickListView) #include "tst_qquicklistview.moc" diff --git a/tests/auto/quick/qquickmultipointtoucharea/BLACKLIST b/tests/auto/quick/qquickmultipointtoucharea/BLACKLIST index cdb3e7733b..6af00ab76f 100644 --- a/tests/auto/quick/qquickmultipointtoucharea/BLACKLIST +++ b/tests/auto/quick/qquickmultipointtoucharea/BLACKLIST @@ -1,6 +1,12 @@ [nonOverlapping] ubuntu-16.04 ubuntu-18.04 +opensuse-42.3 +opensuse-leap +sles [nested] ubuntu-16.04 ubuntu-18.04 +opensuse-42.3 +opensuse-leap +sles diff --git a/tests/auto/quick/qquickmultipointtoucharea/tst_qquickmultipointtoucharea.cpp b/tests/auto/quick/qquickmultipointtoucharea/tst_qquickmultipointtoucharea.cpp index d4ad282701..cd66fc4ede 100644 --- a/tests/auto/quick/qquickmultipointtoucharea/tst_qquickmultipointtoucharea.cpp +++ b/tests/auto/quick/qquickmultipointtoucharea/tst_qquickmultipointtoucharea.cpp @@ -1145,16 +1145,18 @@ void tst_QQuickMultiPointTouchArea::transformedTouchArea() QQuickView *tst_QQuickMultiPointTouchArea::createAndShowView(const QString &file) { - QQuickView *window = new QQuickView(nullptr); + QScopedPointer<QQuickView> window(new QQuickView(nullptr)); window->setSource(testFileUrl(file)); + if (window->status() != QQuickView::Ready) + return nullptr; const QRect screenGeometry = window->screen()->availableGeometry(); const QSize size = window->size(); const QPoint offset = QPoint(size.width() / 2, size.height() / 2); window->setFramePosition(screenGeometry.center() - offset); window->show(); - QTest::qWaitForWindowExposed(window); - - return window; + if (!QTest::qWaitForWindowExposed(window.data())) + return nullptr; + return window.take(); } void tst_QQuickMultiPointTouchArea::mouseInteraction_data() diff --git a/tests/auto/quick/qquickpathview/data/pathview5.qml b/tests/auto/quick/qquickpathview/data/pathview5.qml new file mode 100644 index 0000000000..479c5dc500 --- /dev/null +++ b/tests/auto/quick/qquickpathview/data/pathview5.qml @@ -0,0 +1,65 @@ +import QtQuick 2.0 + +PathView { + property int countclick: 0 + id: pathview + y: 0 + width: 348 + height: 480 + + interactive: false + + cacheItemCount: 10 + currentIndex: 2 + pathItemCount: 4 + highlightMoveDuration: 1000 + highlightRangeMode : PathView.StrictlyEnforceRange + preferredHighlightBegin: 0.5 + preferredHighlightEnd: 0.5 + snapMode : PathView.SnapOneItem + + path: Path { + id: leftPath + startX: pathview.width / 2 - 800 + startY: pathview.height / 2 - 800 + + PathArc { + x: pathview.width / 2 - 800 + y: pathview.height / 2 + 800 + radiusX: 800 + radiusY: 800 + direction: PathArc.Clockwise + } + } + + model: ListModel { + id: model + ListElement { objectName:"aqua"; name: "aqua" ;mycolor:"aqua"} + ListElement { objectName:"blue"; name: "blue" ;mycolor:"blue"} + ListElement { objectName:"blueviolet"; name: "blueviolet" ;mycolor:"blueviolet"} + ListElement { objectName:"brown"; name: "brown" ;mycolor:"brown"} + ListElement { objectName:"chartreuse"; name: "chartreuse" ;mycolor:"chartreuse"} + } + + delegate: Item { + id: revolveritem + objectName: model.objectName + + width: pathview.width + height: pathview.height + + Rectangle + { + id:myRectangle + color: mycolor + width: pathview.width -20 + height: pathview.height -20 + + Text { + anchors.centerIn: parent + text: "index:"+index + color: "white" + } + } + } +} diff --git a/tests/auto/quick/qquickpathview/tst_qquickpathview.cpp b/tests/auto/quick/qquickpathview/tst_qquickpathview.cpp index bf38d2d926..1a5ce39318 100644 --- a/tests/auto/quick/qquickpathview/tst_qquickpathview.cpp +++ b/tests/auto/quick/qquickpathview/tst_qquickpathview.cpp @@ -104,6 +104,7 @@ private slots: void offset_data(); void offset(); void setCurrentIndex(); + void setCurrentIndexWrap(); void resetModel(); void propertyChanges(); void pathChanges(); @@ -1138,6 +1139,28 @@ void tst_QQuickPathView::setCurrentIndex() QCOMPARE(currentIndexSpy.count(), 1); } +void tst_QQuickPathView::setCurrentIndexWrap() +{ + QScopedPointer<QQuickView> window(createView()); + window->setSource(testFileUrl("pathview5.qml")); + window->show(); + qApp->processEvents(); + + QQuickPathView *pathview = qobject_cast<QQuickPathView*>(window->rootObject()); + QVERIFY(pathview); + + // set current index to last item + pathview->setCurrentIndex(4); + // set currentIndex to first item, then quickly set it back (QTBUG-74508) + QSignalSpy currentIndexSpy(pathview, SIGNAL(currentIndexChanged())); + QSignalSpy movementStartedSpy(pathview, SIGNAL(movementStarted())); + pathview->setCurrentIndex(0); + pathview->setCurrentIndex(4); + QCOMPARE(pathview->currentIndex(), 4); + QCOMPARE(currentIndexSpy.count(), 2); + QCOMPARE(movementStartedSpy.count(), 0); +} + void tst_QQuickPathView::resetModel() { QScopedPointer<QQuickView> window(createView()); diff --git a/tests/auto/quick/qquickrectangle/tst_qquickrectangle.cpp b/tests/auto/quick/qquickrectangle/tst_qquickrectangle.cpp index f6ca999cf5..710caaa734 100644 --- a/tests/auto/quick/qquickrectangle/tst_qquickrectangle.cpp +++ b/tests/auto/quick/qquickrectangle/tst_qquickrectangle.cpp @@ -134,14 +134,12 @@ void tst_qquickrectangle::gradient_separate() // Start off clean QQuickItemPrivate *rectPriv = QQuickItemPrivate::get(rect); - bool isDirty = rectPriv->dirtyAttributes & QQuickItemPrivate::Content; - QVERIFY(!isDirty); + QTRY_COMPARE(rectPriv->dirtyAttributes & QQuickItemPrivate::Content, 0u); QMetaObject::invokeMethod(rect, "changeGradient"); // Changing the gradient should have scheduled an update of the item. - isDirty = rectPriv->dirtyAttributes & QQuickItemPrivate::Content; - QVERIFY(isDirty); + QVERIFY((rectPriv->dirtyAttributes & QQuickItemPrivate::Content) != 0); } // When a gradient is changed, every Rectangle connected to it must update. @@ -161,17 +159,15 @@ void tst_qquickrectangle::gradient_multiple() // Start off clean QQuickItemPrivate *firstRectPriv = QQuickItemPrivate::get(firstRect); QQuickItemPrivate *secondRectPriv = QQuickItemPrivate::get(secondRect); - bool firstIsDirty = firstRectPriv->dirtyAttributes & QQuickItemPrivate::Content; + QTRY_VERIFY(!(firstRectPriv->dirtyAttributes & QQuickItemPrivate::Content)); bool secondIsDirty = secondRectPriv->dirtyAttributes & QQuickItemPrivate::Content; - QVERIFY(!firstIsDirty); QVERIFY(!secondIsDirty); QMetaObject::invokeMethod(view.rootObject(), "changeGradient"); // Changing the gradient should have scheduled an update of both items - firstIsDirty = firstRectPriv->dirtyAttributes & QQuickItemPrivate::Content; + QTRY_VERIFY(firstRectPriv->dirtyAttributes & QQuickItemPrivate::Content); secondIsDirty = secondRectPriv->dirtyAttributes & QQuickItemPrivate::Content; - QVERIFY(firstIsDirty); QVERIFY(secondIsDirty); } diff --git a/tests/auto/quick/qquickrepeater/tst_qquickrepeater.cpp b/tests/auto/quick/qquickrepeater/tst_qquickrepeater.cpp index e4b427f6ec..f19f5f9877 100644 --- a/tests/auto/quick/qquickrepeater/tst_qquickrepeater.cpp +++ b/tests/auto/quick/qquickrepeater/tst_qquickrepeater.cpp @@ -899,15 +899,15 @@ void tst_QQuickRepeater::destroyCount() QQuickRepeater *repeater = findItem<QQuickRepeater>(rootObject, "repeater"); QVERIFY(repeater); - repeater->setProperty("model", qVariantFromValue<int>(3)); + repeater->setProperty("model", QVariant::fromValue<int>(3)); QCOMPARE(repeater->property("componentCount").toInt(), 3); - repeater->setProperty("model", qVariantFromValue<int>(0)); + repeater->setProperty("model", QVariant::fromValue<int>(0)); QCOMPARE(repeater->property("componentCount").toInt(), 0); - repeater->setProperty("model", qVariantFromValue<int>(4)); + repeater->setProperty("model", QVariant::fromValue<int>(4)); QCOMPARE(repeater->property("componentCount").toInt(), 4); QStringListModel model; - repeater->setProperty("model", qVariantFromValue<QStringListModel *>(&model)); + repeater->setProperty("model", QVariant::fromValue<QStringListModel *>(&model)); QCOMPARE(repeater->property("componentCount").toInt(), 0); QStringList list; list << "1" << "2" << "3" << "4"; @@ -915,7 +915,7 @@ void tst_QQuickRepeater::destroyCount() QCOMPARE(repeater->property("componentCount").toInt(), 4); model.insertRows(2,1); QModelIndex index = model.index(2); - model.setData(index, qVariantFromValue<QString>(QStringLiteral("foobar"))); + model.setData(index, QVariant::fromValue<QString>(QStringLiteral("foobar"))); QCOMPARE(repeater->property("componentCount").toInt(), 5); model.removeRows(2,1); diff --git a/tests/auto/quick/qquicktableview/tst_qquicktableview.cpp b/tests/auto/quick/qquicktableview/tst_qquicktableview.cpp index 60d48bb59f..420a9fdb13 100644 --- a/tests/auto/quick/qquicktableview/tst_qquicktableview.cpp +++ b/tests/auto/quick/qquicktableview/tst_qquicktableview.cpp @@ -601,8 +601,7 @@ void tst_QQuickTableView::checkContentWidthAndHeight() // Since we move the viewport more than a page, tableview // will jump to the new position and do a rebuild. - QVERIFY(tableViewPrivate->polishScheduled); - QVERIFY(tableViewPrivate->rebuildScheduled); + QVERIFY(tableViewPrivate->scheduledRebuildOptions); WAIT_UNTIL_POLISHED; // Check that the average cell size is now matching the @@ -654,7 +653,7 @@ void tst_QQuickTableView::checkContentWidthAndHeight() // Since we move the viewport more than a page, tableview // will jump to the new position and do a rebuild. QVERIFY(tableViewPrivate->polishScheduled); - QVERIFY(tableViewPrivate->rebuildScheduled); + QVERIFY(tableViewPrivate->scheduledRebuildOptions); WAIT_UNTIL_POLISHED; // We should now have the same content width/height as when we started @@ -689,7 +688,6 @@ void tst_QQuickTableView::checkPageFlicking() QCOMPARE(tableViewPrivate->averageEdgeSize.width(), cellWidth); QCOMPARE(tableViewPrivate->averageEdgeSize.height(), cellHeight); - QVERIFY(!tableViewPrivate->rebuildScheduled); QCOMPARE(tableViewPrivate->scheduledRebuildOptions, QQuickTableViewPrivate::RebuildOption::None); // Flick 5000 columns to the right, and check that this triggers a @@ -699,7 +697,6 @@ void tst_QQuickTableView::checkPageFlicking() const qreal flickToColumnInPixels = ((cellWidth + columnSpacing) * flickToColumn) - columnSpacing; tableView->setContentX(flickToColumnInPixels); - QVERIFY(tableViewPrivate->rebuildScheduled); QVERIFY(tableViewPrivate->scheduledRebuildOptions & QQuickTableViewPrivate::RebuildOption::ViewportOnly); QVERIFY(tableViewPrivate->scheduledRebuildOptions & QQuickTableViewPrivate::RebuildOption::CalculateNewTopLeftColumn); QVERIFY(!(tableViewPrivate->scheduledRebuildOptions & QQuickTableViewPrivate::RebuildOption::CalculateNewTopLeftRow)); @@ -721,7 +718,6 @@ void tst_QQuickTableView::checkPageFlicking() const qreal flickToRowInPixels = ((cellHeight + rowSpacing) * flickToRow) - rowSpacing; tableView->setContentY(flickToRowInPixels); - QVERIFY(tableViewPrivate->rebuildScheduled); QVERIFY(tableViewPrivate->scheduledRebuildOptions & QQuickTableViewPrivate::RebuildOption::ViewportOnly); QVERIFY(!(tableViewPrivate->scheduledRebuildOptions & QQuickTableViewPrivate::RebuildOption::CalculateNewTopLeftColumn)); QVERIFY(tableViewPrivate->scheduledRebuildOptions & QQuickTableViewPrivate::RebuildOption::CalculateNewTopLeftRow); @@ -1942,7 +1938,7 @@ void tst_QQuickTableView::checkChangingModelFromDelegate() // And since the QML code tried to add another row as well, we // expect rebuildScheduled to be true, and a polish event to be pending. - QCOMPARE(tableViewPrivate->rebuildScheduled, true); + QVERIFY(tableViewPrivate->scheduledRebuildOptions); QCOMPARE(tableViewPrivate->polishScheduled, true); WAIT_UNTIL_POLISHED; @@ -2025,7 +2021,7 @@ void tst_QQuickTableView::checkTableviewInsideAsyncLoader() QCOMPARE(loader->status(), QQuickLoader::Ready); // Check that TableView has finished building - QCOMPARE(tableViewPrivate->rebuildScheduled, false); + QVERIFY(!tableViewPrivate->scheduledRebuildOptions); QCOMPARE(tableViewPrivate->rebuildState, QQuickTableViewPrivate::RebuildState::Done); // Check that all expected delegate items have been loaded diff --git a/tests/auto/quick/qquickwindow/tst_qquickwindow.cpp b/tests/auto/quick/qquickwindow/tst_qquickwindow.cpp index a862604fc1..4cf7fa7119 100644 --- a/tests/auto/quick/qquickwindow/tst_qquickwindow.cpp +++ b/tests/auto/quick/qquickwindow/tst_qquickwindow.cpp @@ -1645,11 +1645,11 @@ void tst_qquickwindow::focusReason() window->setTitle(QTest::currentTestFunction()); QVERIFY(QTest::qWaitForWindowExposed(window)); - QQuickItem *firstItem = new QQuickItem; + QScopedPointer<QQuickItem> firstItem(new QQuickItem); firstItem->setSize(QSizeF(100, 100)); firstItem->setParentItem(window->contentItem()); - QQuickItem *secondItem = new QQuickItem; + QScopedPointer<QQuickItem> secondItem(new QQuickItem); secondItem->setSize(QSizeF(100, 100)); secondItem->setParentItem(window->contentItem()); @@ -1673,7 +1673,7 @@ void tst_qquickwindow::ignoreUnhandledMouseEvents() window->show(); QVERIFY(QTest::qWaitForWindowExposed(window)); - QQuickItem *item = new QQuickItem; + QScopedPointer<QQuickItem> item(new QQuickItem); item->setSize(QSizeF(100, 100)); item->setParentItem(window->contentItem()); @@ -1883,8 +1883,8 @@ void tst_qquickwindow::hideThenDelete() QFETCH(bool, persistentSG); QFETCH(bool, persistentGL); - QSignalSpy *openglDestroyed = nullptr; - QSignalSpy *sgInvalidated = nullptr; + QScopedPointer<QSignalSpy> openglDestroyed; + QScopedPointer<QSignalSpy> sgInvalidated; { QQuickWindow window; @@ -1903,10 +1903,10 @@ void tst_qquickwindow::hideThenDelete() const bool isGL = window.rendererInterface()->graphicsApi() == QSGRendererInterface::OpenGL; #if QT_CONFIG(opengl) if (isGL) - openglDestroyed = new QSignalSpy(window.openglContext(), SIGNAL(aboutToBeDestroyed())); + openglDestroyed.reset(new QSignalSpy(window.openglContext(), SIGNAL(aboutToBeDestroyed()))); #endif - sgInvalidated = new QSignalSpy(&window, SIGNAL(sceneGraphInvalidated())); + sgInvalidated.reset(new QSignalSpy(&window, SIGNAL(sceneGraphInvalidated()))); window.hide(); @@ -1951,7 +1951,7 @@ void tst_qquickwindow::showHideAnimate() QQmlEngine engine; QQmlComponent component(&engine); component.loadUrl(testFileUrl("showHideAnimate.qml")); - QQuickItem* created = qobject_cast<QQuickItem *>(component.create()); + QScopedPointer<QQuickItem> created(qobject_cast<QQuickItem *>(component.create())); QVERIFY(created); @@ -2293,7 +2293,7 @@ void tst_qquickwindow::contentItemSize() QQmlEngine engine; QQmlComponent component(&engine); component.setData(QByteArray("import QtQuick 2.1\n Rectangle { anchors.fill: parent }"), QUrl()); - QQuickItem *rect = qobject_cast<QQuickItem *>(component.create()); + QScopedPointer<QQuickItem> rect(qobject_cast<QQuickItem *>(component.create())); QVERIFY(rect); rect->setParentItem(window.contentItem()); QCOMPARE(QSizeF(rect->width(), rect->height()), size); diff --git a/tests/auto/quick/touchmouse/BLACKLIST b/tests/auto/quick/touchmouse/BLACKLIST index b2ba52eca9..0dfe28087a 100644 --- a/tests/auto/quick/touchmouse/BLACKLIST +++ b/tests/auto/quick/touchmouse/BLACKLIST @@ -1,2 +1,6 @@ [buttonOnDelayedPressFlickable] windows gcc developer-build + +# QTBUG-74517 +[buttonOnFlickable] +windows gcc developer-build diff --git a/tests/auto/quicktest/quicktestmainwithsetup/data/tst_setup.qml b/tests/auto/quicktest/quicktestmainwithsetup/data/tst_setup.qml index 0f5466998a..ea6b3e014b 100644 --- a/tests/auto/quicktest/quicktestmainwithsetup/data/tst_setup.qml +++ b/tests/auto/quicktest/quicktestmainwithsetup/data/tst_setup.qml @@ -29,9 +29,15 @@ import QtQuick 2.0 import QtTest 1.2 +import QmlRegisterTypeCppModule 1.0 +import ImportPathQmlModule 1.0 + TestCase { name: "setup" + QmlRegisterTypeCppType {} + ImportPathQmlType {} + function initTestCase() { verify(qmlEngineAvailableCalled) diff --git a/tests/auto/quicktest/quicktestmainwithsetup/imports/ImportPathQmlModule/ImportPathQmlType.qml b/tests/auto/quicktest/quicktestmainwithsetup/imports/ImportPathQmlModule/ImportPathQmlType.qml new file mode 100644 index 0000000000..617bdaaf67 --- /dev/null +++ b/tests/auto/quicktest/quicktestmainwithsetup/imports/ImportPathQmlModule/ImportPathQmlType.qml @@ -0,0 +1,3 @@ +import QtQuick 2.0 + +Item {} diff --git a/tests/auto/quicktest/quicktestmainwithsetup/imports/ImportPathQmlModule/qmldir b/tests/auto/quicktest/quicktestmainwithsetup/imports/ImportPathQmlModule/qmldir new file mode 100644 index 0000000000..dea7c9a8a4 --- /dev/null +++ b/tests/auto/quicktest/quicktestmainwithsetup/imports/ImportPathQmlModule/qmldir @@ -0,0 +1,2 @@ +module ImportPathQmlModule +ImportPathQmlType 1.0 ImportPathQmlType.qml diff --git a/tests/auto/quicktest/quicktestmainwithsetup/tst_quicktestmainwithsetup.cpp b/tests/auto/quicktest/quicktestmainwithsetup/tst_quicktestmainwithsetup.cpp index b0545d1a95..b5deeceac4 100644 --- a/tests/auto/quicktest/quicktestmainwithsetup/tst_quicktestmainwithsetup.cpp +++ b/tests/auto/quicktest/quicktestmainwithsetup/tst_quicktestmainwithsetup.cpp @@ -35,6 +35,14 @@ #include "../../shared/util.h" +class QmlRegisterTypeCppType : public QObject +{ + Q_OBJECT + +public: + QmlRegisterTypeCppType() {} +}; + class CustomTestSetup : public QObject { Q_OBJECT @@ -45,6 +53,12 @@ public: public slots: void qmlEngineAvailable(QQmlEngine *qmlEngine) { + // Test that modules are successfully imported by the TestCaseCollector that + // parses the QML files (but doesn't run them). For that to happen, qmlEngineAvailable() + // must be called before TestCaseCollector does its thing. + qmlRegisterType<QmlRegisterTypeCppType>("QmlRegisterTypeCppModule", 1, 0, "QmlRegisterTypeCppType"); + qmlEngine->addImportPath(QString::fromUtf8(QT_QMLTEST_DATADIR) + "/../imports"); + qmlEngine->rootContext()->setContextProperty("qmlEngineAvailableCalled", true); } }; diff --git a/tests/auto/quickwidgets/qquickwidget/tst_qquickwidget.cpp b/tests/auto/quickwidgets/qquickwidget/tst_qquickwidget.cpp index aaf37b32cd..fd5c3653ad 100644 --- a/tests/auto/quickwidgets/qquickwidget/tst_qquickwidget.cpp +++ b/tests/auto/quickwidgets/qquickwidget/tst_qquickwidget.cpp @@ -161,7 +161,7 @@ void tst_qquickwidget::showHide() window.show(); QVERIFY(QTest::qWaitForWindowExposed(&window)); - QVERIFY(childView->quickWindow()->isVisible()); + QVERIFY(!childView->quickWindow()->isVisible()); // this window is always not visible see QTBUG-65761 QVERIFY(childView->quickWindow()->visibility() != QWindow::Hidden); window.hide(); @@ -612,7 +612,7 @@ void tst_qquickwidget::synthMouseFromTouch() childView->resize(300, 300); window.show(); QVERIFY(QTest::qWaitForWindowActive(&window)); - QVERIFY(childView->quickWindow()->isVisible()); + QVERIFY(!childView->quickWindow()->isVisible()); // this window is always not visible see QTBUG-65761 QVERIFY(item->isVisible()); QPoint p1 = QPoint(20, 20); diff --git a/tests/manual/scenegraph_lancelot/data/text/text_wrap_elide_maxlines.qml b/tests/manual/scenegraph_lancelot/data/text/text_wrap_elide_maxlines.qml new file mode 100644 index 0000000000..927f2b3148 --- /dev/null +++ b/tests/manual/scenegraph_lancelot/data/text/text_wrap_elide_maxlines.qml @@ -0,0 +1,133 @@ +import QtQuick 2.0 + +//test wrapping and elision when maximumLineCount is set + +Item { + width: 320 + height: 480 + Rectangle { + id: text_area + color: "light yellow" + x: 50 + y: 0 + height: parent.height + width: 150 + } + Text { + id: text_0000 + wrapMode: Text.WrapAnywhere + text: "The quick brown fox jumps over the lazy dog." + x: text_area.x + y: text_area.y + width: text_area.width + maximumLineCount: 2 + elide: Text.ElideRight + color: "red" + font.family: "Arial" + font.pixelSize: 22 + } + Text { + id: text_0001 + wrapMode: Text.Wrap + text: text_0000.text + anchors.top: text_0000.bottom + anchors.left: text_0000.left + width: text_0000.width + maximumLineCount: text_0000.maximumLineCount + elide: Text.ElideRight + color: "blue" + font.family: text_0000.font.family + font.pixelSize: text_0000.font.pixelSize + } + Text { + id: text_0002 + wrapMode: Text.WordWrap + text: text_0000.text + anchors.top: text_0001.bottom + anchors.left: text_0000.left + width: text_0000.width + maximumLineCount: text_0000.maximumLineCount + elide: Text.ElideRight + color: "green" + font.family: text_0000.font.family + font.pixelSize: text_0000.font.pixelSize + } + Text { + id: text_0003 + wrapMode: Text.WrapAnywhere + text: "ABCDEFGHIJKL 1234567890123" + anchors.top: text_0002.bottom + anchors.left: text_0000.left + width: 150 + maximumLineCount: 2 + elide: Text.ElideRight + color: "red" + font.family: text_0000.font.family + font.pixelSize: text_0000.font.pixelSize + } + Text { + id: text_0004 + wrapMode: Text.Wrap + text: text_0003.text + anchors.top: text_0003.bottom + anchors.left: text_0000.left + width: text_0000.width + maximumLineCount: text_0000.maximumLineCount + elide: Text.ElideRight + color: "blue" + font.family: text_0000.font.family + font.pixelSize: text_0000.font.pixelSize + } + Text { + id: text_0005 + wrapMode: Text.WordWrap + text: text_0003.text + anchors.top: text_0004.bottom + anchors.left: text_0000.left + width: text_0000.width + maximumLineCount: text_0000.maximumLineCount + elide: Text.ElideRight + color: "green" + font.family: text_0000.font.family + font.pixelSize: text_0000.font.pixelSize + } + Text { + id: text_0006 + wrapMode: Text.WrapAnywhere + text: "The quick brown 1234567890123" + anchors.top: text_0005.bottom + anchors.left: text_0000.left + width: 150 + maximumLineCount: 2 + elide: Text.ElideRight + color: "red" + font.family: text_0000.font.family + font.pixelSize: text_0000.font.pixelSize + } + Text { + id: text_0007 + wrapMode: Text.Wrap + text: text_0006.text + anchors.top: text_0006.bottom + anchors.left: text_0000.left + width: text_0000.width + maximumLineCount: text_0000.maximumLineCount + elide: Text.ElideRight + color: "blue" + font.family: text_0000.font.family + font.pixelSize: text_0000.font.pixelSize + } + Text { + id: text_0008 + wrapMode: Text.WordWrap + text: text_0006.text + anchors.top: text_0007.bottom + anchors.left: text_0000.left + width: text_0000.width + maximumLineCount: text_0000.maximumLineCount + elide: Text.ElideRight + color: "green" + font.family: text_0000.font.family + font.pixelSize: text_0000.font.pixelSize + } +} diff --git a/tests/manual/tableview/tablemodel/form/RowForm.qml b/tests/manual/tableview/tablemodel/form/RowForm.qml index 428682008a..bb03e685c0 100644 --- a/tests/manual/tableview/tablemodel/form/RowForm.qml +++ b/tests/manual/tableview/tablemodel/form/RowForm.qml @@ -45,13 +45,13 @@ ScrollView { clip: true function inputAsRow() { - return [ - { checkable: checkableCheckBox.checked, checked: checkedCheckBox.checked }, - { amount: amountSpinBox.value }, - { fruitType: fruitTypeTextField.text }, - { fruitName: fruitNameTextField.text }, - { fruitPrice: parseFloat(fruitPriceTextField.text) }, - ] + return { + checked: checkedCheckBox.checked, + amount: amountSpinBox.value, + fruitType: fruitTypeTextField.text, + fruitName: fruitNameTextField.text, + fruitPrice: parseFloat(fruitPriceTextField.text) + } } default property alias content: gridLayout.children @@ -60,23 +60,11 @@ ScrollView { id: gridLayout columns: 2 - RowLayout { - Layout.columnSpan: 2 - - Label { - text: "checkable" - } - CheckBox { - id: checkableCheckBox - checked: true - } - - Label { - text: "checked" - } - CheckBox { - id: checkedCheckBox - } + Label { + text: "checked" + } + CheckBox { + id: checkedCheckBox } Label { diff --git a/tests/manual/tableview/tablemodel/form/main.qml b/tests/manual/tableview/tablemodel/form/main.qml index 21ecd8edbb..6c6874fb4b 100644 --- a/tests/manual/tableview/tablemodel/form/main.qml +++ b/tests/manual/tableview/tablemodel/form/main.qml @@ -64,31 +64,37 @@ ApplicationWindow { Layout.fillHeight: true model: TableModel { + TableModelColumn { display: "checked" } + TableModelColumn { display: "amount" } + TableModelColumn { display: "fruitType" } + TableModelColumn { display: "fruitName" } + TableModelColumn { display: "fruitPrice" } + // One row = one type of fruit that can be ordered rows: [ - [ - // Each object (line) is one cell/column, - // and each property in that object is a role. - { checked: false, checkable: true }, - { amount: 1 }, - { fruitType: "Apple" }, - { fruitName: "Granny Smith" }, - { fruitPrice: 1.50 } - ], - [ - { checked: true, checkable: true }, - { amount: 4 }, - { fruitType: "Orange" }, - { fruitName: "Navel" }, - { fruitPrice: 2.50 } - ], - [ - { checked: false, checkable: true }, - { amount: 1 }, - { fruitType: "Banana" }, - { fruitName: "Cavendish" }, - { fruitPrice: 3.50 } - ] + { + // Each object (line) is one column, + // and each property in that object represents a role. + checked: false, + amount: 1, + fruitType: "Apple", + fruitName: "Granny Smith", + fruitPrice: 1.50 + }, + { + checked: true, + amount: 4, + fruitType: "Orange", + fruitName: "Navel", + fruitPrice: 2.50 + }, + { + checked: false, + amount: 1, + fruitType: "Banana", + fruitName: "Cavendish", + fruitPrice: 3.50 + } ] } @@ -97,16 +103,16 @@ ApplicationWindow { column: 0 delegate: CheckBox { objectName: "tableViewCheckBoxDelegate" - checked: model.checked - onToggled: model.checked = checked + checked: model.display + onToggled: model.display = display } } DelegateChoice { column: 1 delegate: SpinBox { objectName: "tableViewSpinBoxDelegate" - value: model.amount - onValueModified: model.amount = value + value: model.display + onValueModified: model.display = value } } DelegateChoice { |