diff options
author | Laszlo Agocs <laszlo.agocs@qt.io> | 2019-04-23 09:33:25 +0200 |
---|---|---|
committer | Laszlo Agocs <laszlo.agocs@qt.io> | 2019-04-23 09:34:29 +0200 |
commit | 580fa7dc88aae23053e44ffa335a15f6af112a20 (patch) | |
tree | 5bc915d7c2e252739122d9441bd0d7fa7175d0c2 /tests/auto/qml | |
parent | 6767114285db9d0e16dc278d08f231e8561546b4 (diff) | |
parent | c00283bb3bb966bf60c307ec8283bd98c12318bf (diff) |
Merge remote-tracking branch 'origin/dev' into wip/scenegraphng
Change-Id: Ifec879473540b609403ac951967f6d9ecb0bb6f0
Diffstat (limited to 'tests/auto/qml')
73 files changed, 1139 insertions, 631 deletions
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" |